Оглавление курса
Query DSL · 12 / 28

Булева логика

Переведём бизнес-правила в дерево bool и разберём неочевидное поведение should.

Разделов: 9Elasticsearch 9.4.3Ещё не прочитан

Чему вы научитесь

  • Четыре роли условий
  • Неявные значения
  • Скобки и отрицание

Переведём бизнес-правила в дерево bool и разберём неочевидное поведение should.

Примеры course-products используют учебную схему и товар из главы 5 «Mapping и типы полей». Разборы упражнений ниже используют отдельный публичный набор тренажёра.

Механизм работы
  • Обязательные ограничения
  • Группа альтернатив
  • Совпадение + score

Переведём бизнес-правила в дерево bool и разберём неочевидное поведение should.

Курс ориентирован на Elasticsearch 9.4.3. Разборы упражнений используют публичный набор products; остальные запросы показывают отдельные учебные индексы и могут требовать подготовки или прав, недоступных в тренажёре. Ответы сокращены, score может меняться. Для расширенных функций проверяйте лицензию и вариант развёртывания.

01 / 09

Четыре роли условий

must требует совпадения и может влиять на score; filter требует совпадения без вклада в score; must_not исключает. should задаёт альтернативы или бонусы. Условия одного must или filter объединяются через AND. Массив should — не универсальный обязательный OR: его обязательность зависит от остальных частей bool и minimum_should_match.

Самопроверка
02 / 09

Неявные значения

Если bool содержит should и не содержит must или filter, по умолчанию нужен один should. При наличии must или filter значение по умолчанию становится нулём. Добавив фильтр наличия, можно случайно превратить обязательный набор брендов в необязательные бонусы. Если альтернативы обязательны по бизнес-смыслу, указывайте minimum_should_match явно или помещайте их в отдельный вложенный bool.

Самопроверка
03 / 09

Скобки и отрицание

Условие «в наличии И (бренд A ИЛИ цена ниже 100)» требует вложенной группы. Исключение товара и исключение отдельного nested-предложения — разные задачи. Для сложных правил сначала выпишите таблицу примеров: какие товары обязаны пройти и какие не должны. Имена запросов помогают диагностировать совпавшие ветви, но могут добавлять стоимость.

Явное требование одной альтернативы сохраняет смысл при добавлении фильтров.

POST /course-products/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "in_stock": true
          }
        }
      ],
      "should": [
        {
          "term": {
            "brand": "Sony"
          }
        },
        {
          "range": {
            "price": {
              "lt": 100
            }
          }
        }
      ],
      "minimum_should_match": 1
    }
  }
}

Как читать результат

Явное требование одной альтернативы сохраняет смысл при добавлении фильтров.

Самопроверка
04 / 09

Разбор на примере каталога

Для условия in_stock AND (Sony OR price<100) составьте четыре товара: Sony/150/в наличии, Bose/50/в наличии, Bose/150/в наличии, Sony/50/нет в наличии. Первые два проходят, последние два — нет. Если после добавления filter проходит третий товар, альтернативы стали необязательными. Если проходит четвёртый, потерялось обязательное ограничение наличия. Такая таблица фиксирует бизнес-смысл и остаётся полезной даже при полном изменении формы JSON.

Самопроверка
05 / 09

Обязательные условия

Каждое условие bool.must обязано совпасть. В query context эти условия также участвуют в оценке. Список из match и term одновременно требует текстового совпадения и точного условия. Пример ищет gaming в name и требует наличие: это И, а не выбор между словом и логическим значением.

Одиночное условие можно записать объектом, несколько обычно записывают массивом. Выбирайте понятный единый стиль. В прикладном поиске наличие чаще удобно вынести в filter, но этот раздел отдельно показывает must: упражнение может намеренно требовать конкретный контекст.

Разберём другой сценарий

POST /products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "gaming"
          }
        },
        {
          "term": {
            "in_stock": true
          }
        }
      ]
    }
  },
  "size": 2,
  "_source": [
    "name",
    "in_stock"
  ]
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "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.

Закрепить в задании 6
06 / 09

Исключение товаров

Условие must_not исключает документ, если внутренний запрос совпал. При нескольких must_not ни одно из них не должно совпасть: исключение статуса A и статуса B убирает обе группы. Это не требование отличаться только от одного значения.

bool только с must_not начинает со всех документов и вычитает совпадения. Поэтому отсутствующие значения могут остаться: документ без status не совпадает с term status: preorder и этим условием не исключается. Если нужно наличие поля, добавьте exists как отдельное обязательное условие.

Разберём другой сценарий

POST /products/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "term": {
            "status": "preorder"
          }
        }
      ]
    }
  },
  "size": 2,
  "_source": [
    "name",
    "status"
  ],
  "sort": [
    {
      "id": "asc"
    }
  ]
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "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: он показывает исключение, а не полную политику доступности.

Закрепить в задании 8
07 / 09

Альтернативные бренды

should задаёт альтернативы. В примере это категории, а не бренды: достаточно Audio или Accessories. minimum_should_match: 1 явно фиксирует ИЛИ, хотя bool только с should и так по умолчанию требует одно совпадение. Явное значение особенно важно при добавлении обязательных условий.

