Это многостраничный печатный вид этого раздела. Нажмите что бы печатать.

Вернуться к обычному просмотру страницы.

Термино-уровневые запросы

Ищут точные значения без анализа текста. Не учитывают релевантность

Общее описание

Термино-уровневые запросы (term-level queries) выполняют поиск по индексу для нахождения документов, содержащих точное соответствие указанному термину. В отличие от полнотекстовых запросов, результаты термино-уровневых запросов не сортируются по оценке релевантности.

Ключевые особенности:

  • Работают только с точными значениями
  • Не анализируют поисковый термин
  • Оптимальны для поиска по полям типа keyword
  • Не подходят для анализа текстовых полей (используйте полнотекстовые запросы)

Типы термино-уровневых запросов

В таблице представлены все виды термино-уровневых запросов:

Тип запроса Описание
term Поиск документов, содержащих точное соответствие указанному термину в заданном поле
terms Поиск документов, содержащих один или несколько указанных терминов в заданном поле
terms_set Поиск документов, соответствующих минимальному количеству указанных терминов
ids Поиск документов по их идентификаторам
range Поиск документов, значения поля которых попадают в указанный диапазон
prefix Поиск документов, содержащих термины с указанным префиксом
exists Поиск документов, имеющих любое проиндексированное значение в указанном поле
fuzzy Поиск документов, содержащих термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна (количество односимвольных изменений для преобразования одного термина в другой)
wildcard Поиск документов, содержащих термины, соответствующие шаблону с подстановочными символами
regexp Поиск документов, содержащих термины, соответствующие регулярному выражению

Практические рекомендации

  1. Для полей keyword всегда используйте термино-уровневые запросы:

    GET products/_search
    {
      "query": {
        "term": {
          "product_code": "ABC-123"
        }
      }
    }
    
  2. Избегайте использования термино-уровневых запросов для полей типа text, так как они проходят анализ при индексации.

  3. Для сложных условий комбинируйте несколько термино-уровневых запросов через bool:

    GET logs/_search
    {
      "query": {
        "bool": {
          "must": [
            { "term": { "status": "error" } },
            { "range": { "timestamp": { "gte": "2023-01-01" }}}
          ]
        }
      }
    }
    
  4. Для нечеткого поиска используйте fuzzy с указанием максимального расстояния:

    GET contacts/_search
    {
      "query": {
        "fuzzy": {
          "last_name": {
            "value": "Smith",
            "fuzziness": 2
          }
        }
      }
    }
    

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

1 - exists

Поиск документов, имеющих любое проиндексированное значение в указанном поле

Запрос exists

Назначение

Запрос exists используется для поиска документов, содержащих указанное поле.

Когда поле считается отсутствующим?

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

  1. В маппинге поля указано "index": false
  2. Значение поля в исходном JSON равно null или [] (пустой массив)
  3. Длина значения поля превышает параметр ignore_above в маппинге
  4. Значение поля имеет некорректный формат и в маппинге определен ignore_malformed

Когда поле считается существующим?

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

  1. Значение является массивом, содержащим как null, так и не-null элементы (например, ["один", null])
  2. Значение представляет собой пустую строку ("" или "-")
  3. Значение является кастомным null_value, определенным в маппинге поля

Пример использования

Добавление тестовых документов:

PUT testindex/_doc/1
{
  "title": "Ветер крепчает"
}

PUT testindex/_doc/2
{
  "title": "Унесенные ветром",
  "description": "Американский эпический исторический фильм 1939 года"
}

Поиск документов с полем description:

GET testindex/_search
{
  "query": {
    "exists": {
      "field": "description"
    }
  }
}

Результат выполнения:

{
  "took": 3,
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "testindex",
        "_id": "2",
        "_source": {
          "title": "Унесенные ветром",
          "description": "Американский эпический исторический фильм 1939 года"
        }
      }
    ]
  }
}

Поиск документов с отсутствующими полями

Для поиска документов без определенного поля используйте комбинацию must_not и exists:

GET testindex/_search
{
  "query": {
    "bool": {
      "must_not": {
        "exists": {
          "field": "description"
        }
      }
    }
  }
}

Результат выполнения:

{
  "took": 19,
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "testindex",
        "_id": "1",
        "_source": {
          "title": "Ветер крепчает"
        }
      }
    ]
  }
}

Параметры запроса

Запрос принимает следующие параметры:

Параметр Тип данных Описание
field Строка Обязательное поле. Имя поля, которое должно существовать в документе.
boost Число с плавающей точкой Определяет вес поля при расчете релевантности. Значения >1 увеличивают вес, значения между 0 и 1 уменьшают вес. По умолчанию: 1.0.

Пример с параметром boost:

