Предотвращение "слишком много статей" по запросу lucene

В моих тестах я неожиданно столкнулся с избытком Too Many Clauses при попытке получить хиты из логического запроса, который состоял из запроса termquery и wildcard.

Я искал в сети и найденных ресурсах, которые они предлагают увеличить BooleanQuery.SetMaxClauseCount().
Это звучит мне подозрительно. К чему мне это? Как я могу полагаться, что этого нового магического числа будет достаточно для моего запроса? Как далеко я могу увеличить это число до того, как все ад сломается?

В общем, я считаю, что это не решение. Должна быть более глубокая проблема.

Запрос был + {+ companyName: mercedes + paintCode: a *}, а индекс имеет документы ~ 2.5M.

Ответ 1

paintCode: * часть запроса - это префиксный запрос для любого paintCode, начинающегося с "a". Это то, к чему вы стремитесь?

Lucene расширяет префиксные запросы в логический запрос, содержащий все возможные термины, соответствующие префиксу. В вашем случае, по-видимому, существует более 1024 возможных paintCode, начинающихся с "a".

Если это звучит для вас, как префиксные запросы бесполезны, вы не далеко от истины.

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

ADDED

Если вы в отчаянии и готовы принять частичные результаты, вы можете создать свою собственную версию Lucene из источника. Вам нужно внести изменения в файлы PrefixQuery.java и MultiTermQuery.java, как в org/apache/lucene/search. В методе rewrite обоих классов измените строку

query.add(tq, BooleanClause.Occur.SHOULD);          // add to query

к

try {
    query.add(tq, BooleanClause.Occur.SHOULD);          // add to query
} catch (TooManyClauses e) {
    break;
}

Я сделал это для своего собственного проекта, и он работает.

Если вам действительно не нравится идея сменить Lucene, вы можете написать свой собственный вариант PrefixQuery и свой собственный QueryParser, но я не думаю, что это намного лучше.

Ответ 2

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

Здесь есть предложение, которое кажется мне довольно элегантным: http://grokbase.com/t/lucene.apache.org/java-user/2007/11/substring-indexing-to-avoid-toomanyclauses-exception/12f7s7kzp2emktbn66tdmfpcxfya

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

Пример:

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

"a4c2d3"

При индексировании этого значения в документе создаются следующие значения полей:

[paintCode]: "a4c2d3"

[paintCode1n]: "a"

[paintCode2n]: "a4"

[paintCode3n]: "a4c"

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

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

Некоторые проблемы могут возникнуть, если у вас есть несколько токенов для каждого поля. Более подробную информацию вы можете найти в статье