Можем ли мы использовать 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();