Бизнес-условия редко помещаются в одну конструкцию: товар должен подходить по тексту, быть в наличии, попадать в диапазон цены и не иметь запрещённого статуса. bool соединяет такие условия. Каждый уровень читайте как отдельное логическое выражение: соседние filter связаны через И, а should задаёт альтернативы с определённым числом обязательных совпадений.
Различие query context и filter context связано с оценкой: поиск определяет, насколько хорошо документ подходит, фильтр — только проходит ли он условие. Внешний filter подавляет scoring и у потомков, даже если вложенный bool содержит must.
- must + filter: обязательно
- must_not: исключить совпавшие
- should: нужное число совпадений
- Допущенный документ + score
Документ должен выполнить обязательные условия и избежать исключений. Обязательные совпадения should проверяются до ранжирования результата.
Примеры выполнены на публичном наборе products в Elasticsearch 9.4.3. Ответы — сокращённые фрагменты JSON: время, сведения о шардах и индексе опущены. Числовые оценки иллюстративны и могут меняться. Примеры объясняют способ решения; значения в заданиях могут отличаться.
Обязательные условия
Каждое условие bool.must обязано совпасть. В query context эти условия также участвуют в оценке. Список из match и term одновременно требует текстового совпадения и точного условия. Пример ищет gaming в name и требует наличие: это И, а не выбор между словом и логическим значением.
Одиночное условие можно записать объектом, несколько обычно записывают массивом. Выбирайте понятный единый стиль. В прикладном поиске наличие чаще удобно вынести в filter, но этот раздел отдельно показывает must: упражнение может намеренно требовать конкретный контекст.
Разберём другой сценарий
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "gaming"
}
},
{
"term": {
"in_stock": true
}
}
]
}
},
"size": 2,
"_source": [
"name",
"in_stock"
]
}Ответ Elasticsearch
{
"hits": {
"total": {
"value": 20,
"relation": "eq"
},
"hits": [
{
"_id": "4",
"_score": 2.7367332,
"_source": {
"name": "Logitech Gaming Keyboard 4",
"in_stock": true
}
},
{
"_id": "14",
"_score": 2.7367332,
"_source": {
"name": "Samsung Gaming Keyboard 14",
"in_stock": true
}
}
]
}
}Как читать результат
Каждый товар подходит по тексту и находится в наличии. Оценка определяется поисковыми условиями, а не количеством полей JSON.
Фильтр без scoring
bool.filter требует выполнения каждого ограничения без добавления вклада в релевантность. Точный бренд, наличие и цена — подходящие примеры: товар не должен становиться релевантнее только из-за наличия. Если поисковых условий нет, bool только с filter обычно возвращает нулевую оценку.
Контекст распространяется на всю вложенную конструкцию. Вложенный bool с двумя фильтрами означает сгруппированное И. Сохраняйте читаемость и не создавайте уровни без необходимости. Elasticsearch может учитывать фильтры для кеширования, но корректность не должна зависеть от попадания в кеш или конкретного порядка исполнения.
| Условие | Обязательно? | Добавляет score в query context? |
|---|---|---|
| must | Да | Да |
| filter | Да | Нет |
| must_not | Не должно совпасть | Нет |
| should | Зависит от minimum_should_match | Да |
Разберём другой сценарий
{
"query": {
"bool": {
"filter": [
{
"term": {
"brand.keyword": "Sony"
}
},
{
"term": {
"in_stock": false
}
},
{
"range": {
"price": {
"lt": 1200
}
}
}
]
}
},
"size": 2,
"_source": [
"name",
"brand",
"price",
"in_stock"
],
"sort": [
{
"id": "asc"
}
]
}Ответ Elasticsearch
{
"hits": {
"total": {
"value": 40,
"relation": "eq"
},
"hits": [
{
"_id": "3",
"_score": null,
"_source": {
"name": "Sony Travel Speaker 3",
"brand": "Sony",
"price": 100,
"in_stock": false
}
},
{
"_id": "15",
"_score": null,
"_source": {
"name": "Sony USB Cable 15",
"brand": "Sony",
"price": 499,
"in_stock": false
}
}
]
}
}Как читать результат
Товары выполняют все три ограничения. Сортировка по id стабилизирует просмотр; нулевой или null-score в таком ответе не означает ошибку.
Исключение товаров
Условие must_not исключает документ, если внутренний запрос совпал. При нескольких must_not ни одно из них не должно совпасть: исключение статуса A и статуса B убирает обе группы. Это не требование отличаться только от одного значения.
bool только с must_not начинает со всех документов и вычитает совпадения. Поэтому отсутствующие значения могут остаться: документ без status не совпадает с term status: preorder и этим условием не исключается. Если нужно наличие поля, добавьте exists как отдельное обязательное условие.
Разберём другой сценарий
{
"query": {
"bool": {
"must_not": [
{
"term": {
"status": "preorder"
}
}
]
}
},
"size": 2,
"_source": [
"name",
"status"
],
"sort": [
{
"id": "asc"
}
]
}Ответ Elasticsearch
{
"hits": {
"total": {
"value": 200,
"relation": "eq"
},
"hits": [
{
"_id": "2",
"_score": null,
"_source": {
"name": "Reference device",
"status": "discontinued"
}
},
{
"_id": "3",
"_score": null,
"_source": {
"name": "Sony Travel Speaker 3",
"status": "active"
}
}
]
}
}Как читать результат
Ни один возвращённый товар не имеет preorder. Запрос намеренно оставляет active и discontinued: он показывает исключение, а не полную политику доступности.
Альтернативные бренды
should задаёт альтернативы. В примере это категории, а не бренды: достаточно Audio или Accessories. minimum_should_match: 1 явно фиксирует ИЛИ, хотя bool только с should и так по умолчанию требует одно совпадение. Явное значение особенно важно при добавлении обязательных условий.
Каждая альтернатива может быть целым деревом запроса. Для (A И B) ИЛИ (C И D) поместите в should две вложенные bool-группы, а не четыре независимых условия. В финальном уроке такое группирование связывает категории с разными диапазонами цен.
| A | B | A И B | A ИЛИ B |
|---|---|---|---|
| ложь | ложь | ложь | ложь |
| ложь | истина | ложь | истина |
| истина | ложь | ложь | истина |
| истина | истина | истина | истина |
Разберём другой сценарий
{
"query": {
"bool": {
"should": [
{
"term": {
"category": "Audio"
}
},
{
"term": {
"category": "Accessories"
}
}
],
"minimum_should_match": 1
}
},
"size": 2,
"_source": [
"name",
"category"
],
"sort": [
{
"id": "asc"
}
]
}Ответ Elasticsearch
{
"hits": {
"total": {
"value": 150,
"relation": "eq"
},
"hits": [
{
"_id": "2",
"_score": null,
"_source": {
"name": "Reference device",
"category": "Audio"
}
},
{
"_id": "4",
"_score": null,
"_source": {
"name": "Logitech Gaming Keyboard 4",
"category": "Accessories"
}
}
]
}
}Как читать результат
Каждый товар относится хотя бы к одной разрешённой категории. Обе одновременно не требуются, что важно для нашего однозначного category.
Минимум совпадений
minimum_should_match задаётся в том bool, чьими should он управляет. При наличии must или filter значение по умолчанию равно нулю; без них — единице. Для «не меньше двух признаков» задайте число явно. Пример требует два из трёх слов в name и одновременно ограничивает наличие.
Подсчитываются совпавшие условия should, а не число терминов одного match. Один match с несколькими словами всё ещё является одним should-условием. Для отдельно учитываемых признаков нужны отдельные конструкции; внутри каждой match анализатор продолжает обрабатывать регистр и токены.
Разберём другой сценарий
{
"query": {
"bool": {
"filter": [
{
"term": {
"in_stock": true
}
}
],
"should": [
{
"match": {
"name": "wireless"
}
},
{
"match": {
"name": "premium"
}
},
{
"match": {
"name": "mouse"
}
}
],
"minimum_should_match": 2
}
},
"size": 2,
"_source": [
"name",
"in_stock"
]
}Ответ Elasticsearch
{
"hits": {
"total": {
"value": 39,
"relation": "eq"
},
"hits": [
{
"_id": "7",
"_score": 3.2707968,
"_source": {
"name": "Apple Wireless Mouse 7",
"in_stock": true
}
},
{
"_id": "17",
"_score": 3.2707968,
"_source": {
"name": "Dell Wireless Mouse 17",
"in_stock": true
}
}
]
}
}Как читать результат
Подходящее название содержит как минимум два запрошенных словесных признака. Одного совпадения по наличию недостаточно.
Краткая памятка
- must — обязательное поисковое совпадение; filter — обязательный допуск.
- must_not исключает документы, совпавшие хотя бы с одним исключением.
- Значение should по умолчанию меняется при наличии must или filter.
- minimum_should_match считает условия, а не слова внутри match.
- Сначала группируйте ветви И, затем соединяйте их через ИЛИ.
Официальная документация
Готовы применить знания?
Подтвердите прочтение, чтобы сохранить своё место. Чтение и решение заданий учитываются отдельно в этом браузере с помощью гостевой cookie.