Что не так с TermRangeQuery? - PullRequest
       13

Что не так с TermRangeQuery?

0 голосов
/ 29 апреля 2020

TermRangeQuery работает не так, как я ожидаю.
Я новичок в Lucene и новичок в Java.
Так что, возможно, я не понимаю, какой должен быть мой код, или я сделал несколько ужасная ошибка.
Это код (вы можете попробовать его на https://repl.it/@Tekener / AstonishingAridWatch ):

import java.io.IOException;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermRangeQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.RAMDirectory;

@SuppressWarnings("deprecation")
class Main {
    private static IndexSearcher indexSearcher;
    private static IndexReader indexReader;
    private static String separatorLine = "===========================";

    public static void main(String[] args) throws IOException {
        Analyzer analyzer = new StandardAnalyzer();
        Directory directory = new RAMDirectory();
        IndexWriterConfig config = new IndexWriterConfig(analyzer);
        IndexWriter indexWriter = new IndexWriter(directory, config);

        System.out.println(separatorLine);
        System.out.println("Building the index:");
        indexWriter.addDocument(createDocumentWithFields("1st", "Humpty Dumpty sat on a wall,"));
        indexWriter.addDocument(createDocumentWithFields("2nd", "Humpty Dumpty had a great fall."));
        indexWriter.addDocument(createDocumentWithFields("3rd", "All the king's horses and all the king'smen"));
        indexWriter.addDocument(createDocumentWithFields("4th", "Couldn't put Humpty together again."));
        System.out.println(separatorLine);

        indexWriter.commit();
        indexWriter.close();        

        indexReader = DirectoryReader.open(directory);
        indexSearcher = new IndexSearcher(indexReader);

        showQueryResult(1, TermRangeQuery.newStringRange("content", "a", "h", true, true));
        showQueryResult(2, TermRangeQuery.newStringRange("content", "A", "H", true, true));
        showQueryResult(3, TermRangeQuery.newStringRange("content", "a", "f", true, true));
        showQueryResult(4, TermRangeQuery.newStringRange("content", "A", "F", true, true));
    }

    private static void showQueryResult(int queryNo, Query query) throws IOException {
        System.out.println(String.format("Query #%d: %s", queryNo, query.toString()));
        TopDocs topDocs = indexSearcher.search(query, 100);
        System.out.println("Result:");
        for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
            Document doc = indexReader.document(scoreDoc.doc);
            System.out.println(String.format("name: %s - content: %s", doc.getField("name").stringValue(), doc.getField("content").stringValue()));
        }
        System.out.println(separatorLine);
    }

    private static Document createDocumentWithFields(String name, String content) {
        System.out.println(String.format("name: %s - content: %s", name, content));
        Document doc = new Document();
        doc.add(new StringField("name",  name,    Store.YES));
        doc.add(new TextField("content", content, Store.YES));
        return doc;
    }
}

Это вывод консоли:

===========================
Building the index:
name: 1st - content: Humpty Dumpty sat on a wall,
name: 2nd - content: Humpty Dumpty had a great fall.
name: 3rd - content: All the king's horses and all the king'smen
name: 4th - content: Couldn't put Humpty together again.
===========================
Query #1: content:[a TO h]
Result:
name: 1st - content: Humpty Dumpty sat on a wall,
name: 2nd - content: Humpty Dumpty had a great fall.
name: 3rd - content: All the king's horses and all the king'smen
name: 4th - content: Couldn't put Humpty together again.
===========================
Query #2: content:[A TO H]
Result:
===========================
Query #3: content:[a TO f]
Result:
name: 1st - content: Humpty Dumpty sat on a wall,
name: 2nd - content: Humpty Dumpty had a great fall.
name: 3rd - content: All the king's horses and all the king'smen
name: 4th - content: Couldn't put Humpty together again.
===========================
Query #4: content:[A TO F]
Result:
===========================

Мои выводы:
Результаты для запросов № 1, № 2 и № 4 могут быть правильными, если индексированные тексты (для поля «содержимое») хранятся в виде строчных букв.
Но если это В этом случае результат запроса № 3 будет неверным.
В запросе № 3 должны быть найдены только 3-я и 4-я запись.
Где моя ошибка?

1 Ответ

0 голосов
/ 29 апреля 2020

Стандартный анализатор использует фильтр нижнего регистра - так что да, все ваши проиндексированные данные будут строчными:

Фильтрует StandardTokenizer с LowerCaseFilter и StopFilter, используя настраиваемый список стоп-слов.

Также имейте в виду, что это:

TermRangeQuery.newStringRange("content", "a", "f", true, true);

означает, что «a» и «f» включены в диапазон (значения true).

Таким образом, "a" in "сильно упал" - это совпадение. Вот почему все 4 результата находятся в запросе 3. Измените третий поиск на что-то вроде этого, чтобы увидеть результат:

TermRangeQuery.newStringRange("content", "a", "b", true, true);
TermRangeQuery.newStringRange("content", "a", "b", false, false);

Этот следующий пункт не имеет прямого отношения к вашему вопросу, но может оказаться полезным. Обычно при выполнении поиска желательно использовать тот же анализатор, что и при индексации данных (есть исключения). Так, например, для поисковых запросов характерно совпадение поисковых терминов без учета регистра. Используя стандартный анализатор для поисковых терминов, вы можете достичь этого.

Существуют различные способы сделать это - вот один из способов - могут быть более приятные:

QueryParser parser = new QueryParser("content", analyzer);

Query q1 = TermRangeQuery.newStringRange("content", "b", "h", true, true);
Query query1 = parser.parse(q1.toString());
showQueryResult(1, query1);

Результаты должны Имеет смысл в свете вышесказанного.

Если вы хотите изучить, что на самом деле индексируется, я рекомендую изменить, чтобы использовать это:

org.apache.lucene.store.MMapDirectory;

и что-то вроде этого:

Directory directory = new MMapDirectory(Paths.get("E:/lucene/indexes/range_queries"));

И, во всяком случае, RAMDirectory обычно не рекомендуется - за исключением, может быть, для демонстраций.

Как только данные находятся на диске, вы можете указать на них Люка - очень полезный инструмент (с GUI) для изучения данных индекса. Он доступен в виде файла JAR (lucene-luke-8.xxjar), который можно найти в основном бинарном выпуске Lucene.

РЕДАКТИРОВАТЬ :

Если вы используйте RAMDirectory, вы также можете использовать это:

if (!DirectoryReader.indexExists(directory)) {
    // index builder logic here
}

Это позволяет избежать повторного заполнения индекса дублирующимися данными.

Относительно стоп-слов: по умолчанию стандартный анализатор имеет пустой список стоп-слов. Вы можете предоставить конструктору список слов в виде org.apache.lucene.analysis.CharArraySet:

import org.apache.lucene.analysis.CharArraySet;

...

CharArraySet myStopWords = new CharArraySet(2, true); 
myStopWords .add("foo");
myStopWords .add("bar");
Analyzer analyzer = new StandardAnalyzer(myStopWords);

Или вы можете использовать один из существующих списков стоп-слов. Вот тот, для Engli sh стоп-слов:

import static org.apache.lucene.analysis.en.EnglishAnalyzer.ENGLISH_STOP_WORDS_SET;

...

Analyzer analyzer = new StandardAnalyzer(ENGLISH_STOP_WORDS_SET);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...