Предотвращение «слишком большого количества предложений» в запросе Lucene

StackOverflow https://stackoverflow.com/questions/614758

  •  03-07-2019
  •  | 
  •  

Вопрос

В своих тестах я внезапно столкнулся с исключением «Слишком много предложений» при попытке получить результаты логического запроса, состоящего из терминального запроса и запроса с подстановочными знаками.

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

В общем, я считаю, что это не выход.Должна быть проблема посерьезнее..

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

Это было полезно?

Решение

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

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

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

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

ДОБАВЛЕН

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

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, но я не думаю, что это намного лучше.

Другие советы

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

Здесь есть предложение, которое кажется мне довольно элегантным: 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.Видимо это тоже ускоряет процесс поиска.

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top