Можем ли мы использовать SpanNearQuery в фонетическом индексе?

Я внедрил программное обеспечение на основе люцена, чтобы индексировать более 10 миллионов имен людей, и эти имена могут быть написаны по-разному, например, "Luíz" и "Luis". Индекс был создан с использованием фонетических значений соответствующих токенов (был создан специальный анализатор).

В настоящее время я использую QueryParser для запроса заданного имени с хорошими результатами. Но в книге "Lucene in Action" упоминается, что SpanNearQuery может улучшить мои запросы, используя близость токенов. Я играл с SpanNearQuery против нефонетического индекса имени, и результаты были лучше по сравнению с QueryParser.

Поскольку мы должны выполнять запросы с использованием того же анализатора, который использовался для индексации, я не смог найти, как я могу использовать свой собственный фонетический анализатор и SpanNearQuery одновременно или перефразировать:

    how can I use SpanNearQuery on the phonetic index?

Заранее спасибо.

1 ответ

Моя первая мысль: разве не справится фраза с запросом slop? Это, безусловно, будет самым простым способом:

"term1 term2"~5

Это будет использовать ваш фонетический анализатор и выдаст запрос о близости с полученными токенами.


Так что, если вам действительно нужно использовать SpanQueries здесь (возможно, вы используете нечеткие запросы или подстановочные знаки или что-то подобное, или PhraseQuery угрожающе насмехается над вами, и вы не хотите больше ничего делать с ним), вам нужно сделать анализируй сам. Вы можете сделать это, получив TokenStream от Analyzer.tokenStreamи итерация по анализируемым токенам.

Если вы используете фонетический алгоритм, который выдает один код для каждого термина (например, soundex):

SpanNearQuery.Builder nearBuilder = new SpanNearQuery.Builder("text", true);
nearBuilder.setSlop(4);

TokenStream stream = analyzer.tokenStream("text", queryStringToParse);
stream.addAttribute(CharTermAttribute.class);
stream.reset();
while(stream.incrementToken()) {
    CharTermAttribute token = stream.getAttribute(CharTermAttribute.class);
    nearBuilder.addClause(new SpanTermQuery(new Term("text", token.toString())));
}
Query finalQuery = nearBuilder.build();
stream.close();

Если вы используете двойной метафон, где у вас может быть 1-2 термина в одной и той же позиции, это немного сложнее, так как вам нужно будет учитывать эти приращения позиции:

SpanNearQuery.Builder nearBuilder = new SpanNearQuery.Builder("text", true);
nearBuilder.setSlop(4);

TokenStream stream = analyzer.tokenStream("text", "through and through");
stream.addAttribute(CharTermAttribute.class);
stream.addAttribute(PositionIncrementAttribute.class);
stream.reset();
String queuedToken = null;
while(stream.incrementToken()) {
    CharTermAttribute token = stream.getAttribute(CharTermAttribute.class);
    PositionIncrementAttribute increment = stream.getAttribute(PositionIncrementAttribute.class);

    if (increment.getPositionIncrement() == 0) {
        nearBuilder.addClause(new SpanOrQuery(
                new SpanTermQuery(new Term("text", queuedToken)),
                new SpanTermQuery(new Term("text", token.toString()))
                ));
        queuedToken = null;
    }
    else if (increment.getPositionIncrement() >= 1 && queuedToken != null) {
        nearBuilder.addClause(new SpanTermQuery(new Term("text", queuedToken)));
        queuedToken = token.toString();
    }
    else {
        queuedToken = token.toString();
    }
}

if (queuedToken != null) {
    nearBuilder.addClause(new SpanTermQuery(new Term("text", queuedToken)));
}

Query finalQuery = nearBuilder.build();
stream.close();
Другие вопросы по тегам