Запрос Lucene: бла ~ * (сопоставить слова, начинающиеся с чего-то нечеткого), как? - PullRequest
10 голосов
/ 13 апреля 2010

В синтаксисе запроса 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 : индексировать данные, создавая поле, содержащее все префиксы моего (короткого) ввода.

Время поиска : используйте только оператор ~, поскольку префиксы явно присутствуют в индексе.

Ответы [ 4 ]

8 голосов
/ 08 мая 2010

в стволе разработки 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);
2 голосов
/ 13 апреля 2010

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

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

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

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

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

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

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

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

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

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

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

1 голос
/ 13 апреля 2010

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

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

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

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

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

Итак, подобный индекс здания :

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

И выполнить поиск по индексу следующим образом :

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

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

0 голосов
/ 13 апреля 2010

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

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