GET testindex/_search
{
  "query": {
    "exists": {
      "field": "description",
      "boost": 2.0
    }
  }
}

Особенности работы

  1. Запрос exists проверяет именно наличие индексированного значения поля, а не его наличие в исходном документе.
  2. Для проверки отсутствия поля всегда используйте комбинацию bool + must_not + exists.
  3. Запрос можно комбинировать с другими типами запросов в составе bool запроса.

2 - fuzzy

Поиск документов, содержащих термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна

Нечеткий поиск (Fuzzy query)

Основные понятия

Нечеткий запрос (fuzzy query) ищет документы, содержащие термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна. Это расстояние измеряет количество односимвольных изменений, необходимых для преобразования одного термина в другой:

  1. Замены: кот → бот
  2. Вставки: кот → коты
  3. Удаления: кот → от
  4. Транспозиции: кот → кто

Принцип работы

  1. Запрос генерирует все возможные варианты поискового термина, попадающие в заданное расстояние редактирования
  2. Количество вариантов ограничивается параметром max_expansions
  3. Поиск выполняется по всем сгенерированным вариантам

Примеры запросов

Базовый пример с поиском ошибочного написания “HALET” вместо “HAMLET”:

GET shakespeare/_search
{
  "query": {
    "fuzzy": {
      "speaker": {
        "value": "HALET"
      }
    }
  }
}

Примечание: Используется автоматическое определение расстояния (AUTO)

Расширенный пример с настройкой параметров:

GET shakespeare/_search
{
  "query": {
    "fuzzy": {
      "speaker": {
        "value": "HALET",
        "fuzziness": "2",
        "max_expansions": 40,
        "prefix_length": 0,
        "transpositions": true,
        "rewrite": "constant_score"
      }
    }
  }
}

Параметры запроса

Синтаксис запроса:

GET _search
{
  "query": {
    "fuzzy": {
      "<поле>": {
        "value": "образец",
        ...
      }
    }
  }
}

Доступные параметры:

Параметр Тип данных Описание
value Строка Обязательный. Искомый термин
boost Число с плавающей точкой Влияет на вес поля при расчете релевантности (>1 - увеличивает, 0-1 - уменьшает). По умолчанию: 1.0
fuzziness AUTO, 0 или положительное число Максимальное расстояние редактирования. AUTO - автоматический расчет на основе длины термина
max_expansions Положительное целое Максимальное количество вариантов термина для поиска. По умолчанию: 50
prefix_length Неотрицательное целое Количество начальных символов, не учитываемых при нечетком сравнении. По умолчанию: 0
rewrite Строка Стратегия перезаписи запроса. Допустимые значения: constant_score, scoring_boolean и др. По умолчанию: constant_score
transpositions Логическое Разрешать перестановки соседних символов (ab→ba). По умолчанию: true

Особенности производительности

  1. Большие значения max_expansions (особенно с prefix_length=0) могут снизить производительность из-за генерации множества вариантов
  2. При search.allow_expensive_queries=false нечеткие запросы не выполняются
  3. Для длинных слов рекомендуется использовать prefix_length>0

Практические рекомендации

  1. Для исправления опечаток используйте fuzziness=1 или fuzziness=2
  2. Для профессиональных терминов уменьшайте max_expansions
  3. Для ускорения поиска увеличивайте prefix_length
  4. Для точных полей отключайте транспозиции (transpositions=false)

3 - ids

Поиск документов по их идентификаторам

Запрос IDs (поиск по идентификаторам)

Назначение

Запрос ids позволяет находить документы по их уникальным идентификаторам в поле _id.

Синтаксис запроса

GET shakespeare/_search
{
  "query": {
    "ids": {
      "values": [
        "34229",
        "91296"
      ]
    }
  }
}

Параметры запроса

Параметр Тип данных Описание Обязательный По умолчанию
values Массив строк Список идентификаторов документов для поиска Да -
boost Число с плавающей точкой Коэффициент усиления релевантности. Значения >1 увеличивают вес, 0-1 уменьшают вес Нет 1.0

Особенности работы

  1. Тип идентификаторов:
    Идентификаторы всегда передаются как строки, даже если в системе они числовые.

  2. Производительность:
    Запрос оптимален для выборки небольшого количества документов по известным ID.

  3. Использование с boost:
    Пример с изменением релевантности:

    GET shakespeare/_search
    {
      "query": {
        "ids": {
          "values": ["34229", "91296"],
          "boost": 2.0
        }
      }
    }
    
  4. Ограничения:

    • Не поддерживает шаблоны или диапазоны ID
    • Для поиска по >1000 ID рекомендуется использовать terms запрос
  5. Ответ системы:
    Возвращает только те документы, чьи ID присутствуют в индексе (несуществующие ID игнорируются без ошибки)

