Я пытаюсь преобразовать свои функции поиска, чтобы учесть нечеткие поиски, включающие несколько слов. Мой существующий поисковый код выглядит так:
// Split the search into seperate queries per word, and combine them into one major query
var finalQuery = new BooleanQuery();
string[] terms = searchString.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
foreach (string term in terms)
{
// Setup the fields to search
string[] searchfields = new string[]
{
// Various strings denoting the document fields available
};
var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, searchfields, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29));
finalQuery.Add(parser.Parse(term), BooleanClause.Occur.MUST);
}
// Perform the search
var directory = FSDirectory.Open(new DirectoryInfo(LuceneIndexBaseDirectory));
var searcher = new IndexSearcher(directory, true);
var hits = searcher.Search(finalQuery, MAX_RESULTS);
Это работает правильно, и если у меня есть сущность с полем имени «Меня зовут Андрей», и я выполняю поиск по «имени Андрея», Lucene правильно находит правильный документ. Теперь я хочу включить нечеткий поиск, чтобы «Имя Anderw» было найдено правильно. Я изменил свой метод, чтобы использовать следующий код:
const int MAX_RESULTS = 10000;
const float MIN_SIMILARITY = 0.5f;
const int PREFIX_LENGTH = 3;
if (string.IsNullOrWhiteSpace(searchString))
throw new ArgumentException("Provided search string is empty");
// Split the search into seperate queries per word, and combine them into one major query
var finalQuery = new BooleanQuery();
string[] terms = searchString.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
foreach (string term in terms)
{
// Setup the fields to search
string[] searchfields = new string[]
{
// Strings denoting document field names here
};
// Create a subquery where the term must match at least one of the fields
var subquery = new BooleanQuery();
foreach (string field in searchfields)
{
var queryTerm = new Term(field, term);
var fuzzyQuery = new FuzzyQuery(queryTerm, MIN_SIMILARITY, PREFIX_LENGTH);
subquery.Add(fuzzyQuery, BooleanClause.Occur.SHOULD);
}
// Add the subquery to the final query, but make at least one subquery match must be found
finalQuery.Add(subquery, BooleanClause.Occur.MUST);
}
// Perform the search
var directory = FSDirectory.Open(new DirectoryInfo(LuceneIndexBaseDirectory));
var searcher = new IndexSearcher(directory, true);
var hits = searcher.Search(finalQuery, MAX_RESULTS);
К сожалению, с этим кодом, если я отправлю поисковый запрос "Andrew Name" (как и прежде), я получу ноль результатов назад.
Основная идея заключается в том, что все термины должны быть найдены как минимум в одном поле документа, но каждый термин может находиться в разных полях. У кого-нибудь есть идеи, почему мой переписанный запрос терпит неудачу?
Окончательное редактирование: Хорошо, оказывается, я слишком усложнил это ЛОТОМ, и не было необходимости менять мой первый подход. Вернувшись к первому фрагменту кода, я включил нечеткий поиск, изменив
finalQuery.Add(parser.Parse(term), BooleanClause.Occur.MUST);
до
finalQuery.Add(parser.Parse(term.Replace("~", "") + "~"), BooleanClause.Occur.MUST);