Нечеткий поиск по фразе Lucene (FuzzyQuery + SpanQuery)

Я ищу способ кодирования нечеткого запроса lucene, который ищет все документы, которые имеют отношение к конкретной фразе. Если я выполню поиск "Оценки сотрудника Мозаики", в результате будет возвращен документ, содержащий "Оценки большинства сотрудников".

Я пытался использовать:

FuzzyQeury = new FuzzyQuery(new Term("contents","mosa employee appreicata"))

К сожалению, эмпирически это не работает. FuzzyQuery использует расстояние редактора, теоретически, "оценка сотрудника мозаики" должна совпадать с "оценкой большинства сотрудников", если дано соответствующее расстояние. Это кажется немного странным.

Есть какие-нибудь подсказки? Спасибо.

2 ответа

Решение

Ответ от femtoRgon великолепен! Спасибо.

Есть еще один способ решить эту проблему.

//declare a mutilphrasequery
MultiPhraseQuery childrenInOrder = new MultiPhraseQuery();

//user fuzzytermenum to enumerate your query string
FuzzyTermEnum fuzzyEnumeratedTerms1 = new FuzzyTermEnum(reader, new Term(searchField,"mosa"));
FuzzyTermEnum fuzzyEnumeratedTerms2 = new FuzzyTermEnum(reader, new Term(searchField,"employee"));
FuzzyTermEnum fuzzyEnumeratedTerms3 = new FuzzyTermEnum(reader, new Term(searchField,"appreicata"));

//this basically pull out the possbile terms from the index             
Term termHolder1 = fuzzyEnumeratedTerms1.term();
Term termHolder2 = fuzzyEnumeratedTerms2.term();
Term termHolder3 = fuzzyEnumeratedTerms3.term();

//put the possible terms into multiphrasequery
if (termHolder1==null){
    childrenInOrder.add(new Term(searchField,"mosa"));
}else{
    childrenInOrder.add(fuzzyEnumeratedTerms1.term());
}

if (termHolder2==null){
    childrenInOrder.add(new Term(searchField,"employee"));
}else{
    childrenInOrder.add(fuzzyEnumeratedTerms2.term());
}

if (termHolder3==null){
    childrenInOrder.add(new Term(searchField,"appreicata"));
}else{
    childrenInOrder.add(fuzzyEnumeratedTerms3.term());
}


//close it - it is important to close it
fuzzyEnumeratedTerms1.close();
fuzzyEnumeratedTerms2.close();
fuzzyEnumeratedTerms3.close();

Здесь есть две вероятные проблемы. Во-первых: я предполагаю, что поле "содержание" анализируется таким образом, что "большинство сотрудников ценят" - это не термин, а три термина. Определение в качестве одного термина не подходит в этом случае.

Однако, даже если в указанном контенте содержится один термин, вторая вероятная проблема заключается в том, что между терминами слишком большое расстояние, чтобы найти совпадение. Расстояние Дамерау-Левенштейн между mosa employee appreicata а также most employees appreciate 4 (приблизительное расстояние, между прочим, между моим средним первым выстрелом в правописании "Дамерау-Левенштейн" и правильным правописанием). Fuzzy Query, начиная с 4.0, обрабатывает расстояния редактирования не более 2 из-за ограничений производительности и предположения, что большие расстояния обычно не особенно актуальны.

Если вам нужно выполнить запрос фразы с нечеткими терминами, вы должны посмотреть либо MultiPhraseQuery или объединить набор SpanQueries (особенно SpanMultiTermQueryWrapper а также SpanNearQuery) для удовлетворения ваших потребностей.

SpanQuery[] clauses = new SpanQuery[3];
clauses[0] = new SpanMultiTermQueryWrapper(new FuzzyQuery(new Term("contents", "mosa")));
clauses[1] = new SpanMultiTermQueryWrapper(new FuzzyQuery(new Term("contents", "employee")));
clauses[2] = new SpanMultiTermQueryWrapper(new FuzzyQuery(new Term("contents", "appreicata")));
SpanNearQuery query = new SpanNearQuery(clauses, 0, true)

И поскольку ни один из отдельных терминов не имеет расстояния редактирования больше 2, это должно быть более эффективным.

ComplexPhraseQueryParser обрабатывает нечеткий поиск по словосочетанию - то есть указывает слова, которые следует искать нечетко, а те, которые не следует. Работает следующим образом

Query query = new ComplexPhraseQueryParser("content", analyzer)
                    .parse("some test~ query~ blah blah");

Кажется, работает хорошо. Однако не уверен насчет производительности, но, похоже, хорошо работает с небольшими наборами данных.

У меня было немного (очень маленькое) смешивание со следующим:

String[] searchTerms = searchString.split(" ");
FuzzyLikeThisQuery fltw = new FuzzyLikeThisQuery(searchTerms.length, new StandardAnalyzer());
Arrays.stream(searchTerms)
    .forEach(term -> fltq.addTerms(term, FIELD, SIMILARITY_IN_EDITS, PREFIX_LENGTH); 

Этот запрос сопоставляет слишком отдаленные строки с индексом. Строки, которые не совпадают, - это строки, в которых каждое из терминов удалено более чем на 2 редактирования от терминов, используемых в проиндексированном контенте.

Пожалуйста, используйте на свой страх и риск.

Другие вопросы по тегам