Альтернативные подходы

Для сложных сценариев поиска по ID можно использовать:

GET _search
{
  "query": {
    "terms": {
      "_id": ["34229", "91296"]
    }
  }
}

4 - prefix

Поиск документов, содержащих термины с указанным префиксом

Запрос prefix (поиск по префиксу)

Назначение

Запрос prefix выполняет поиск терминов, начинающихся с указанной приставки (префикса). Используется для:

  • Автодополнения
  • Поиска по начальным символам
  • Классификации данных с общими префиксами

Базовый синтаксис

GET shakespeare/_search
{
  "query": {
    "prefix": {
      "speaker": "KING H"
    }
  }
}

Этот запрос ищет документы, где поле speaker содержит термины, начинающиеся на “KING H”.

Расширенный синтаксис с параметрами

GET shakespeare/_search
{
  "query": {
    "prefix": {
      "speaker": {
        "value": "KING H",
        "boost": 1.5,
        "case_insensitive": true,
        "rewrite": "scoring_boolean"
      }
    }
  }
}

Параметры запроса

Параметр Тип данных Описание По умолчанию
value Строка Обязательный. Искомый префикс -
boost Число с плавающей точкой Коэффициент усиления релевантности (>1 - увеличивает, 0-1 - уменьшает) 1.0
case_insensitive Логический Регистронезависимый поиск. Если true, игнорирует регистр символов false
rewrite Строка Метод перезаписи запроса. Допустимые значения: constant_score, scoring_boolean и др. constant_score

Особенности работы

  1. Производительность:

    • При включенной настройке index_prefixes в маппинге поля запрос выполняется оптимально
    • При search.allow_expensive_queries=false запросы prefix не выполняются (кроме случаев с index_prefixes)
  2. Регистр символов:

    • По умолчанию поиск чувствителен к регистру
    • Для регистронезависимого поиска используйте "case_insensitive": true
  3. Примеры использования:

    // Поиск продуктов с кодом, начинающимся на "A12"
    GET products/_search
    {
      "query": {
        "prefix": {
          "product_code": "A12"
        }
      }
    }
    
    // Поиск городов, названия которых начинаются на "сан"
    GET cities/_search
    {
      "query": {
        "prefix": {
          "name": {
            "value": "сан",
            "case_insensitive": true
          }
        }
      }
    }
    
  4. Рекомендации:

    • Для полей с длинными значениями установите index_prefixes в маппинге
    • Избегайте очень коротких префиксов (1-2 символа) на больших индексах
    • Для сложных сценариев автодополнения рассмотрите completion suggester

5 - range

Поиск документов, значения поля которых попадают в указанный диапазон

Запрос range (диапазонный запрос)

Основные возможности

Запрос range позволяет выполнять поиск документов, значения полей которых попадают в указанный диапазон.

Синтаксис базового запроса

GET shakespeare/_search
{
  "query": {
    "range": {
      "line_id": {
        "gte": 10,
        "lte": 20
      }
    }
  }
}

Этот запрос находит документы, где значение поля line_id находится в диапазоне от 10 до 20 включительно.

Операторы сравнения

Параметр поля в запросе range принимает следующие операторы:

Оператор Описание
gte Больше или равно
gt Строго больше
lte Меньше или равно
lt Строго меньше

Работа с датами

Пример поиска по датам:

GET products/_search
{
  "query": {
    "range": {
      "created": {
        "gte": "2019/01/01",
        "lte": "2019/12/31"
      }
    }
  }
}

Этот запрос находит все товары, добавленные в 2019 году.

Указание формата даты:

GET /products/_search
{
  "query": {
    "range": {
      "created": {
        "gte": "01/01/2022",
        "lte": "31/12/2022",
        "format":"dd/MM/yyyy"
      }
    }
  }
}

Параметр format позволяет указать формат даты, отличный от формата, заданного в маппинге поля.

Особенности обработки дат

Автозаполнение отсутствующих компонентов даты: OpenSearch заполняет отсутствующие компоненты даты следующими значениями:

  • MONTH_OF_YEAR: 01
  • DAY_OF_MONTH: 01
  • HOUR_OF_DAY: 23
  • MINUTE_OF_HOUR: 59
  • SECOND_OF_MINUTE: 59
  • NANO_OF_SECOND: 999_999_999

Пример:

GET /products/_search
{
  "query": {
    "range": {
      "created": {
        "gte": "2022",
        "lte": "2022-12-31"
      }
    }
  }
}

В этом случае начальная дата будет интерпретирована как 2022-01-01T23:59:59.999999999Z.

Относительные даты

Использование математики дат:

