【发布时间】:2017-02-21 22:51:17
【问题描述】:
多年来,我们一直在使用 Lucene.NET 根据用户输入的搜索词来搜索从文件中提取的文本。但是,我们最近遇到了一个客户报告的问题,即搜索具有多个正斜杠的术语时没有返回匹配项。
例如,SB/ABC/1234-123 的索引值和用户输入 SB/* 以匹配具有该前缀的所有文档。但是,不会根据该查询返回任何结果。奇怪的是搜索ABC/* 确实返回值为SB/ABC/1234-123 的文档,完全忽略了SB/ 组件。
最初报告的问题是正斜杠和通配符的组合(SB/* 不会返回与 SB/1234-123 的匹配项),但通过使用 QueryParser 和 KeywordAnalyzer 以及除了以前的 QueryParser 只有一个 StandardAnalyzer。
这是当前使用的代码(简化为可以重现问题的关键元素)。
var reader = IndexReader.Open(FSDirectory.Open(new DirectoryInfo(indexPath)), true);
var searcher = new IndexSearcher(reader);
var mainQuery = new BooleanQuery();
// The analyzer and parser for searching the index fields with full stop-words and tokenizers
var fieldAnalyzer = new StandardAnalyzer(LuceneVersion);
var fieldParser = new MultiFieldQueryParser(LuceneVersion, reader.GetFieldNames(IndexReader.FieldOption.ALL).ToArray(), fieldAnalyzer);
// The analyzer and parser for searching the index fields using no stop words or tokenizers
var fieldKeywordAnalyzer = new KeywordAnalyzer();
var fieldKeywordParser = new MultiFieldQueryParser(LuceneVersion, reader.GetFieldNames(IndexReader.FieldOption.ALL).ToArray(), fieldKeywordAnalyzer);
// Build and append the Standard and Keyword query clauses together for the whole field value query to pick up all relevant results
var fieldQuery = fieldParser.Parse(textCriteria);
var fieldKeywordQuery = fieldKeywordParser.Parse(textCriteria);
var fieldBooleanQuery = new BooleanQuery
{
{fieldQuery, Occur.SHOULD},
{fieldKeywordQuery, Occur.SHOULD}
};
mainQuery.Add(fieldBooleanQuery, Occur.MUST);
var hits = searcher.Search(mainQuery, reader.NumDocs());
在调用searcher.Search 时,在mainQuery 中实际解析的查询是+((Title:sb/abc/*) (Title:sb/abc/*))。在这种情况下,BooleanQuery 的两个子句恰好是相同的。通常用于处理 Lucene 索引的 Luke 工具似乎认为在使用 KeywordAnalyzer 时这是无效语法(暂时忽略标记化方面):
Cannot parse '+((Title:sb/abc/*) (Title:sb/abc/*))': '*' or '?' not allowed as first character in WildcardQuery.
我的假设是拥有两个正斜杠使其将其视为正则表达式。问题是我们如何让它正确匹配结果而不是将其视为正则表达式。转义搜索条件中的斜杠不会改变上面看到的解析查询或返回的结果。
我们当前的要求是它必须同时支持相同字段上的标记化/停用词搜索(用于文本短语等)以及完全匹配(我们存储大量不应标记化的发票号码等),并且都处理通配符。 SB/* 查询是在完全匹配值场景中进行通配符搜索的示例。
希望这是有道理的。如果需要,我可以添加更多说明。
编辑:我们的数据被组织成许多列,可以存储任何文本值。示例:一些客户将一个唯一/ID 值(发票号等)放入 doctype A 的字段 1。同一客户可以使用字段 1 作为 doctype B 的文本块(全名等)。文档的分类,从高层次上描述特定文档应该代表什么,例如发票、采购订单等。示例数据:
DocId DocType Field1 Field2 Field3, etc
1234 A SB/2567 John Doe
5678 B Jane Doe 90210
3456 A ABC/5678 Bobby Lee
【问题讨论】:
-
StandardAnalyzer 将您的示例发票编号 SB/ABC/1234-123 视为两个标记:[sb] [abc/1234-123]。这就是 'ABC/*' 匹配的原因。
-
这就是为什么我们也添加了关键字分析器,以便它搜索标记化(标准)值和非标记化(关键字)。在这种情况下,它似乎忽略了 KeywordAnalyzer。
-
@DanielBrixen 抱歉,没有在我的回复中标记你,它不会让我编辑它。
标签: .net lucene lucene.net