Elasticsearch: порядок фильтров для лучшей производительности

руководство Elasticsearch говорит

" каждый фильтр вычисляется и кэшируется независимо, независимо от того, где он используется. Если два разных запроса используют один и тот же фильтр, один и тот же набор битов фильтра будет использоваться повторно. Аналогично, если один запрос использует один и тот же фильтр в нескольких местах, вычисляется только один набор битов, а затем используется повторно." (https://www.elastic.co/guide/en/elasticsearch/guide/current/filter-caching.html)

на другой странице он также говорит:

" порядок фильтров в предложении bool важен для производительности. Более конкретные фильтры следует размещать перед менее конкретными фильтрами, чтобы исключить как можно больше документов как можно раньше. Если предложение A может соответствовать 10 миллионам документов, а предложение B может соответствовать только 100 документам, то предложение B должно быть помещено перед предложением A." (https://www.elastic.co/guide/en/elasticsearch/guide/current/_filter_order.html)

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

Я бы предположил, что предложение B выполняется или извлекается из кэша, предложение A выполняется или извлекается из кэша, а затем битовые наборы фильтров "объединяются". Почему вопрос?

4 ответов


это руководство немного вводит в заблуждение. Это сложнее, и очень трудно попытаться написать один набор правил, который подходит для всех ситуаций. По мере изменения данных меняются и правила. По мере изменения типов запросов и фильтров меняются правила. Конкретный фильтр может выполняться медленнее, чем широкий, правила меняются. На основе каждого сегмента размер результата фильтра может быть противоположным, чем на другом сегменте, это не всегда предсказуемо. Итак, сначала вы должны понять больше внутренности, тогда вам нужно отпустить попытку контролировать его, когда вы переходите в современный Elasticsearch 2.x.

Примечание: ваша вторая цитата (порядок фильтрации) и связанная с ней ссылка относятся к странице, которая считается "устаревшей" для Elasticsearch 2.х, он будет обновлен позже. Поэтому совет может быть или не быть применим к современности.

оглядываясь назад во времени на Elasticsearch 1.x и причина заказ предложения:

давайте сначала поговорим о том, как фильтры представлены в памяти. Они представляют собой либо итерационный список соответствующих документов, либо модель произвольного доступа "это здесь". В зависимости от типа фильтра, зависит от того, что является более эффективным. Теперь, если все кэшируется, вы просто пересекаете их, и стоимость будет зависеть от размера и типа.

если фильтры не кэшируются, но являются кэшируемыми, то фильтр будет выполняться независимо и предыдущие фильтры будут влиять только на общую стоимость пересечения.

если фильтр не является кэшируемым, то он может руководствоваться предыдущими результатами. Представьте себе Query плюс Filter. Если вы выполняете запрос, и после применения фильтра, вы делаете много лишней работы, если фильтр ограничивает очень небольшой набор записей. Вы потратили время в запросе на сбор, подсчет очков и общее построение большого набора результатов. Но если вы конвертируете в FilteredQuery и то, и другое в то же время, тогда Query игнорирует все записи, уже устраненные Filter. Он только должен рассмотреть те же документы, которые уже в игре. Это называется "пропуск". Не все типы фильтров используют преимущества пропуска, но некоторые могут. И вот почему меньший" направляющий " фильтр заставит других использовать его быстрее.

если вы не знаете каждый тип фильтра, эвристику ваших данных и как каждый конкретный фильтр будет зависеть от каждого из них, у вас просто недостаточно информация, кроме как сказать "сначала поставьте большинство ограничивающих фильтров, а затем большие" и надеюсь, что все получится. Для bool по умолчанию, не кэшировать ее общий результат, поэтому вы должны обратить внимание на его повторное выступление (и/или его кэша). Это более эффективно, когда одна сторона пересечения фильтра мала. Поэтому, имея маленький, чтобы начать с делает все остальные пересечения быстрее, потому что они могут стать только меньше. Если бы это было bool запрос вместо фильтр делать подсчет очков еще более важно, чтобы избежать подсчета больше документов, чем необходимо.

еще одно важное замечание: "сначала самый конкретный фильтр" иногда может быть медленным (фильтр скрипта или другой), поэтому он должен действительно читать: "самые недорогие, самые специфические фильтры сперва".

С Elasticsearch 2.0, все изменится:

это время забыть все, что вы знали о запросах и фильтрах: Elasticsearch 2.0 будет принимать гораздо лучшие решения сам по себе, а не полагаться на пользователей, чтобы сформулировать оптимизированный запрос.

в 2.x вы должны стараться меньше играть в систему, и пусть двигатель сделает лучший выбор. Двигатель на самом деле может оказаться с чем-то совсем другим под капотом, переписанным фильтром, полным изменением внутренней структуры и данных. И вы даже не можете контролировать кэширование больше. Так что тебе нужно почитать об этом подробнее.

предыдущий API фильтра можно использовать двумя способами: либо с помощью итераторов над соответствующими документами, либо с помощью дополнительного API произвольного доступа, который позволяет проверить, соответствует ли конкретный документ фильтру или нет. До сих пор все хорошо, за исключением того, что лучший способ использовать фильтр зависел от того, какой фильтр у вас был: например script фильтр был более эффективным при использовании API произвольного доступа в то время как bool фильтр был более эффективным с использованием API итератора. Это был настоящий кошмар для оптимизации и был основной причиной, почему


не все фильтры кэшируются/подробное описание. Например, фильтр диапазона дат с помощью now переменная не кэшируется, потому что она меняется все время. если вы посмотрите немного ниже в первой ссылке, которую вы дали, вы увидите раздел с именем "управление кэшированием", который констатирует этот факт:

некоторые листовые фильтры, однако, не кэшируются по умолчанию, потому что это не имеет смысла делать: фильтры сценариев, фильтры geo, диапазон дат фильтры.

чтобы проиллюстрировать это, предположим, у нас есть следующая дата range фильтр (назовем его фильтром A), который фильтрует все документы за последний месяц

"range" : {
    "timestamp" : {
         "gt" : "now-1m"
    }
}

и еще один term фильтр (назовем его фильтром B) для фильтрации документов с типом XYZ

"term" : {
    "type" : "XYZ"
}

это имеет большое значение (производительность мудрая), если вы размещаете

  1. фильтр a перед фильтром B или
  2. фильтр B перед фильтром А

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

в случае 2 Вы сначала отфильтруете все документы без type XYZ, что быстро, потому что фильтр B кэшируется. Затем документы, которые сделали это через фильтр B, могут пройти через фильтр A. Поэтому, даже если фильтр A не кэшируется, выполнение все равно будет быстрее, поскольку документов меньше слева в трубопроводе фильтра.

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

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


этой сообщение в блоге на эластичном сайте опубликовано в май, 2017 говорит

Q: есть ли порядок, в котором я помещаю свои запросы / фильтры в запрос DSL дело?

a: нет, потому что они будут автоматически регистрироваться в любом случае на основе их соответствующих затрат и сопоставимых затрат.


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

поправьте меня, если я ошибаюсь...