GET products/_search
{
  "query": {
    "range": {
      "created": {
        "gte": "2019/01/01||-1y-1d"
      }
    }
  }
}

Здесь 2019/01/01 - это опорная дата, от которой вычитается 1 год и 1 день.

Округление дат:

GET products/_search
{
  "query": {
    "range": {
      "created": {
        "gte": "now-1y/M"
      }
    }
  }
}

Ключевое слово now ссылается на текущую дату и время, /M означает округление по месяцам.

Правила округления относительных дат

| Параметр | Правило округления | Пример для 2022-05-18||/M | |———-|—————————————-|—————————–| | gt | Округляет вверх | 2022-06-01T00:00:00.000 | | gte | Округляет вниз | 2022-05-01T00:00:00.000 | | lt | Округляет вниз до последней миллисекунды | 2022-04-30T23:59:59.999 | | lte | Округляет вверх до последней миллисекунды | 2022-05-31T23:59:59.999 |

Часовые пояса

По умолчанию даты считаются в UTC. Можно указать часовой пояс параметром time_zone:

GET /products/_search
{
  "query": {
    "range": {
      "created": {
        "time_zone": "-04:00",
        "gte": "2022-04-17T06:00:00"
      }
    }
  }
}

Значение 2022-04-17T06:00:00-04:00 будет преобразовано в 2022-04-17T10:00:00 UTC.

Дополнительные параметры

Синтаксис с параметрами:

GET _search
{
  "query": {
    "range": {
      "<поле>": {
        "gt": 10,
        ...
      }
    }
  }
}

Доступные параметры:

Параметр Тип данных Описание
format Строка Формат даты для этого запроса. По умолчанию используется формат, заданный в маппинге поля.
relation Строка Определяет способ сопоставления значений для полей диапазона. Допустимые значения:
- INTERSECTS (по умолчанию): Находит документы, чей диапазон пересекается с запросом
- CONTAINS: Находит документы, чей диапазон полностью содержит запрос
- WITHIN: Находит документы, чей диапазон полностью внутри запроса
boost Число с плавающей точкой Коэффициент усиления релевантности (>1 - увеличивает, 0-1 - уменьшает). По умолчанию: 1.0.
time_zone Строка Часовой пояс для преобразования дат в UTC. Допустимы смещения UTC (например, -04:00) или идентификаторы IANA (например, America/New_York).

Важно: При search.allow_expensive_queries=false диапазонные запросы по текстовым и ключевым полям не выполняются.

6 - regexp

Поиск документов, содержащих термины, соответствующие регулярному выражению

Запрос regexp (поиск по регулярным выражениям)

Назначение

Запрос regexp позволяет выполнять поиск терминов, соответствующих указанному регулярному выражению. Подробнее о синтаксисе регулярных выражений см. в документации по синтаксису регулярных выражений.

Базовый пример

GET shakespeare/_search
{
  "query": {
    "regexp": {
      "play_name": "[a-zA-Z]amlet"
    }
  }
}

Этот запрос ищет любые термины в поле play_name, которые начинаются с любой буквы (верхнего или нижнего регистра), за которой следует “amlet”.

Ключевые особенности

  1. Область применения:
    Регулярные выражения применяются к отдельным терминам (токенам) в поле, а не ко всему полю целиком.

  2. Ограничения:

    • Максимальная длина регулярного выражения по умолчанию: 1,000 символов (настраивается через index.max_regex_length)
    • Используется синтаксис Lucene, который отличается от стандартных реализаций
  3. Производительность:

    • Избегайте шаблонов с .* или .*?+ без префикса/суффикса
    • Ресурсоемкие операции, требуют search.allow_expensive_queries=true
    • Для частых запросов рекомендуется тестировать влияние на кластер
  4. Оптимизация:
    Тип поля wildcard специально оптимизирован для эффективных запросов с регулярными выражениями.

Расширенный синтаксис с параметрами

GET _search
{
  "query": {
    "regexp": {
      "<поле>": {
        "value": "[Ss]ample",
        "boost": 1.5,
        "case_insensitive": true,
        "flags": "INTERSECTION|COMPLEMENT",
        "max_determinized_states": 20000,
        "rewrite": "constant_score"
      }
    }
  }
}

Параметры запроса

Параметр Тип данных Описание По умолчанию
value Строка Обязательный. Регулярное выражение для поиска -
boost Число с плавающей точкой Коэффициент релевантности (>1 - увеличивает, 0-1 - уменьшает) 1.0
case_insensitive Логический Регистронезависимый поиск false
flags Строка Дополнительные операторы Lucene (INTERSECTION, COMPLEMENT и др.) -
max_determinized_states Целое число Максимальное число состояний автомата (защита от перегрузки) 10000
rewrite Строка Метод перезаписи запроса (constant_score, scoring_boolean и др.) constant_score

