以下注释基于 Lucene 8.x,而不是 Lucene 6.6 - 因此可能存在一些语法差异 - 但我同意您的观点,即任何此类差异应该与您的问题巧合。
这里有一些注释,我将重点关注您问题的以下方面:
但是,这样我无法使用标准分析器正确解析如下查询:+type:"RockMusic" +title:"a sample title"
我认为这有两个部分:
首先,使用"a sample title" 的查询示例 - 正如你所说 - 不能很好地与标准分析器的工作方式配合 - 出于你陈述的原因。
但是,其次,可以将您想要使用的两种类型的查询结合起来,我相信这可以满足您的需求:type 字段的完全匹配(例如RockMusic)和title 字段(a sample title)的更传统的标记化和不区分大小写的结果。
我会这样做:
这是一些简单的测试数据:
public static void buildIndex() throws IOException {
final Directory dir = FSDirectory.open(Paths.get(INDEX_PATH));
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
iwc.setOpenMode(OpenMode.CREATE);
Document doc;
try (IndexWriter writer = new IndexWriter(dir, iwc)) {
doc = new Document();
doc.add(new StringField("type", "RockMusic", Field.Store.YES));
doc.add(new TextField("title", "a sample title", Field.Store.YES));
writer.addDocument(doc);
doc = new Document();
doc.add(new StringField("type", "RockMusic", Field.Store.YES));
doc.add(new TextField("title", "another different title", Field.Store.YES));
writer.addDocument(doc);
doc = new Document();
doc.add(new StringField("type", "Rock Music", Field.Store.YES));
doc.add(new TextField("title", "a sample title", Field.Store.YES));
writer.addDocument(doc);
}
}
这里是查询代码:
public static void doSearch() throws QueryNodeException, ParseException, IOException {
IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(INDEX_PATH)));
IndexSearcher searcher = new IndexSearcher(reader);
TermQuery typeQuery = new TermQuery(new Term("type", "RockMusic"));
Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser("title", analyzer);
Query titleQuery = parser.parse("A Sample Title");
Query query = new BooleanQuery.Builder()
.add(typeQuery, BooleanClause.Occur.MUST)
.add(titleQuery, BooleanClause.Occur.MUST)
.build();
System.out.println("Query: " + query.toString());
System.out.println();
TopDocs results = searcher.search(query, 100);
ScoreDoc[] hits = results.scoreDocs;
for (ScoreDoc hit : hits) {
System.out.println("doc = " + hit.doc + "; score = " + hit.score);
Document doc = searcher.doc(hit.doc);
System.out.println("Type = " + doc.get("type")
+ "; Title = " + doc.get("title"));
System.out.println();
}
}
上述查询的输出如下:
Query: +type:RockMusic +(title:a title:sample title:title)
doc = 0; score = 0.7016101
Type = RockMusic; Title = a sample title
doc = 1; score = 0.2743341
Type = RockMusic; Title = another different title
如您所见,此查询与从您的问题中提取的查询略有不同。
但是找到的文档列表显示 (a) 根本没有找到 Rock Music 文档(很好 - 因为 Rock Music 与 RockMusic 的“类型”搜索词不匹配); (b) 在搜索 A Sample Title 时,标题 a sample title 的匹配分数远高于 another different title 文档。
补充说明:
此查询通过将 StringField 精确搜索与更传统的 TextField 标记化搜索相结合来工作 - 后一种搜索由 StandardAnalyzer 处理(匹配数据最初的索引方式)。
我假设分数排名对您有用 - 但对于标题搜索,我认为这是合理的。
这种方法也适用于您的BRAIN 与brain 示例,用于StringField 数据。
(我还假设,对于用户界面,用户可以从下拉列表中选择“RockMusic”类型值,然后在输入字段中输入“A Sample Title”搜索 - 但这已经开始了 -主题,我想)。
您显然可以根据需要增强分析器以包含停用词等。
当然,我的示例涉及硬编码数据 - 但推广这种处理动态提供的搜索词的方法并不需要太多。
希望这是有道理的 - 并且我正确理解了这个问题。