Lucene 同时搜索已存储和未存储的字段
Lucene searching over stored and unstored Fields concurrently
我正在使用 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:这是我很长一段时间以来的第一个 post,如果不是的话。请备注任何格式或内容问题。
编辑:
用于索引内容字段和搜索内容字段的分析器:
Analyzer myTxtAnalyzer = CustomAnalyzer.builder()
.withTokenizer("standard")
.addTokenFilter("lowercase")
.addTokenFilter("stop")
.addTokenFilter("porterstem")
.build();
我正在使用 KeywordAnalyzer 搜索文件名字段,重申一下,该字段已存储,因此未进行分析。
我的程序应该索引文件并搜索该索引,检索
最相关文件的列表。如果可能包含空格的 searchString 与文件名完全匹配,
我希望这会严重影响我的搜索结果。
我是一名计算机科学专业的学生,这是我使用 Lucene 的第一个项目。
如果没有可用的功能,那一切都很好。我要求的不是我的任务的要求。我只是在思考,我觉得这可能已经存在一个简单的解决方案。但我似乎找不到它,如果它存在的话。
编辑 2:
我对使用 Stored.YES/.NO 时会发生什么有一个误解。
我的问题与它无关。
String 没有被标记化,因为它在 StringField 中。
我以为这是因为它被存储了。
但是,我的问题仍然存在。
有没有办法同时搜索标记化和未标记化的字段?
正如@andrewjames 提到的,您不需要在示例中使用多个分析器,因为只有 TextField
得到分析,StringField
不需要。如果您确实需要针对不同的领域使用不同的分析器,Lucene 可以适应这种情况。为此,您可以使用 PerFieldAnalyzerWrapper
,它基本上让您指定一个默认分析器,然后指定任意数量的字段特定分析器(作为字典传递给 PerFieldAnalyzerWrapper
)。然后在分析文档时,如果指定了一个,它将使用字段特定的分析器,如果没有,它将使用您为 PerFieldAnalyzerWrapper
.
指定的默认分析器
无论是使用单个分析器还是通过 PerFieldAnalyzerWrapper
使用多个分析器,您只需要一个 QueryParser
并且您将向该解析器传递一个分析器或作为分析器的 PerFieldAnalyzerWrapper
包装了几个分析器。
您的一些字段已存储而另一些未存储这一事实对搜索它们没有影响。唯一对搜索重要的是字段被索引,StringField
s 和 TextField
s 总是被索引。
您提到了以下内容:
And I'm using the KeywordAnalyzer to search over the filename Field, which, to reiterate, is stored, so not analyzed.
字段是否存储与是否解析无关。对于文件名字段,您的代码使用 StringField
和 Field.Store.YES
。因为它是一个 StringField
它将被索引但不会被分析,并且因为您指定要存储它将被存储的字段。因此,由于未分析该字段,因此不会使用 KeywordAnalyzer
或任何其他分析器 :-)
Is there a way to search over tokenized and untokenized Fields concurrently?
这里真正的问题不是同时搜索标记化和未标记化的字段,而是同时搜索多个字段。一个被标记化而一个未被标记化这一事实对 lucene 没有影响。要一次搜索多个字段,您可以使用 BooleanQuery
并使用此查询对象,您可以向其添加多个查询,每个字段一个,并指定 AND
即 Must
或 OR
即Should
子查询之间的关系。
我希望这可以帮助您解决问题。
我正在使用 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:这是我很长一段时间以来的第一个 post,如果不是的话。请备注任何格式或内容问题。
编辑: 用于索引内容字段和搜索内容字段的分析器:
Analyzer myTxtAnalyzer = CustomAnalyzer.builder()
.withTokenizer("standard")
.addTokenFilter("lowercase")
.addTokenFilter("stop")
.addTokenFilter("porterstem")
.build();
我正在使用 KeywordAnalyzer 搜索文件名字段,重申一下,该字段已存储,因此未进行分析。
我的程序应该索引文件并搜索该索引,检索 最相关文件的列表。如果可能包含空格的 searchString 与文件名完全匹配, 我希望这会严重影响我的搜索结果。
我是一名计算机科学专业的学生,这是我使用 Lucene 的第一个项目。 如果没有可用的功能,那一切都很好。我要求的不是我的任务的要求。我只是在思考,我觉得这可能已经存在一个简单的解决方案。但我似乎找不到它,如果它存在的话。
编辑 2: 我对使用 Stored.YES/.NO 时会发生什么有一个误解。 我的问题与它无关。 String 没有被标记化,因为它在 StringField 中。 我以为这是因为它被存储了。 但是,我的问题仍然存在。 有没有办法同时搜索标记化和未标记化的字段?
正如@andrewjames 提到的,您不需要在示例中使用多个分析器,因为只有 TextField
得到分析,StringField
不需要。如果您确实需要针对不同的领域使用不同的分析器,Lucene 可以适应这种情况。为此,您可以使用 PerFieldAnalyzerWrapper
,它基本上让您指定一个默认分析器,然后指定任意数量的字段特定分析器(作为字典传递给 PerFieldAnalyzerWrapper
)。然后在分析文档时,如果指定了一个,它将使用字段特定的分析器,如果没有,它将使用您为 PerFieldAnalyzerWrapper
.
无论是使用单个分析器还是通过 PerFieldAnalyzerWrapper
使用多个分析器,您只需要一个 QueryParser
并且您将向该解析器传递一个分析器或作为分析器的 PerFieldAnalyzerWrapper
包装了几个分析器。
您的一些字段已存储而另一些未存储这一事实对搜索它们没有影响。唯一对搜索重要的是字段被索引,StringField
s 和 TextField
s 总是被索引。
您提到了以下内容:
And I'm using the KeywordAnalyzer to search over the filename Field, which, to reiterate, is stored, so not analyzed.
字段是否存储与是否解析无关。对于文件名字段,您的代码使用 StringField
和 Field.Store.YES
。因为它是一个 StringField
它将被索引但不会被分析,并且因为您指定要存储它将被存储的字段。因此,由于未分析该字段,因此不会使用 KeywordAnalyzer
或任何其他分析器 :-)
Is there a way to search over tokenized and untokenized Fields concurrently?
这里真正的问题不是同时搜索标记化和未标记化的字段,而是同时搜索多个字段。一个被标记化而一个未被标记化这一事实对 lucene 没有影响。要一次搜索多个字段,您可以使用 BooleanQuery
并使用此查询对象,您可以向其添加多个查询,每个字段一个,并指定 AND
即 Must
或 OR
即Should
子查询之间的关系。
我希望这可以帮助您解决问题。