В синтаксисе запроса Lucene я хотел бы объединиться * и ~ в допустимом запросе, подобном: bla ~*//недопустимый запрос
Значение: распознайте слова, которые начинаются с "bla" или чего-то подобного "bla".
Обновление: То, что я делаю теперь, работы для маленького входа, является использованием следующее (отрывок схемы SOLR):
<fieldtype name="text_ngrams" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="0"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.EdgeNGramFilterFactory" minGramSize="2" maxGramSize="15" side="front"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="0"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
В случае, если Вы не используете SOLR, это делает следующее.
Indextime: Индексные данные путем создания поля, содержащего все префиксы моего (короткого) входа.
Searchtime: только используйте ~ оператор, поскольку префиксы явно присутствуют в индексе.
Я не верю, что Lucene поддерживает что-либо подобное, и не Я считаю, что у этого есть тривиальное решение.
«Нечеткий» поиск не работает с фиксированным количеством символов. bla ~
может, например, соответствовать blah
, поэтому он должен учитывать весь термин.
Что вы могли бы сделать, так это реализовать алгоритм расширения запроса, который взял бы запрос bla ~ *
и преобразовал его в серию запросов ИЛИ
bla* OR blb* OR blc OR .... etc.
Но это действительно возможно только в том случае, если строка очень короткая. или если вы можете сузить расширение на основе некоторых правил.
В качестве альтернативы, если длина префикса фиксирована, вы можете добавить поле с подстроками и выполнить нечеткий поиск по нему. Это даст вам то, что вы хотите, но сработает только в том случае, если ваш вариант использования достаточно узкий.
Вы не указываете, зачем вам это нужно, возможно, это вызовет другие решения.
Один из сценариев, который я могу придумать, связан с разными формами слов. Например. обнаружение автомобилей
и автомобилей
.
Это легко сделать по-английски, так как существуют словосочетания. В других языках может быть довольно сложно реализовать словосочетания, если вообще возможно.
В этом сценарии, однако, вы можете (при условии, что у вас есть доступ к хорошему словарю) найти поисковый запрос и программно расширить поиск для поиска всех форм слова.
Например. поиск cars
переводится в car OR cars
.Это было успешно применено для моего языка по крайней мере в одной поисковой системе, но, очевидно, реализовать его нетривиально.
Вы имеете в виду, что хотите объединить подстановочный знак и нечеткий запрос? Вы можете использовать логический запрос с условием ИЛИ для объединения, например:
BooleanQuery bq = new BooleanQuery();
Query q1 = //here goes your wildcard query
bq.Add(q1, BooleanClause...)
Query q2 = //here goes your fuzzy query
bq.Add(q2, BooleanClause...)
Это для службы поиска адресов, где я хочу предлагать адреса на основе частично набранных и, возможно, неправильно введенных названий улиц/городов/и т.д. (любая комбинация). (представьте ajax, пользователи вводят частичные адреса улиц в текстовое поле)
Для этого случая предложенное расширение запроса, возможно, не так осуществимо, поскольку частичная строка (адрес улицы) может стать длиннее, чем "короткая" :)
Нормализация
Одна из возможностей, о которой я могу думать, это использовать "нормализацию" строки вместо нечеткого поиска, и просто объединить это с запросами с подстановочными знаками. Адрес улицы
"miklabraut 42, 101 reykjavík"
при нормализации станет "miklabrat 42 101 rekavik"
.
Итак, построение индекса следующим образом:
1) построить индекс с записями, содержащими "нормализованные" версии названий улиц, городов и т.д., с одним адресом улицы на документ (1 или несколько полей).
И выполните поиск по индексу следующим образом:
2) нормализуйте входные строки (например, mikl reyk
), используемые для формирования запросов (например, mik rek
).
3) использовать подстановочный знак для выполнения поиска (например, mik* AND rek*
), оставив нечеткую часть.
Это будет работать, если алгоритм нормализации достаточно хорош :)
в основной ветке разработки lucene (еще не выпуск), есть код для поддержки таких случаев использования, через AutomatonQuery. Предупреждение: API-интерфейсы могут / будут изменены до его выпуска, но это дает вам представление.
Вот пример для вашего случая:
// a term representative of the query, containing the field.
// the term text is not so important and only used for toString() and such
Term term = new Term("yourfield", "bla~*");
// builds a DFA that accepts all strings within an edit distance of 2 from "bla"
Automaton fuzzy = new LevenshteinAutomata("bla").toAutomaton(2);
// concatenate this DFA with another DFA equivalent to the "*" operator
Automaton fuzzyPrefix = BasicOperations.concatenate(fuzzy, BasicAutomata.makeAnyString());
// build a query, search with it to get results.
AutomatonQuery query = new AutomatonQuery(term, fuzzyPrefix);