Рекомендации по использованию

  1. Тестирование:
    Всегда проверяйте регулярные выражения на тестовых данных перед использованием в production.

  2. Производительность:

    // Неэффективно:
    { "regexp": { "text": ".*pattern.*" } }
    
    // Оптимально:
    { "regexp": { "text": "prefix.*suffix" } }
    
  3. Альтернативы:
    Для сложных сценариев рассмотрите:

    • Использование wildcard типа поля
    • Применение match_phrase для текстовых фраз
    • Использование keyword полей для точного соответствия
  4. Безопасность:
    Ограничивайте max_determinized_states для предотвращения DoS-атак через сложные регулярные выражения.

Примечание: При search.allow_expensive_queries=false запросы regexp не выполняются.

7 - term

Поиск документов, содержащих точное соответствие указанному термину в заданном поле

Запрос term (поиск точного термина)

Назначение

Запрос term выполняет поиск точного соответствия указанному термину в поле. Основные характеристики:

  • Ищет неизмененное значение без анализа текста
  • Чувствителен к регистру по умолчанию
  • Оптимален для полей типа keyword, дат и чисел

Базовый синтаксис

GET shakespeare/_search
{
  "query": {
    "term": {
      "line_id": {
        "value": "61809"
      }
    }
  }
}

Этот запрос ищет строку с точным значением line_id = "61809".

Важные особенности

  1. Отличие от match запросов:

    • term не анализирует поисковый термин
    • Не подходит для текстовых полей (text), так как они анализируются при индексации
    • Для текстовых полей используйте match запросы
  2. Регистронезависимый поиск (начиная с OpenSearch 2.x):

GET shakespeare/_search
{
  "query": {
    "term": {
      "speaker": {
        "value": "HAMLET",
        "case_insensitive": true
      }
    }
  }
}

Внимание! В версиях OpenSearch 2.x и ранее регистронезависимый поиск может значительно снижать производительность. Рекомендуется:

  • Использовать lowercase фильтр при индексации
  • Применять термины в нижнем регистре в запросах

Пример ответа

{
  "hits": {
    "total": {
      "value": 1582,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "shakespeare",
        "_id": "32700",
        "_score": 2,
        "_source": {
          "speaker": "HAMLET",
          "text_entry": "[Aside] A little more than kin..."
        }
      }
    ]
  }
}

Параметры запроса

Синтаксис с параметрами:

GET _search
{
  "query": {
    "term": {
      "<поле>": {
        "value": "образец",
        ...
      }
    }
  }
}
Параметр Тип данных Описание По умолчанию
value Строка Обязательный. Точное значение для поиска (учитывает регистр и пробелы) -
boost Число с плавающей точкой Коэффициент релевантности (>1 - увеличивает, 0-1 - уменьшает) 1.0
_name Строка Имя запроса для тегирования (опционально) -
case_insensitive Логический Регистронезависимый поиск (только для OpenSearch 2.x+) false

Практические рекомендации

  1. Для текстовых полей всегда используйте match вместо term:

    // Неправильно (для text полей):
    { "term": { "description": "quick brown fox" } }
    
    // Правильно:
    { "match": { "description": "quick brown fox" } }
    
  2. Для точных значений (ID, коды, категории):

    GET products/_search
    {
      "query": {
        "term": {
          "product_code": "ABC-123"
        }
      }
    }
    
  3. Комбинируйте с другими запросами:

    GET logs/_search
    {
      "query": {
        "bool": {
          "must": [
            { "term": { "status": "error" } },
            { "range": { "timestamp": { "gte": "2023-01-01" }}}
          ]
        }
      }
    }
    
  4. Производительность:

    • Для частых запросов добавьте индекс на поле
    • Избегайте case_insensitive в favor lowercase анализаторов

8 - terms

Поиск документов, содержащих один или несколько указанных терминов в заданном поле

Terms Query (Поиск по нескольким значениям)

Основное назначение

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

Базовый синтаксис

GET shakespeare/_search
{
  "query": {
    "terms": {
      "line_id": [
        "61809",
        "61810"
      ]
    }
  }
}

Ключевые особенности

  1. Лимит терминов:
    По умолчанию максимальное количество терминов в запросе - 65,536. Настраивается через параметр index.max_terms_count.

  2. Производительность:
    Для оптимизации производительности с длинными списками терминов рекомендуется:

    • Передавать термины в отсортированном порядке (по возрастанию UTF-8 byte values)
    • Использовать механизм Terms Lookup для больших наборов терминов
  3. Подсветка результатов:
    Возможность подсветки результатов зависит от:

    • Типа highlighter’а
    • Количества терминов в запросе

