【问题标题】:Lucene searching over stored and unstored Fields concurrentlyLucene 同时搜索存储和未存储的字段
【发布时间】:2020-12-20 14:04:16
【问题描述】:

我正在使用 Lucene 7.4 并且已经索引了一个 txt 文件样本。 我有一些已存储的字段,例如路径和文件名, 和一个内容字段,在将文档传递给 IndexWriter 之前未存储。 因此,我的内容字段包含文件的已处理(例如标记化、词干化)内容数据,我的文件名字段包含未处理的文件名、整个字符串。

try (InputStream stream = Files.newInputStream(file)) {

            // create empty document
            Document doc = new Document();

            // add the last modification time field
            Field lastModField = new StoredField(LuceneConstants.LAST_MODIFICATION_TIME, Files.getAttribute(file, "lastModifiedTime", LinkOption.NOFOLLOW_LINKS).toString());
            doc.add(lastModField);
            
            // add the path Field
            Field pathField = new StringField(LuceneConstants.FILE_PATH, file.toString(), Field.Store.YES);
            doc.add(pathField);

            // add the name Field
            doc.add(new StringField(LuceneConstants.FILE_NAME, file.getFileName().toString(), Field.Store.YES));

            // add the content
            doc.add(new TextField(LuceneConstants.CONTENTS, new BufferedReader(new InputStreamReader(stream))));

            System.out.println("adding " + file);
            writer.addDocument(doc);

现在,据我了解,我必须使用 2 个 QueryParsers,因为我需要使用 2 个不同的分析器来搜索两个字段,每个字段一个。 我不知道如何将它们结合起来。 我想要的是一个 TopDoc,其中结果按相关性分数排序,这是对文件名字段的搜索和对内容字段的搜索的 2 个相关性分数的某种组合。 Lucene 7.4 是否为您提供了轻松解决此问题的方法?

PS:这是我很长时间以来的第一篇文章,如果不是的话。请备注任何格式或内容问题。

编辑: 用于索引内容字段和搜索内容字段的分析器:

Analyzer myTxtAnalyzer = CustomAnalyzer.builder()
                    .withTokenizer("standard")
                    .addTokenFilter("lowercase")
                    .addTokenFilter("stop")
                    .addTokenFilter("porterstem")
                    .build();

我正在使用 KeywordAnalyzer 搜索文件名字段,重申一下,该字段已存储,因此不进行分析。

我的程序应该索引文件并搜索该索引,检索 最相关的文件清单。如果可能包含空格的 searchString 与文件名完全匹配, 我希望这会对我的搜索结果产生重大影响。

我是一名计算机科学专业的学生,​​这是我使用 Lucene 的第一个项目。 如果没有可用的功能,一切都很好。我所要求的不是我的任务的要求。我只是在思考,我觉得这可能已经存在一个简单的解决方案。但我似乎找不到它,如果它存在的话。

编辑 2: 我对使用 Stored.YES/.NO 时会发生什么有一个误解。 我的问题与它无关。 字符串未标记化,因为它位于 StringField 中。 我认为这是因为它被存储了。 但是,我的问题仍然存在。 有没有办法同时搜索标记化和未标记化的字段?

【问题讨论】:

  • 您能解释一下为什么需要两种不同的分析仪吗?这通常只有在您对不同字段有不同的标记/过滤需求时才会出现这种情况。但是使用这些不同的字段类型(StringFieldTextField)不会强制您这样做,因为 StringField 是“按原样”索引的 - 跳过了标记化。也许如果你edit你的问题显示你当前需要使用的分析器和查询解析器,问题会更清楚。

标签: java lucene


【解决方案1】:

正如@andrewjames 所提到的,您不需要在示例中使用多个分析器,因为只有TextField 会被分析,StringFields 不会。如果您确实需要为不同的字段使用不同的分析器,Lucene 可以适应这种情况。为此,您使用PerFieldAnalyzerWrapper,它基本上让您指定一个默认分析器,然后指定任意数量的特定于字段的分析器(作为字典传递给PerFieldAnalyzerWrapper)。然后在分析文档时,如果指定了字段特定分析器,它将使用字段特定分析器,如果未指定,它将使用您为 PerFieldAnalyzerWrapper 指定的默认分析器。

无论是使用单个分析器还是通过PerFieldAnalyzerWrapper 使用多个分析器,您只需要一个QueryParser,您将通过一个分析器或PerFieldAnalyzerWrapper(包装多个分析器的分析器)传递该解析器。

您的某些字段已存储而有些未存储这一事实对搜索它们没有影响。对搜索而言唯一重要的是该字段已编入索引,StringFields 和 TextFields 始终都已编入索引。

您提到以下内容:

我正在使用 KeywordAnalyzer 搜索文件名字段,重申一下,该字段已存储,因此未分析。

字段是否存储与是否分析无关。对于文件名字段,您的代码使用StringFieldField.Store.YES。因为它是StringField,它将被索引但不被分析,并且因为您指定存储字段,它将被存储。因此,由于未分析该字段,因此不会使用 KeywordAnalyzer 或任何其他分析器:-)

有没有办法同时搜索标记化和未标记化的字段?

这里真正的问题不是同时搜索标记化和非标记化字段,它实际上只是同时搜索多个字段。一个被标记化而一个没有被标记化的事实对 lucene 没有任何影响。要一次搜索多个字段,您可以使用 BooleanQuery 并使用此查询对象,您可以向其中添加多个查询,每个字段一个,并指定 ANDMustORShould子查询之间的关系。

我希望这可以帮助您解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-07-26
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    相关资源
    最近更新 更多