Термино-уровневые запросы
Ищут точные значения без анализа текста. Не учитывают релевантность
Общее описание
Термино-уровневые запросы (term-level queries) выполняют поиск по индексу для нахождения документов, содержащих точное соответствие указанному термину. В отличие от полнотекстовых запросов, результаты термино-уровневых запросов не сортируются по оценке релевантности.
Ключевые особенности:
- Работают только с точными значениями
- Не анализируют поисковый термин
- Оптимальны для поиска по полям типа
keyword
- Не подходят для анализа текстовых полей (используйте полнотекстовые запросы)
Типы термино-уровневых запросов
В таблице представлены все виды термино-уровневых запросов:
Тип запроса |
Описание |
term |
Поиск документов, содержащих точное соответствие указанному термину в заданном поле |
terms |
Поиск документов, содержащих один или несколько указанных терминов в заданном поле |
terms_set |
Поиск документов, соответствующих минимальному количеству указанных терминов |
ids |
Поиск документов по их идентификаторам |
range |
Поиск документов, значения поля которых попадают в указанный диапазон |
prefix |
Поиск документов, содержащих термины с указанным префиксом |
exists |
Поиск документов, имеющих любое проиндексированное значение в указанном поле |
fuzzy |
Поиск документов, содержащих термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна (количество односимвольных изменений для преобразования одного термина в другой) |
wildcard |
Поиск документов, содержащих термины, соответствующие шаблону с подстановочными символами |
regexp |
Поиск документов, содержащих термины, соответствующие регулярному выражению |
Практические рекомендации
-
Для полей keyword
всегда используйте термино-уровневые запросы:
GET products/_search
{
"query": {
"term": {
"product_code": "ABC-123"
}
}
}
-
Избегайте использования термино-уровневых запросов для полей типа text
, так как они проходят анализ при индексации.
-
Для сложных условий комбинируйте несколько термино-уровневых запросов через bool
:
GET logs/_search
{
"query": {
"bool": {
"must": [
{ "term": { "status": "error" } },
{ "range": { "timestamp": { "gte": "2023-01-01" }}}
]
}
}
}
-
Для нечеткого поиска используйте fuzzy
с указанием максимального расстояния:
GET contacts/_search
{
"query": {
"fuzzy": {
"last_name": {
"value": "Smith",
"fuzziness": 2
}
}
}
}
Все технические термины сохранены в оригинальном написании (term, fuzzy, wildcard и т.д.) для соответствия международной практике, с добавлением пояснений на русском языке для лучшего понимания.
1 - exists
Поиск документов, имеющих любое проиндексированное значение в указанном поле
Запрос exists
Назначение
Запрос exists
используется для поиска документов, содержащих указанное поле.
Когда поле считается отсутствующим?
Индексированное значение будет отсутствовать для поля документа в следующих случаях:
- В маппинге поля указано
"index": false
- Значение поля в исходном JSON равно
null
или []
(пустой массив)
- Длина значения поля превышает параметр
ignore_above
в маппинге
- Значение поля имеет некорректный формат и в маппинге определен
ignore_malformed
Когда поле считается существующим?
Индексированное значение будет присутствовать для поля документа в следующих случаях:
- Значение является массивом, содержащим как
null
, так и не-null элементы (например, ["один", null]
)
- Значение представляет собой пустую строку (
""
или "-"
)
- Значение является кастомным
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
}
}
}
Особенности работы
- Запрос
exists
проверяет именно наличие индексированного значения поля, а не его наличие в исходном документе.
- Для проверки отсутствия поля всегда используйте комбинацию
bool
+ must_not
+ exists
.
- Запрос можно комбинировать с другими типами запросов в составе
bool
запроса.
2 - fuzzy
Поиск документов, содержащих термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна
Нечеткий поиск (Fuzzy query)
Основные понятия
Нечеткий запрос (fuzzy query) ищет документы, содержащие термины, схожие с поисковым термином в пределах максимально допустимого расстояния Дамерау-Левенштейна. Это расстояние измеряет количество односимвольных изменений, необходимых для преобразования одного термина в другой:
- Замены: кот → бот
- Вставки: кот → коты
- Удаления: кот → от
- Транспозиции: кот → кто
Принцип работы
- Запрос генерирует все возможные варианты поискового термина, попадающие в заданное расстояние редактирования
- Количество вариантов ограничивается параметром
max_expansions
- Поиск выполняется по всем сгенерированным вариантам
Примеры запросов
Базовый пример с поиском ошибочного написания “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 |
Особенности производительности
- Большие значения
max_expansions
(особенно с prefix_length=0
) могут снизить производительность из-за генерации множества вариантов
- При
search.allow_expensive_queries=false
нечеткие запросы не выполняются
- Для длинных слов рекомендуется использовать
prefix_length>0
Практические рекомендации
- Для исправления опечаток используйте
fuzziness=1
или fuzziness=2
- Для профессиональных терминов уменьшайте
max_expansions
- Для ускорения поиска увеличивайте
prefix_length
- Для точных полей отключайте транспозиции (
transpositions=false
)
3 - ids
Поиск документов по их идентификаторам
Запрос IDs (поиск по идентификаторам)
Назначение
Запрос ids
позволяет находить документы по их уникальным идентификаторам в поле _id
.
Синтаксис запроса
GET shakespeare/_search
{
"query": {
"ids": {
"values": [
"34229",
"91296"
]
}
}
}
Параметры запроса
Параметр |
Тип данных |
Описание |
Обязательный |
По умолчанию |
values |
Массив строк |
Список идентификаторов документов для поиска |
Да |
- |
boost |
Число с плавающей точкой |
Коэффициент усиления релевантности. Значения >1 увеличивают вес, 0-1 уменьшают вес |
Нет |
1.0 |
Особенности работы
-
Тип идентификаторов:
Идентификаторы всегда передаются как строки, даже если в системе они числовые.
-
Производительность:
Запрос оптимален для выборки небольшого количества документов по известным ID.
-
Использование с boost:
Пример с изменением релевантности:
GET shakespeare/_search
{
"query": {
"ids": {
"values": ["34229", "91296"],
"boost": 2.0
}
}
}
-
Ограничения:
- Не поддерживает шаблоны или диапазоны ID
- Для поиска по >1000 ID рекомендуется использовать
terms
запрос
-
Ответ системы:
Возвращает только те документы, чьи 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 |
Особенности работы
-
Производительность:
- При включенной настройке
index_prefixes
в маппинге поля запрос выполняется оптимально
- При
search.allow_expensive_queries=false
запросы prefix
не выполняются (кроме случаев с index_prefixes
)
-
Регистр символов:
- По умолчанию поиск чувствителен к регистру
- Для регистронезависимого поиска используйте
"case_insensitive": true
-
Примеры использования:
// Поиск продуктов с кодом, начинающимся на "A12"
GET products/_search
{
"query": {
"prefix": {
"product_code": "A12"
}
}
}
// Поиск городов, названия которых начинаются на "сан"
GET cities/_search
{
"query": {
"prefix": {
"name": {
"value": "сан",
"case_insensitive": true
}
}
}
}
-
Рекомендации:
- Для полей с длинными значениями установите
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,000 символов (настраивается через
index.max_regex_length
)
- Используется синтаксис Lucene, который отличается от стандартных реализаций
-
Производительность:
- Избегайте шаблонов с
.*
или .*?+
без префикса/суффикса
- Ресурсоемкие операции, требуют
search.allow_expensive_queries=true
- Для частых запросов рекомендуется тестировать влияние на кластер
-
Оптимизация:
Тип поля 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 |
Рекомендации по использованию
-
Тестирование:
Всегда проверяйте регулярные выражения на тестовых данных перед использованием в production.
-
Производительность:
// Неэффективно:
{ "regexp": { "text": ".*pattern.*" } }
// Оптимально:
{ "regexp": { "text": "prefix.*suffix" } }
-
Альтернативы:
Для сложных сценариев рассмотрите:
- Использование
wildcard
типа поля
- Применение
match_phrase
для текстовых фраз
- Использование
keyword
полей для точного соответствия
-
Безопасность:
Ограничивайте 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"
.
Важные особенности
-
Отличие от match запросов:
term
не анализирует поисковый термин
- Не подходит для текстовых полей (
text
), так как они анализируются при индексации
- Для текстовых полей используйте
match
запросы
-
Регистронезависимый поиск (начиная с 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 |
Практические рекомендации
-
Для текстовых полей всегда используйте match
вместо term
:
// Неправильно (для text полей):
{ "term": { "description": "quick brown fox" } }
// Правильно:
{ "match": { "description": "quick brown fox" } }
-
Для точных значений (ID, коды, категории):
GET products/_search
{
"query": {
"term": {
"product_code": "ABC-123"
}
}
}
-
Комбинируйте с другими запросами:
GET logs/_search
{
"query": {
"bool": {
"must": [
{ "term": { "status": "error" } },
{ "range": { "timestamp": { "gte": "2023-01-01" }}}
]
}
}
}
-
Производительность:
- Для частых запросов добавьте индекс на поле
- Избегайте
case_insensitive
в favor lowercase анализаторов
8 - terms
Поиск документов, содержащих один или несколько указанных терминов в заданном поле
Terms Query (Поиск по нескольким значениям)
Основное назначение
Запрос terms
позволяет искать документы, содержащие одно или несколько указанных значений в заданном поле. Документ возвращается в результатах, если значение его поля точно соответствует хотя бы одному термину из списка.
Базовый синтаксис
GET shakespeare/_search
{
"query": {
"terms": {
"line_id": [
"61809",
"61810"
]
}
}
}
Ключевые особенности
-
Лимит терминов:
По умолчанию максимальное количество терминов в запросе - 65,536. Настраивается через параметр index.max_terms_count
.
-
Производительность:
Для оптимизации производительности с длинными списками терминов рекомендуется:
- Передавать термины в отсортированном порядке (по возрастанию UTF-8 byte values)
- Использовать механизм Terms Lookup для больших наборов терминов
-
Подсветка результатов:
Возможность подсветки результатов зависит от:
- Типа highlighter’а
- Количества терминов в запросе
Параметры запроса
Параметр |
Тип данных |
Описание |
По умолчанию |
<field> |
String |
Поле для поиска (точное соответствие хотя бы одному термину) |
- |
boost |
Float |
Вес поля в расчете релевантности (>1 - увеличивает, 0-1 - уменьшает) |
1.0 |
_name |
String |
Имя запроса для тегирования |
- |
value_type |
String |
Тип значений для фильтрации (default или bitmap ) |
default |
Terms Lookup (Поиск терминов из другого документа)
Общие принципы
Механизм Terms Lookup позволяет:
- Извлекать значения полей из указанного документа
- Использовать эти значения как условия поиска
- Работать с большими наборами терминов
Требования:
- Поле
_source
должно быть включено (включено по умолчанию)
- Для уменьшения сетевого трафика рекомендуется использовать индекс с:
- Одним первичным шардом
- Полными репликами на всех узлах данных
Пример использования
- Создаем индекс студентов:
PUT students
{
"mappings": {
"properties": {
"student_id": { "type": "keyword" }
}
}
}
- Добавляем данные студентов:
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"
}
- Создаем индекс классов с информацией о зачисленных студентах:
PUT classes/_doc/101
{
"name": "CS101",
"enrolled" : ["111" , "222"]
}
- Поиск студентов, зачисленных на CS101:
GET students/_search
{
"query": {
"terms": {
"student_id": {
"index": "classes",
"id": "101",
"path": "enrolled"
}
}
}
}
- Результат содержит соответствующих студентов:
{
"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"
}
}
]
}
}
Работа с вложенными полями
- Добавляем документ с вложенной структурой:
PUT classes/_doc/102
{
"name": "CS102",
"enrolled_students" : {
"id_list" : ["111" , "333"]
}
}
- Поиск с указанием пути к вложенному полю:
GET students/_search
{
"query": {
"terms": {
"student_id": {
"index": "classes",
"id": "102",
"path": "enrolled_students.id_list"
}
}
}
}
- Результат поиска:
{
"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
Важные замечания
- Для полей типа
text
используйте match
вместо terms
- При работе с большими наборами терминов (>10,000) рассмотрите возможность использования Bitmap Filtering
- Убедитесь, что поле
_source
включено для документов-источников
Bitmap Filtering (Фильтрация с использованием битовых карт)
Введение
Начиная с версии 2.17, OpenSearch предлагает механизм bitmap filtering для эффективной фильтрации по большому количеству терминов (10,000+). Этот подход решает проблему высокой нагрузки на сеть и память при работе с обычными terms-запросами.
Основные концепции
-
Проблема:
Обычные terms-запросы становятся неэффективными при большом количестве терминов из-за:
- Высокого сетевого трафика
- Чрезмерного потребления памяти
-
Решение:
Использование 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 |
Преимущества подхода
-
Эффективность:
- Снижение сетевого трафика до 10 раз
- Уменьшение использования памяти на 50-90%
-
Гибкость:
- Поддержка динамического обновления фильтров
- Возможность комбинирования условий
-
Производительность:
- Быстрое выполнение даже для 100,000+ терминов
- Оптимизированные битовые операции на уровне ядра
Рекомендации
- Используйте для сложных фильтров с >10,000 значений
- Регулярно обновляйте bitmap при изменении данных
- Тестируйте производительность для вашего конкретного сценария
- Рассмотрите использование сжатых форматов 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 - уменьшает) |
Опционально |
Особенности работы
-
Механизм подсчета:
Документ считается соответствующим, если количество совпадающих терминов из массива terms
≥ указанного минимума.
-
Определение минимума:
- Через поле: значение берется из указанного поля документа
- Через скрипт: вычисляется динамически для каждого документа
-
Производительность:
- Использование поля
minimum_should_match_field
обычно более эффективно
- Скрипты обеспечивают гибкость, но могут снижать производительность
Рекомендации по использованию
- Для статических условий используйте
minimum_should_match_field
- Для сложной логики применяйте
minimum_should_match_script
- Всегда индексируйте поля, используемые для определения минимума
- Для текстовых полей предварительно применяйте нормализацию
- Тестируйте производительность на реалистичных объемах данных
Примеры скриптов
- Фиксированное значение:
"minimum_should_match_script": {
"source": "2"
}
- Динамическое вычисление:
"minimum_should_match_script": {
"source": "doc['min_required'].value * params.factor",
"params": {
"factor": 1.5
}
}
- Ограничение сверху:
"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 |
Критические особенности производительности
-
Предупреждение:
Wildcard-запросы могут быть медленными, так как требуют перебора множества терминов.
-
Золотое правило:
Избегайте размещения подстановочных символов в начале шаблона (например, *pattern
), так как это:
- Крайне ресурсоемко
- Может привести к таймаутам
- Создает нагрузку на кластер
-
Оптимизация:
Для частых wildcard-запросов используйте специальный wildcard
тип поля, который:
- Создает оптимизированный индекс
- Обеспечивает высокую производительность
- Поддерживает сложные шаблоны
Практические рекомендации
-
Для префиксного поиска используйте prefix
запрос вместо H*
:
{
"query": {
"prefix": {
"field": "H"
}
}
}
-
Для сложных шаблонов рассмотрите:
- Использование
wildcard
типа поля
- Применение
regexp
запросов для более сложных паттернов
-
При работе с большими индексами:
- Ограничивайте время выполнения через
timeout
- Используйте
search.allow_expensive_queries
для контроля
-
Пример безопасного шаблона:
{
"query": {
"wildcard": {
"product_code": {
"value": "ABC-202?-*",
"case_insensitive": true
}
}
}
}
Такой шаблон найдет коды типа “ABC-2023-XXX” и безопасен для выполнения.
Важные ограничения
- При
search.allow_expensive_queries=false
wildcard-запросы не выполняются
- Максимальная длина шаблона ограничена параметром
index.max_regex_length
(по умолчанию 1000 символов)
- Не поддерживает стандартные regex-конструкции (используйте
regexp
запрос для сложных выражений)