Параметры запроса

Параметр Тип данных Описание По умолчанию
<field> String Поле для поиска (точное соответствие хотя бы одному термину) -
boost Float Вес поля в расчете релевантности (>1 - увеличивает, 0-1 - уменьшает) 1.0
_name String Имя запроса для тегирования -
value_type String Тип значений для фильтрации (default или bitmap) default

Terms Lookup (Поиск терминов из другого документа)

Общие принципы

Механизм Terms Lookup позволяет:

  1. Извлекать значения полей из указанного документа
  2. Использовать эти значения как условия поиска
  3. Работать с большими наборами терминов

Требования:

  • Поле _source должно быть включено (включено по умолчанию)
  • Для уменьшения сетевого трафика рекомендуется использовать индекс с:
    • Одним первичным шардом
    • Полными репликами на всех узлах данных

Пример использования

  1. Создаем индекс студентов:
PUT students
{
  "mappings": {
    "properties": {
      "student_id": { "type": "keyword" }
    }
  }
}
  1. Добавляем данные студентов:
PUT students/_doc/1
{
  "name": "Jane Doe",
  "student_id" : "111"
}

PUT students/_doc/2
{
  "name": "Mary Major",
  "student_id" : "222"
}

PUT students/_doc/3
{
  "name": "John Doe",
  "student_id" : "333"
}
  1. Создаем индекс классов с информацией о зачисленных студентах:
PUT classes/_doc/101
{
  "name": "CS101",
  "enrolled" : ["111" , "222"]
}
  1. Поиск студентов, зачисленных на CS101:
GET students/_search
{
  "query": {
    "terms": {
      "student_id": {
        "index": "classes",
        "id": "101",
        "path": "enrolled"
      }
    }
  }
}
  1. Результат содержит соответствующих студентов:
{
  "took": 13,
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_source": {
          "name": "Jane Doe",
          "student_id": "111"
        }
      },
      {
        "_index": "students",
        "_id": "2",
        "_source": {
          "name": "Mary Major",
          "student_id": "222"
        }
      }
    ]
  }
}

Работа с вложенными полями

  1. Добавляем документ с вложенной структурой:
PUT classes/_doc/102
{
  "name": "CS102",
  "enrolled_students" : {
    "id_list" : ["111" , "333"]
  }
}
  1. Поиск с указанием пути к вложенному полю:
GET students/_search
{
  "query": {
    "terms": {
      "student_id": {
        "index": "classes",
        "id": "102",
        "path": "enrolled_students.id_list"
      }
    }
  }
}
  1. Результат поиска:
{
  "took": 18,
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "students",
        "_id": "1",
        "_source": {
          "name": "Jane Doe",
          "student_id": "111"
        }
      },
      {
        "_index": "students",
        "_id": "3",
        "_source": {
          "name": "John Doe",
          "student_id": "333"
        }
      }
    ]
  }
}

Параметры Terms Lookup

Параметр Тип данных Описание Обязательность
index String Индекс, из которого извлекаются значения Обязательно
id String ID документа-источника Обязательно
path String Путь к полю (для вложенных полей - точечная нотация) Обязательно
routing String Кастомное значение маршрутизации документа Опционально*
store Boolean Использовать stored fields вместо _source Опционально

*Обязателен, если при индексации использовалось кастомное routing

Важные замечания

  1. Для полей типа text используйте match вместо terms
  2. При работе с большими наборами терминов (>10,000) рассмотрите возможность использования Bitmap Filtering
  3. Убедитесь, что поле _source включено для документов-источников

Bitmap Filtering (Фильтрация с использованием битовых карт)

Введение

Начиная с версии 2.17, OpenSearch предлагает механизм bitmap filtering для эффективной фильтрации по большому количеству терминов (10,000+). Этот подход решает проблему высокой нагрузки на сеть и память при работе с обычными terms-запросами.

Основные концепции

  1. Проблема:
    Обычные terms-запросы становятся неэффективными при большом количестве терминов из-за:

    • Высокого сетевого трафика
    • Чрезмерного потребления памяти
  2. Решение:
    Использование roaring bitmap для кодирования условий фильтрации:

    • Эффективное сжатие данных
    • Быстрые битовые операции
    • Оптимизированное использование памяти

Пример реализации

1. Подготовка индексов

Индекс продуктов:

PUT /products
{
  "mappings": {
    "properties": {
      "product_id": { "type": "integer" }
    }
  }
}

Добавление продуктов:

PUT /products/_doc/1
{
  "name": "Product 1",
  "product_id" : 111
}

PUT /products/_doc/2
{
  "name": "Product 2",
  "product_id" : 222
}

