Lucene.Net 包含两个 MUST 子句的查询返回不正确的结果
Lucene.Net Query with two MUST Clauses Returning Incorrect Results
我创建了一个包含两个 MUST 子句(和零个 SHOULD 子句)的查询,该查询返回的结果仅满足其中一个子句。据我所知,这是不正确的行为。
搜索前的此类查询示例是
{+(Text:wba) +(Attribute:10)}
返回的错误结果在 'Text' 字段中有 'wba' 作为术语,但在 'Attribute' 字段中没有“10”作为术语。
当我在 Luke 中查看我的索引时,转到“搜索”选项卡,运行 此搜索
+Text:wba +Attribute:10
如我所料,我没有得到任何结果。
下面是 运行 搜索代码的稍微简化版本:
public static ScoreDoc[] Search( string searchPhrase, int maxResults, IEnumerable<string> attributes ) {
var topQuery = new BooleanQuery();
var textQuery = new BooleanQuery();
using( var ngAnalyzer = new NGramAnalyzer( Version.LUCENE_30, 3, 9 ) ) {
using( var stAnalyzer = new StandardAnalyzer( Version.LUCENE_30, new HashSet<string>() ) ) {
var ngParser = new QueryParser( Version.LUCENE_30, IndexManager.TextFieldName, ngAnalyzer );
var stParser = new QueryParser( Version.LUCENE_30, IndexManager.TextFieldName, stAnalyzer );
var terms = AutoCompleter.QueryToTerms( searchPhrase );
foreach( var word in terms ) {
if( string.IsNullOrWhiteSpace( word ) ) {
continue;
}
if( word.Length < 3 ) {
textQuery.Add( stParser.Parse( word ), Occur.MUST );
} else {
var parsed = ngParser.Parse( word );
var extractedTerms = new HashSet<Term>();
parsed.ExtractTerms( extractedTerms );
foreach( var term in extractedTerms ) {
textQuery.Add( new TermQuery( term ), Occur.SHOULD );
}
}
}
}
}
topQuery.Add( textQuery, Occur.MUST );
if( attributes != null && attributes.Any() ) {
var attrQuery = new BooleanQuery();
foreach( var attr in attributes ) {
attrQuery.Add( new TermQuery( new Term( IndexManager.AttributeFieldName, attr ) ), Occur.SHOULD );
}
topQuery.Add( attrQuery, Occur.MUST );
}
// Actually conduct the search
var searcher = AutoCompleter.IndexManager.GetOrCreateSearcher( AutoCompleter.TableId );
var resultDocs = searcher.Search( textQuery, maxResults ).ScoreDocs;
return resultDocs;
}
这是生成索引的代码的摘录:
// Add the new document
var doc = new Document();
var field = new Field( IndexManager.TextFieldName, term.Text, Field.Store.YES, Field.Index.ANALYZED );
doc.Add( field );
if( !String.IsNullOrWhiteSpace( term.Id ) ) {
field = new Field( IndexManager.IdFieldName, term.Id, Field.Store.YES, Field.Index.NO );
doc.Add( field );
}
foreach( var attr in term.Attributes ) {
if( !String.IsNullOrWhiteSpace( attr ) ) {
field = new Field( IndexManager.AttributeFieldName, attr, Field.Store.YES, Field.Index.NOT_ANALYZED );
doc.Add( field );
}
}
writer.AddDocument( doc );
所以,明确地说,我只期望与 textQuery
中的文本子句匹配的结果以及至少与 attrQuery
中包含的属性子句之一相匹配的结果。为什么这不像我预期的那样工作?
这一行是错误的:
var resultDocs = searcher.Search( textQuery, maxResults ).ScoreDocs;
应该是:
var resultDocs = searcher.Search( topQuery, maxResults ).ScoreDocs;
糟糕。
我创建了一个包含两个 MUST 子句(和零个 SHOULD 子句)的查询,该查询返回的结果仅满足其中一个子句。据我所知,这是不正确的行为。
搜索前的此类查询示例是
{+(Text:wba) +(Attribute:10)}
返回的错误结果在 'Text' 字段中有 'wba' 作为术语,但在 'Attribute' 字段中没有“10”作为术语。
当我在 Luke 中查看我的索引时,转到“搜索”选项卡,运行 此搜索
+Text:wba +Attribute:10
如我所料,我没有得到任何结果。
下面是 运行 搜索代码的稍微简化版本:
public static ScoreDoc[] Search( string searchPhrase, int maxResults, IEnumerable<string> attributes ) {
var topQuery = new BooleanQuery();
var textQuery = new BooleanQuery();
using( var ngAnalyzer = new NGramAnalyzer( Version.LUCENE_30, 3, 9 ) ) {
using( var stAnalyzer = new StandardAnalyzer( Version.LUCENE_30, new HashSet<string>() ) ) {
var ngParser = new QueryParser( Version.LUCENE_30, IndexManager.TextFieldName, ngAnalyzer );
var stParser = new QueryParser( Version.LUCENE_30, IndexManager.TextFieldName, stAnalyzer );
var terms = AutoCompleter.QueryToTerms( searchPhrase );
foreach( var word in terms ) {
if( string.IsNullOrWhiteSpace( word ) ) {
continue;
}
if( word.Length < 3 ) {
textQuery.Add( stParser.Parse( word ), Occur.MUST );
} else {
var parsed = ngParser.Parse( word );
var extractedTerms = new HashSet<Term>();
parsed.ExtractTerms( extractedTerms );
foreach( var term in extractedTerms ) {
textQuery.Add( new TermQuery( term ), Occur.SHOULD );
}
}
}
}
}
topQuery.Add( textQuery, Occur.MUST );
if( attributes != null && attributes.Any() ) {
var attrQuery = new BooleanQuery();
foreach( var attr in attributes ) {
attrQuery.Add( new TermQuery( new Term( IndexManager.AttributeFieldName, attr ) ), Occur.SHOULD );
}
topQuery.Add( attrQuery, Occur.MUST );
}
// Actually conduct the search
var searcher = AutoCompleter.IndexManager.GetOrCreateSearcher( AutoCompleter.TableId );
var resultDocs = searcher.Search( textQuery, maxResults ).ScoreDocs;
return resultDocs;
}
这是生成索引的代码的摘录:
// Add the new document
var doc = new Document();
var field = new Field( IndexManager.TextFieldName, term.Text, Field.Store.YES, Field.Index.ANALYZED );
doc.Add( field );
if( !String.IsNullOrWhiteSpace( term.Id ) ) {
field = new Field( IndexManager.IdFieldName, term.Id, Field.Store.YES, Field.Index.NO );
doc.Add( field );
}
foreach( var attr in term.Attributes ) {
if( !String.IsNullOrWhiteSpace( attr ) ) {
field = new Field( IndexManager.AttributeFieldName, attr, Field.Store.YES, Field.Index.NOT_ANALYZED );
doc.Add( field );
}
}
writer.AddDocument( doc );
所以,明确地说,我只期望与 textQuery
中的文本子句匹配的结果以及至少与 attrQuery
中包含的属性子句之一相匹配的结果。为什么这不像我预期的那样工作?
这一行是错误的:
var resultDocs = searcher.Search( textQuery, maxResults ).ScoreDocs;
应该是:
var resultDocs = searcher.Search( topQuery, maxResults ).ScoreDocs;
糟糕。