Запрет "слишком много статей" в запросе lucene
В моих тестах я неожиданно столкнулся с исключением "Слишком много статей" при попытке получить попадания из логического запроса, состоящего из запроса запроса и символа подстановки.
Я искал по сети и на найденных ресурсах они предлагают увеличить BooleanQuery.SetMaxClauseCount().
Это звучит подозрительно для меня.. К чему мне это? Как я могу рассчитывать, что этого нового магического числа будет достаточно для моего запроса? Как далеко я могу увеличить это число до того, как все начнется ад?
В общем, я чувствую, что это не решение проблемы. Там должна быть более глубокая проблема..
Запрос был +{+companyName:mercedes +paintCode:a*}, а индекс содержит ~2,5 млн документов.
2 ответа
paintCode:a* часть запроса является префиксным запросом для любого paintCode, начинающегося с "a". Это то, к чему вы стремитесь?
Lucene расширяет префиксные запросы в логический запрос, содержащий все возможные термины, соответствующие префиксу. В вашем случае, видимо, существует более 1024 возможных paintCode
ы, которые начинаются с "а".
Если вам кажется, что префиксные запросы бесполезны, вы не далеки от истины.
Я бы посоветовал вам изменить схему индексации, чтобы избежать использования префиксного запроса. Я не уверен, что вы пытаетесь выполнить в своем примере, но если вы хотите искать коды рисования по первой букве, создайте поле 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, вы можете написать свой собственный вариант Prefix Query и свой собственный QueryParser, но я не думаю, что это намного лучше.
Похоже, вы используете это в поле, которое является типом ключевого слова (то есть в вашем источнике данных не будет нескольких токенов).
Здесь есть предложение, которое кажется мне довольно элегантным: http://grokbase.com/t/lucene.apache.org/java-user/2007/11/substring-indexing-to-avoid-toomanyclauses-exception/12f7s7kzp2emktbn66tdmfpcxfya
Основная идея состоит в том, чтобы разбить ваш термин на несколько полей с увеличивающейся длиной, пока вы не будете уверены, что не достигнете предела предложения.
Пример:
Представьте себе paintCode как это:
"a4c2d3"
При индексации этого значения в документе создаются следующие значения полей:
[paintCode]: "a4c2d3"
[paintCode1n]: "a"
[paintCode2n]: "a4"
[paintCode3n]: "a4c"
К тому времени, когда вы сделаете запрос, количество символов в вашем термине определит, в каком поле искать. Это означает, что вы будете выполнять запрос префикса только для терминов, содержащих более 3 символов, что значительно уменьшает количество внутренних результатов, предотвращая печально известное исключение TooManyBooleanClausesException. По-видимому, это также ускоряет процесс поиска.
Вы можете легко автоматизировать процесс, который автоматически разбивает термины и заполняет документы значениями в соответствии со схемой имен во время индексации.
Некоторые проблемы могут возникнуть, если у вас есть несколько токенов для каждого поля. Вы можете найти более подробную информацию в статье