PUT /products/_doc/3
{
  "name": "Product 3",
  "product_id" : 333
}

Индекс клиентов с bitmap-полем:

PUT /customers
{
  "mappings": {
    "properties": {
      "customer_filter": {
        "type": "binary",
        "store": true
      }
    }
  }
}

2. Генерация bitmap

Пример кода на Python с использованием PyRoaringBitMap:

from pyroaring import BitMap
import base64

bm = BitMap([111, 222, 333])  # ID продуктов клиента
encoded = base64.b64encode(BitMap.serialize(bm))
encoded_bm_str = encoded.decode('utf-8')

print(f"Encoded Bitmap: {encoded_bm_str}")

3. Индексация bitmap

POST customers/_doc/customer123
{
  "customer_filter": "OjAAAAEAAAAAAAIAEAAAAG8A3gBNAQ==" 
}

Использование bitmap в запросах

Вариант 1: Lookup из документа

POST /products/_search
{
  "query": {
    "terms": {
      "product_id": {
        "index": "customers",
        "id": "customer123",
        "path": "customer_filter",
        "store": true
      },
      "value_type": "bitmap"
    }
  }
}

Вариант 2: Прямая передача bitmap

POST /products/_search
{
  "query": {
    "terms": {
      "product_id": [
        "OjAAAAEAAAAAAAIAEAAAAG8A3gBNAQ=="
      ],
      "value_type": "bitmap"
    }
  }
}

Ключевые параметры

Параметр Тип данных Описание Обязательность
value_type String Должно быть bitmap для активации этого режима Обязательно
store Boolean true для поиска в stored field вместо _source Опционально
index String Индекс-источник bitmap (для lookup) Для lookup
id String ID документа с bitmap Для lookup
path String Поле с bitmap данными Для lookup

Преимущества подхода

  1. Эффективность:

    • Снижение сетевого трафика до 10 раз
    • Уменьшение использования памяти на 50-90%
  2. Гибкость:

    • Поддержка динамического обновления фильтров
    • Возможность комбинирования условий
  3. Производительность:

    • Быстрое выполнение даже для 100,000+ терминов
    • Оптимизированные битовые операции на уровне ядра

Рекомендации

  1. Используйте для сложных фильтров с >10,000 значений
  2. Регулярно обновляйте bitmap при изменении данных
  3. Тестируйте производительность для вашего конкретного сценария
  4. Рассмотрите использование сжатых форматов bitmap для экономии места

9 - terms set

Поиск документов, соответствующих минимальному количеству указанных терминов

Terms Set Query (Запрос с условием минимального соответствия терминов)

Основное назначение

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

Основные характеристики

  • Ищет точные соответствия терминов (без анализа текста)
  • Требует указания минимального количества совпадающих терминов
  • Поддерживает два способа определения минимального количества:
    • Через поле документа (minimum_should_match_field)
    • Через скрипт (minimum_should_match_script)
  • Оптимален для работы с полями типа keyword

Пример использования

1. Подготовка индекса

PUT students
{
  "mappings": {
    "properties": {
      "name": { "type": "keyword" },
      "classes": { "type": "keyword" },
      "min_required": { "type": "integer" }
    }
  }
}

2. Индексация документов

PUT students/_doc/1
{
  "name": "Mary Major",
  "classes": [ "CS101", "CS102", "MATH101" ],
  "min_required": 2
}

PUT students/_doc/2
{
  "name": "John Doe",
  "classes": [ "CS101", "MATH101", "ENG101" ],
  "min_required": 2
}

3. Поиск с использованием поля для минимального соответствия

GET students/_search
{
  "query": {
    "terms_set": {
      "classes": {
        "terms": [ "CS101", "CS102", "MATH101" ],
        "minimum_should_match_field": "min_required"
      }
    }
  }
}

4. Поиск с использованием скрипта для минимального соответствия

GET students/_search
{
  "query": {
    "terms_set": {
      "classes": {
        "terms": [ "CS101", "CS102", "MATH101" ],
        "minimum_should_match_script": {
          "source": "Math.min(params.num_terms, doc['min_required'].value)"
        }
      }
    }
  }
}

Параметры запроса

Базовый синтаксис:

GET _search
{
  "query": {
    "terms_set": {
      "<поле>": {
        "terms": [ "term1", "term2" ],
        ...
      }
    }
  }
}
Параметр Тип данных Описание Обязательность
terms Массив строк Термины для поиска (точное соответствие) Обязательно
minimum_should_match_field Строка Поле, содержащее минимальное количество совпадений Один из двух
minimum_should_match_script Строка Скрипт, возвращающий минимальное количество совпадений Один из двух
boost Число с плавающей точкой Коэффициент релевантности (>1 - увеличивает, 0-1 - уменьшает) Опционально