Каждая альтернатива может быть целым деревом запроса. Для (A И B) ИЛИ (C И D) поместите в should две вложенные bool-группы, а не четыре независимых условия. В финальном уроке такое группирование связывает категории с разными диапазонами цен.

ABA И BA ИЛИ B
ложьложьложьложь
ложьистиналожьистина
истиналожьложьистина
истинаистинаистинаистина

Разберём другой сценарий

POST /products/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "category": "Audio"
          }
        },
        {
          "term": {
            "category": "Accessories"
          }
        }
      ],
      "minimum_should_match": 1
    }
  },
  "size": 2,
  "_source": [
    "name",
    "category"
  ],
  "sort": [
    {
      "id": "asc"
    }
  ]
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "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.

Закрепить в задании 9
08 / 09

Минимум совпадений

minimum_should_match задаётся в том bool, чьими should он управляет. При наличии must или filter значение по умолчанию равно нулю; без них — единице. Для «не меньше двух признаков» задайте число явно. Пример требует два из трёх слов в name и одновременно ограничивает наличие.

Подсчитываются совпавшие условия should, а не число терминов одного match. Один match с несколькими словами всё ещё является одним should-условием. Для отдельно учитываемых признаков нужны отдельные конструкции; внутри каждой match анализатор продолжает обрабатывать регистр и токены.

Разберём другой сценарий

POST /products/_search
{
  "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
Сокращённый ответ · JSON
{
  "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
        }
      }
    ]
  }
}

Как читать результат

Подходящее название содержит как минимум два запрошенных словесных признака. Одного совпадения по наличию недостаточно.

Закрепить в задании 10
09 / 09

Сложные бизнес-условия

Начните с формулы S И (A ИЛИ B). S — общий допуск: наличие и разрешённые статусы. Каждая ветвь связывает свою категорию со своим диапазоном. В примере S разрешает только preorder, A — Accessories дешевле 200, B — Smartphones от 200 включительно до 900 исключительно.

Разместите общие ограничения во внешнем filter, две ветви во внешнем should и minimum_should_match: 1 на том же уровне. Внутри ветви используйте bool.filter для категории И цены. Плоский should из четырёх отдельных условий пропускает, например, дешёвый товар чужой категории.

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

Общее SВетвь AВетвь BПринять?
ложьистинаистинаНет
истиналожьложьНет
истинаистиналожьДа
истиналожьистинаДа

Разберём другой сценарий

POST /products/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "in_stock": true
          }
        },
        {
          "term": {
            "status": "preorder"
          }
        }
      ],
      "should": [
        {
          "bool": {
            "filter": [
              {
                "term": {
                  "category": "Accessories"
                }
              },
              {
                "range": {
                  "price": {
                    "lt": 200
                  }
                }
              }
            ]
          }
        },
        {
          "bool": {
            "filter": [
              {
                "term": {
                  "category": "Smartphones"
                }
              },
              {
                "range": {
                  "price": {
                    "gte": 200,
                    "lt": 900
                  }
                }
              }
            ]
          }
        }
      ],
      "minimum_should_match": 1
    }
  },
  "size": 2,
  "_source": [
    "name",
    "category",
    "price",
    "status",
    "in_stock"
  ],
  "sort": [
    {
      "id": "asc"
    }
  ]
}
Ответ Elasticsearch
Сокращённый ответ · JSON
{
  "hits": {
    "total": {
      "value": 15,
      "relation": "eq"
    },
    "hits": [
      {
        "_id": "4",
        "_score": null,
        "_source": {
          "name": "Logitech Gaming Keyboard 4",
          "category": "Accessories",
          "price": 199,
          "in_stock": true,
          "status": "preorder"
        }
      },
      {
        "_id": "25",
        "_score": null,
        "_source": {
          "name": "Apple USB Cable 25",
          "category": "Smartphones",
          "price": 499,
          "in_stock": true,
          "status": "preorder"
        }
      }
    ]
  }
}

Как читать результат

Каждый товар проходит общие ограничения и целую ветвь категория–цена. Условие из ветви A нельзя соединить с несвязанным условием из B.

Закрепить в задании 26

Самопроверка

Сначала ответьте самостоятельно, затем раскройте объяснение.

1. Когда should по умолчанию обязателен?

Если есть should и нет must или filter, требуется одно совпадение.

2. Что меняется после добавления filter?

Неявный minimum_should_match становится нулём.

3. Чем must отличается от filter?

Оба требуют совпадения, но filter не вносит score.

4. Как выразить скобки?

Вложенным bool с нужной обязательностью альтернатив.

5. Как проверить бизнес-правило?

Составить положительные и отрицательные примеры, особенно на границах условий.

Краткая памятка

  • Если есть should и нет must или filter, требуется одно совпадение.
  • Неявный minimum_should_match становится нулём.
  • Оба требуют совпадения, но filter не вносит score.
  • Вложенным bool с нужной обязательностью альтернатив.
  • Составить положительные и отрицательные примеры, особенно на границах условий.

Официальная документация

Готовы применить знания?

Подтвердите прочтение, чтобы сохранить своё место. Чтение и решение заданий учитываются отдельно в этом браузере с помощью гостевой cookie.