Запрос, который вы создали, в основном требует соответствия всех трех слов.
Вы обертываете каждое слово в BooleanQuery
с помощью пункта SHOULD
. Это эквивалентно непосредственному использованию внутреннего запроса (вы просто добавляете косвенность, которая не изменяет поведение запроса). Логический запрос имеет только одно предложение, которое должно соответствовать логическому запросу.
Затем вы обертываете каждый из них в другой логический запрос, на этот раз с предложением MUST
для каждого. Это означает, что каждое предложение должно соответствовать запросу для соответствия.
Для BooleanQuery
, чтобы соответствовать все MUST
положения должны быть удовлетворены, и если их нет, то как минимум MinimumNumberShouldMatch
SHOULD
положений должны быть удовлетворены. Оставьте это свойство по умолчанию, так как задокументированное поведение:
По умолчанию для соответствия не требуются необязательные оговорки (если нет необходимых условий).
Эффективно, ваш запрос (при условии, что нет MultiFieldQueryParser
для простоты):
+(john) +(data) +(check)
Или, в виде дерева:
BooleanQuery
MUST: BooleanQuery
SHOULD: TermQuery: john
MUST: BooleanQuery
SHOULD: TermQuery: data
MUST: BooleanQuery
SHOULD: TermQuery: check
Что может быть упрощена:
BooleanQuery
MUST: TermQuery: john
MUST: TermQuery: data
MUST: TermQuery: check
Но ваш запрос Муравей:
BooleanQuery
SHOULD: TermQuery: john
SHOULD: TermQuery: data
SHOULD: TermQuery: check
Таким образом, удалить mainQuery.MinimumNumberShouldMatch = 1;
линию, а затем заменить foreach
тело следующим, и он должен получить работу:
mainQuery.Add(queryParser.Parse(word), Occur.SHOULD);
Итак, вот полный пример , который работает для меня:
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
var directory = new RAMDirectory();
using (var writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED))
{
var doc = new Document();
doc.Add(new Field("id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("name", "John Smith", Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("additionalData", "faster data", Field.Store.NO, Field.Index.ANALYZED));
writer.AddDocument(doc);
doc = new Document();
doc.Add(new Field("id", "2", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("name", "Alan Smith", Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("additionalData", "faster drive", Field.Store.NO, Field.Index.ANALYZED));
writer.AddDocument(doc);
doc = new Document();
doc.Add(new Field("id", "3", Field.Store.YES, Field.Index.NOT_ANALYZED));
doc.Add(new Field("name", "Mike Std", Field.Store.NO, Field.Index.ANALYZED));
doc.Add(new Field("additionalData", "faster check", Field.Store.NO, Field.Index.ANALYZED));
writer.AddDocument(doc);
}
var words = new[] {"John", "data", "check"};
var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, new[] {"name", "additionalData"}, analyzer);
var mainQuery = new BooleanQuery();
foreach (var word in words)
mainQuery.Add(parser.Parse(word), Occur.SHOULD); // Should probably use parser.Parse(QueryParser.Escape(word)) instead
using (var searcher = new IndexSearcher(directory))
{
var results = searcher.Search(mainQuery, null, int.MaxValue, Sort.RELEVANCE);
var idFieldSelector = new MapFieldSelector("id");
foreach (var scoreDoc in results.ScoreDocs)
{
var doc = searcher.Doc(scoreDoc.Doc, idFieldSelector);
Console.WriteLine("Found: {0}", doc.Get("id"));
}
}
, но когда я изменил код, как вы предложили, есть также возвращены те документы, которые не соответствуют критериям поиска – Tony
Ммм он не должен иметь, не могли бы вы сказать, что такое 'mainQuery .ToString() 'печатает? –
{((имя: Joh дополнительная информация: Joh) (имя: dat extraData: dat) (имя: chec extraData: chec)) ~ 1} – Tony