Многоязычный анализатор / индексный подход Lucene

У меня есть рабочий индекс Lucene, поддерживающий службу предложений. Когда пользователь вводит текст в поле поиска, он запрашивает индекс по SUGGESTION_FIELD. Каждая запись в SUGGESTION_FIELD может относиться к одному из множества поддерживаемых языков, и каждый из них хранится с использованием анализатора для соответствующего языка. Чтобы узнать, какой анализатор использовался, для каждой записи есть второе поле, в котором хранится LOCALE. Поэтому во время запроса я могу сказать что-то вроде приведенного ниже кода, чтобы выполнить запрос для конкретного языка с использованием соответствующего анализатора.

QueryParser parser = new QueryParser(Version.LUCENE_33, SUGGESTION_FIELD, getLangaugeAnalyzer(locale));
return searcher.search(parser.parse("SUGGESTION_FIELD:" + queryString + " AND LOCALE:"
                + locale), 100);

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

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

Sol. №1. Казалось бы, самое простое решение: выполните запрос несколько раз. Один раз для каждой локали, тем самым каждый раз применяя соответствующий анализатор языка. Наконец, разумным образом добавьте результаты каждого запроса.

Sol. №2. В качестве альтернативы я мог бы повторно индексировать, используя столбец для каждого языкового стандарта, например:

SUGGESTION_FIELD_en, SUGGESTION_FIELD_fr, SUGGESTION_FIELD_es etc.. 

с использованием другого анализатора для каждого поля (с использованием PerFieldAnalyzerWrapper), а затем запрос с использованием более сложной строки запроса, такой как:

"SUGGESTION_FIELD_en:" + queryString + " AND SUGGESTION_FIELD_fr:" + queryString + " AND SUGGESTION_FIELD_es:" + queryString

Пожалуйста, помогите, если думаете, что вы :)


person Rob McFeely    schedule 03.04.2012    source источник
comment
Судя по тому, что вы указали, это не похоже на много работы - почему бы просто ИЛИ не объединить все нужные вам языковые стандарты?   -  person Marko Topolnik    schedule 03.04.2012
comment
Спасибо. Потому что я не уверен, что он будет работать быстрее при увеличении индекса. Ваше право, хотя это не так много работы. К сожалению, хотя я работаю с тестовой базой данных с небольшим количеством данных, я не могу быть уверен, что будет лучше, когда индекс в конечном итоге станет очень большим в производственной среде. Так что мне интересно мнение людей :)   -  person Rob McFeely    schedule 04.04.2012
comment
Ваш запрос будет примерно таким: sugField: queryString AND (locale: loc1 OR locale: loc2 OR ...). Это BooleanQuery, состоящий из TermQueries, с одним из обязательных условий. Этот термин также редко встречается в индексе, и Lucene знает это с самого начала (он проверяет общее количество документов для каждого заданного Term), поэтому он будет знать, что сначала нужно ограничить результат queryString, а затем дополнительно пересечь его с терминами локали. Это будет ОЧЕНЬ эффективно независимо от размера вашего индекса.   -  person Marko Topolnik    schedule 04.04.2012
comment
@Marko Topolnik Спасибо за ответ. К сожалению, этот подход (для одного запроса) не будет работать, поскольку мне нужно выбрать анализатор языка при запросе sugField. Таким образом, в то время как логическое значение: подсказка И (loc OR loc OR loc ...) эффективно запрашивает правильные части индекса, оно применяет один и тот же общий анализатор для каждой части. Этого я не хочу. Вот почему в моем решении № 1 выше использовалось несколько вызовов (по одному на локаль), чтобы я мог каждый раз применять соответствующий анализатор.   -  person Rob McFeely    schedule 04.04.2012


Ответы (1)


Ваш запрос будет примерно таким: (sugField: queryString1 AND locale: loc1) OR (sugField: queryString2 AND locale: loc2) ИЛИ .... Это логический запрос верхнего уровня с подчиненными логическими запросами, добавленными с помощью plays = SHOULD, где каждый подчиненный запрос имеет свои условия с встречается = ОБЯЗАТЕЛЬНО. QueryString1, queryString2 и т. Д. Являются выходными данными из разных языковых анализаторов, имеющих один и тот же вход, строку, введенную пользователем.

Каждый подчиненный запрос включает обязательные термины (из вашей строки запроса), которые редко встречаются в индексе, и Lucene знает это с самого начала (он знает общее количество документов для каждого Term в индексе), поэтому он сначала ограничит результат queryString и затем дополнительно пересечь это с терминами локали. Это будет ОЧЕНЬ эффективно независимо от размера вашего индекса.

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

person Marko Topolnik    schedule 04.04.2012
comment
Спасибо @Marko Topolnik. Думаю, это хорошее решение. Единичный вызов Lucene с использованием не проанализированных запросов и предварительное выполнение всего анализа отдельно. Мне это нравится. Я никогда раньше не занимался анализом вручную (кроме писателя или парсера запросов). Я предполагаю, что это самый популярный ответ на этот stackoverflow.com/questions/6334692/ - это правильная процедура? :) - person Rob McFeely; 04.04.2012
comment
Фактически, этот устаревший API в Lucene 3.5 использует ответ с меньшим количеством голосов. Просто я бы извлек атрибут в локальную переменную вместо того, чтобы получать его снова на каждой итерации, например здесь. - person Marko Topolnik; 04.04.2012