Lucene.Net: соответствие расстоянию между словами - PullRequest
0 голосов
/ 07 июля 2011

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

            Lucene.Net.Store.Directory directory = FSDirectory.Open(new System.IO.DirectoryInfo("TestLuceneIndex"));
            StandardAnalyzer standardAnalyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
            IndexWriter indexWriter = new IndexWriter(directory, standardAnalyzer, IndexWriter.MaxFieldLength.UNLIMITED);
            Document doc = new Document();
            doc.Add(new Field("UID", uid, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO));
            doc.Add(new Field("GENDER", gender, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO));
            doc.Add(new Field("COUNTRY", countrycode, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO));
            doc.Add(new Field("CITY", citycode, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO));
            doc.Add(new Field("USERDATA", userdata, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            doc.Add(new Field("USERINFO", userinfo, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS));
            indexWriter.UpdateDocument(new Term("UID", uid), doc);
            indexWriter.Optimize();
            indexWriter.Commit();
            indexWriter.Close();

Значения, хранящиеся в индексе, следующие:
UID - идентификатор пользователя (строка GUID) GENDER - идентификатор пола (строка «0» (неопознано), «1» (мужчина) или «2» (женщина)) СТРАНА - код страны (строка типа "США", "FR" и т. Д.) CITY - код города (строка «A121», «C432» и т. Д.) USERDATA - длинная цепочка пользовательских деталей (что-то вроде «Джон Доу j.doe@gmail.com дизайнерское высшее образование 5 лет опыта») USERINFO - длинная строка текста о пользователе (что-то вроде «Меня зовут Джон Доу. Я родился ...»)

Затем я выполняю поиск по индексу. Я выполняю поиск в двух полях (USERDATA и USERINFO), и всякий раз, когда это необходимо, я фильтрую результаты по GENDER, COUNTRY и CITY. В результате я получаю UID (мне нужно это значение, чтобы идентифицировать идентификатор записи пользователя в БД).

Это код, который я использую для поиска:

        Lucene.Net.Store.Directory directory = Lucene.Net.Store.FSDirectory.Open(new System.IO.DirectoryInfo("TestLuceneIndex");
        standardAnalyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
        Lucene.Net.Index.IndexReader indexReader = Lucene.Net.Index.IndexReader.Open(directory, true);
        indexSearcher = new Lucene.Net.Search.IndexSearcher(indexReader);
        Lucene.Net.Search.BooleanQuery booleanQuery = new Lucene.Net.Search.BooleanQuery();
        Lucene.Net.QueryParsers.MultiFieldQueryParser queryTextParser = new Lucene.Net.QueryParsers.MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_29, new string[] { "USERDATA", "USERINFO" }, standardAnalyzer);
        Lucene.Net.Search.Query queryText = queryTextParser.Parse(SearchText);
        booleanQuery.Add(queryText, Lucene.Net.Search.BooleanClause.Occur.MUST);
        if (searchGender != "0")
        {
            Lucene.Net.Index.Term termGender = new Lucene.Net.Index.Term("GENDER", searchGender);
            Lucene.Net.Search.Query queryGender = new Lucene.Net.Search.TermQuery(termGender);
            booleanQuery.Add(queryGender, Lucene.Net.Search.BooleanClause.Occur.MUST);
        }
        if (searchCity != "0")
        {
            Lucene.Net.Index.Term termCity = new Lucene.Net.Index.Term("CITY", searchCity);
            Lucene.Net.Search.Query queryCity = new Lucene.Net.Search.TermQuery(termCity);
            booleanQuery.Add(queryCity, Lucene.Net.Search.BooleanClause.Occur.MUST);
        }
        if (searchCountry != "0")
        {
            Lucene.Net.Index.Term termCountry = new Lucene.Net.Index.Term("COUNTRY", searchCountry);
            Lucene.Net.Search.Query queryCountry = new Lucene.Net.Search.TermQuery(termCountry);
            booleanQuery.Add(queryCountry, Lucene.Net.Search.BooleanClause.Occur.MUST);
        }
        Lucene.Net.Search.TopScoreDocCollector collector = Lucene.Net.Search.TopScoreDocCollector.create(indexReader.MaxDoc(), true);
        indexSearcher.Search(booleanQuery, collector);
        Lucene.Net.Search.ScoreDoc[] scoreDocs=collector.TopDocs().scoreDocs;
        Lucene.Net.Highlight.Formatter formatter = new Lucene.Net.Highlight.SimpleHTMLFormatter("<b>", "</b>");
        Lucene.Net.Highlight.QueryScorer queryScorer = new Lucene.Net.Highlight.QueryScorer(booleanQuery);
        highlighter = new Lucene.Net.Highlight.Highlighter(formatter, queryScorer);
        Lucene.Net.Highlight.Fragmenter fragmenter = new Lucene.Net.Highlight.SimpleFragmenter(150);
        highlighter.SetTextFragmenter(fragmenter);

Все работает достаточно хорошо, кроме качества релевантности при использовании нескольких слов: Когда я ищу, например, (microsoft .net programmer) результаты, содержащие точную подстроку, не оцениваются выше, чем результаты, содержащие эти слова в разных местах текста. Я понимаю, что это связано с простым фактом, что подсчет баллов основан на процентном соотношении искомой строки в тексте, а не на точности совпадения строк. Но как заставить алгоритм скоринга повысить точность активов? То есть как сделать так, чтобы расстояние между найденными словами считалось более важным при расчете релевантности?

1 Ответ

2 голосов
/ 14 июля 2011
  1. Наиболее эффективным (и наиболее трудоемким способом) было бы написание собственного объекта запроса, который улучшил бы назначение более релевантных документов со словами в непосредственной близости. SpanQuery было бы неплохо для начала.

  2. Самый простой способ - использовать поиск по близости с обычным логическим запросом: ("search text"~10 || (search && text)).Это увеличит совпадение фразы приближения.

4.3. Поиск по близости - Lucene поддерживает поиск слов на определенном расстоянии.Для поиска по близости используйте тильду, символ «~» в конце фразы.Например, для поиска «apache» и «jakarta» в пределах 10 слов друг от друга в документе используйте поиск: «jakarta apache» ~ 10

Поскольку вы создаете свой собственный запрос, выможет даже увеличить "search text"~10 больше, чем "search text"~20, что выше (search && text).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...