Особенности работы

  1. Механизм подсчета:
    Документ считается соответствующим, если количество совпадающих терминов из массива terms ≥ указанного минимума.

  2. Определение минимума:

    • Через поле: значение берется из указанного поля документа
    • Через скрипт: вычисляется динамически для каждого документа
  3. Производительность:

    • Использование поля minimum_should_match_field обычно более эффективно
    • Скрипты обеспечивают гибкость, но могут снижать производительность

Рекомендации по использованию

  1. Для статических условий используйте minimum_should_match_field
  2. Для сложной логики применяйте minimum_should_match_script
  3. Всегда индексируйте поля, используемые для определения минимума
  4. Для текстовых полей предварительно применяйте нормализацию
  5. Тестируйте производительность на реалистичных объемах данных

Примеры скриптов

  1. Фиксированное значение:
"minimum_should_match_script": {
  "source": "2"
}
  1. Динамическое вычисление:
"minimum_should_match_script": {
  "source": "doc['min_required'].value * params.factor",
  "params": {
    "factor": 1.5
  }
}
  1. Ограничение сверху:
"minimum_should_match_script": {
  "source": "Math.min(5, doc['min_required'].value)"
}

10 - wildcard

Поиск документов, содержащих термины, соответствующие шаблону с подстановочными символами

Wildcard Query (Поиск с подстановочными символами)

Основное назначение

Запрос wildcard позволяет выполнять поиск терминов по шаблону с использованием подстановочных символов. Особенно полезен для:

  • Поиска по частичным совпадениям
  • Нечеткого поиска с известной структурой
  • Работы с кодами, артикулами и другими структурированными данными

Поддерживаемые операторы

Оператор Описание Пример
* Соответствует нулю или более символов H*Y найдет “HAPPY”, “HALLEY”
? Соответствует любому одному символу H?Y найдет “HAY”, но не “HAPPY”
case_insensitive Флаг регистронезависимости true/false (по умолчанию false)

Примеры запросов

1. Чувствительный к регистру поиск:

GET shakespeare/_search
{
  "query": {
    "wildcard": {
      "speaker": {
        "value": "H*Y",
        "case_insensitive": false
      }
    }
  }
}

2. Использование разных операторов:

  • H*Y - найдет любые значения, начинающиеся на H и заканчивающиеся на Y
  • H?Y - найдет только 3-символьные значения типа “HMY”

Параметры запроса

Базовый синтаксис:

GET _search
{
  "query": {
    "wildcard": {
      "<поле>": {
        "value": "шаб*лон",
        ...
      }
    }
  }
}
Параметр Тип данных Описание По умолчанию
value String Шаблон для поиска с подстановочными символами Обязательный
boost Float Коэффициент релевантности (>1 - увеличивает, 0-1 - уменьшает) 1.0
case_insensitive Boolean Регистронезависимый поиск false
rewrite String Метод перезаписи запроса (constant_score, scoring_boolean и др.) constant_score

Критические особенности производительности

  1. Предупреждение:
    Wildcard-запросы могут быть медленными, так как требуют перебора множества терминов.

  2. Золотое правило:
    Избегайте размещения подстановочных символов в начале шаблона (например, *pattern), так как это:

    • Крайне ресурсоемко
    • Может привести к таймаутам
    • Создает нагрузку на кластер
  3. Оптимизация:
    Для частых wildcard-запросов используйте специальный wildcard тип поля, который:

    • Создает оптимизированный индекс
    • Обеспечивает высокую производительность
    • Поддерживает сложные шаблоны

Практические рекомендации

  1. Для префиксного поиска используйте prefix запрос вместо H*:

    {
      "query": {
        "prefix": {
          "field": "H"
        }
      }
    }
    
  2. Для сложных шаблонов рассмотрите:

    • Использование wildcard типа поля
    • Применение regexp запросов для более сложных паттернов
  3. При работе с большими индексами:

    • Ограничивайте время выполнения через timeout
    • Используйте search.allow_expensive_queries для контроля
  4. Пример безопасного шаблона:

    {
      "query": {
        "wildcard": {
          "product_code": {
            "value": "ABC-202?-*",
            "case_insensitive": true
          }
        }
      }
    }
    

    Такой шаблон найдет коды типа “ABC-2023-XXX” и безопасен для выполнения.

Важные ограничения

  1. При search.allow_expensive_queries=false wildcard-запросы не выполняются
  2. Максимальная длина шаблона ограничена параметром index.max_regex_length (по умолчанию 1000 символов)
  3. Не поддерживает стандартные regex-конструкции (используйте regexp запрос для сложных выражений)