Предотвращение "слишком много статей" по запросу 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. По-видимому, это ускоряет процесс поиска.
Вы можете легко автоматизировать процесс, который автоматически разбивает термины и заполняет документы со значениями по схеме имени при индексировании.
Некоторые проблемы могут возникнуть, если у вас есть несколько токенов для каждого поля. Более подробную информацию вы можете найти в статье