Почему этот запрос Lucene.Net терпит неудачу? - PullRequest
1 голос
/ 25 мая 2011

Я пытаюсь преобразовать свои функции поиска, чтобы учесть нечеткие поиски, включающие несколько слов. Мой существующий поисковый код выглядит так:

        // 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);

Ответы [ 2 ]

3 голосов
/ 26 мая 2011

Ваш код работает для меня, если я переписываю searchString в нижний регистр.Я предполагаю, что вы используете StandardAnalyzer при индексации, и она будет генерировать строчные термины.

Вам необходимо 1) пропустить ваши токены через один и тот же анализатор (чтобы включить идентичную обработку)2) применять ту же логику, что и анализатор, или 3) использовать анализатор, который соответствует обработке, которую вы выполняете (WhitespaceAnalyzer).

1 голос
/ 25 мая 2011

Вы хотите эту строку:

var queryTerm = new Term(term);

чтобы выглядеть так:

var queryTerm = new Term(field, term);

Прямо сейчас вы ищете поле term (которое, вероятно, не существует) для пустой строки (которая никогда не будет найдена).

...