我们多年来一直使用Lucene.NET来搜索基于搜索词的用户输入从文件中提取的文本。但是,我们最近遇到了客户报告的问题,其中搜索带有多个正斜杠的术语不返回匹配项。
示例是SB/ABC/1234-123
的索引值,用户输入SB/*
以匹配具有该前缀的所有文档。但是,不会根据该查询返回任何结果。奇怪的是,搜索ABC/*
会返回值为SB/ABC/1234-123
的文档,完全忽略SB/
组件。
最初报告的问题是正斜杠和通配符的组合(SB/*
不会返回SB/1234-123
的匹配项)但是使用QueryParser
和{ {1}}除了之前的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());
来电时mainQuery
内的实际已解析查询为searcher.Search
。在这种情况下,+((Title:sb/abc/*) (Title:sb/abc/*))
的两个条款恰好相同。通常用于处理Lucene索引的Luke工具似乎认为这在使用BooleanQuery
时是无效的语法(暂时忽略标记化方面):
KeywordAnalyzer
我的假设是,使用两个正斜杠使其将其视为正则表达式。问题是我们如何让它正确匹配结果而不是将其视为正则表达式。在搜索条件中转义斜杠并未更改上面看到的已解析查询或返回的结果。
我们目前的要求是它必须同时支持标记化/停止词搜索(用于文本短语等)以及完全匹配(我们存储大量不应该被标记化的发票号等)和都处理通配符。 Cannot parse '+((Title:sb/abc/*) (Title:sb/abc/*))': '*' or '?' not allowed as first character in WildcardQuery.
查询是完全匹配值方案的通配符搜索示例。
希望这是有道理的。如果需要,我可以添加额外的说明。
编辑:我们的数据被组织成许多列,可以存储任何文本值。示例:某些客户将唯一/ ID值(发票编号等)的值放入字段1中,用于doctype A.同一客户可以将字段1用作doctype B的文本块(全名等).Doctypes是高级别描述特定文档应表示的文档的分类,例如发票,采购订单等。示例数据:
SB/*