Запрос Lucene: bla ~ * (совпадающие слова, начинающиеся с чего-то нечеткого), как?

В синтаксисе запроса 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: используйте только оператор ~, поскольку префиксы явно присутствуют в индексе.

Ответ 1

Я не считаю, что Lucene поддерживает что-то подобное, и я не верю, что это имеет тривиальное решение.

"Нечеткие" запросы не работают с фиксированным числом символов. bla~ может, например, соответствовать blah, и поэтому он должен учитывать весь термин.

Что вы можете сделать, так это реализовать алгоритм расширения запроса, который взял запрос bla~* и преобразовал его в серию OR запросов

bla* OR blb* OR blc OR .... etc.

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

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

Вы точно не определяете, зачем вам это нужно, возможно, это приведет к появлению других решений.

Один сценарий, о котором я могу думать, имеет дело с разными формами слов. Например. нахождение car и cars.

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

В этом случае вы можете (при условии, что у вас есть доступ к хорошему словарю), найдите поисковый запрос и программно разверните поиск для поиска всех форм слова.

например. поиск cars переводится в car OR cars. Это было успешно применено для моего языка, по крайней мере, в одной поисковой системе, но, очевидно, нетривиально реализовать.

Ответ 2

в области разработки 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);

Ответ 3

Это для службы поиска адресов, где я хочу предложить адреса, основанные на частично типизированных и, возможно, туманных уличных именах /citynames/etc (любая комбинация). (думаю, ajax, пользователи вводят частичные адреса улицы в текстовое поле)

В этом случае предлагаемое расширение запроса, возможно, не так возможно, так как частичная строка (адрес улицы) может стать длиннее "короткой":)

Нормализация

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

"miklabraut 42, 101 reykjavík", при нормализации станет "miklabrat 42 101 rekavik".

Итак, построим такой индекс:

1) создайте индекс с записями, содержащими "нормализованные" версии имен улиц, названий городов и т.д., с одним адресом на один документ (1 или несколько полей).

И найдите индекс, подобный этому:

2) Нормализовать входные строки (например, mikl reyk), используемые для формирования запросов (т.е. mik rek). 3) используйте групповой символ op для выполнения поиска (т.е. mik* AND rek*), оставив нечеткую часть.

Это будет летать, если алгоритм нормализации достаточно хорош:)

Ответ 4

Вы хотите объединить подстановочный знак и нечеткий запрос? Вы можете использовать логический запрос с условием ИЛИ для объединения, например:

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...)