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

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

Специализированные запросы

OpenSearch поддерживает следующие специализированные запросы: distance_feature, more_like_this и др.
  • distance_feature: Вычисляет оценки документов на основе динамически рассчитанного расстояния между исходной точкой и полями даты, date_nanos или geo_point документа. Этот запрос может пропускать неконкурентные результаты.

  • more_like_this: Находит документы, похожие на предоставленный текст, документ или коллекцию документов.

  • knn: Используется для поиска сырых векторов во время векторного поиска.

  • neural: Используется для поиска по тексту или изображению в векторном поиске.

  • neural_sparse: Используется для поиска по векторным полям в разреженном нейронном поиске.

  • percolate: Находит запросы (сохраненные в виде документов), которые соответствуют предоставленному документу.

  • rank_feature: Вычисляет оценки на основе значений числовых признаков. Этот запрос может пропускать неконкурентные результаты.

  • script: Использует скрипт в качестве фильтра.

  • script_score: Вычисляет пользовательскую оценку для соответствующих документов с использованием скрипта.

  • wrapper: Принимает другие запросы в виде строк JSON или YAML.

1 - distance_feature

distance_feature для увеличения релевантности документов, которые ближе к определенной дате или географической точке.

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

Вы можете применять этот запрос к полям, содержащим данные о дате или местоположении. Он часто используется в условии should запроса bool для улучшения оценки релевантности без фильтрации результатов.

Настройка индекса

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

  • date
  • date_nanos
  • geo_point

В этом примере вы настроите поля opening_date и coordinates, которые можно использовать для выполнения запросов distance_feature:

PUT /stores
{
  "mappings": {
    "properties": {
      "opening_date": {
        "type": "date"
      },
      "coordinates": {
        "type": "geo_point"
      }
    }
  }
}

Добавьте пример документов в индекс:

PUT /stores/_doc/1
{
  "store_name": "Green Market",
  "opening_date": "2025-03-10",
  "coordinates": [74.00, 40.70]
}

PUT /stores/_doc/2
{
  "store_name": "Fresh Foods",
  "opening_date": "2025-04-01",
  "coordinates": [73.98, 40.75]
}

PUT /stores/_doc/3
{
  "store_name": "City Organics",
  "opening_date": "2021-04-20",
  "coordinates": [74.02, 40.68]
}

Пример: Увеличение оценок на основе свежести

Следующий запрос ищет документы с store_name, соответствующим слову “market”, и увеличивает оценки недавно открытых магазинов:

GET /stores/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "store_name": "market"
        }
      },
      "should": {
        "distance_feature": {
          "field": "opening_date",
          "origin": "2025-04-07",
          "pivot": "10d"
        }
      }
    }
  }
}

Ответ содержит соответствующий документ:

{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.2372394,
    "hits": [
      {
        "_index": "stores",
        "_id": "1",
        "_score": 1.2372394,
        "_source": {
          "store_name": "Green Market",
          "opening_date": "2025-03-10",
          "coordinates": [
            74,
            40.7
          ]
        }
      }
    ]
  }
}

Пример: Увеличение оценок на основе географической близости

Следующий запрос ищет документы с store_name, соответствующим слову “market”, и увеличивает результаты, находящиеся ближе к заданной исходной точке:

GET /stores/_search
{
  "query": {
    "bool": {
      "must": {
        "match": {
          "store_name": "market"
        }
      },
      "should": {
        "distance_feature": {
          "field": "coordinates",
          "origin": [74.00, 40.71],
          "pivot": "500m"
        }
      }
    }
  }
}

Ответ содержит соответствующий документ:

{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.2910118,
    "hits": [
      {
        "_index": "stores",
        "_id": "1",
        "_score": 1.2910118,
        "_source": {
          "store_name": "Green Market",
          "opening_date": "2025-03-10",
          "coordinates": [
            74,
            40.7
          ]
        }
      }
    ]
  }
}

Параметры

Следующая таблица перечисляет все параметры верхнего уровня, поддерживаемые запросами distance_feature.

Параметр Обязательный/Необязательный Описание
field Обязательный Имя поля, используемого для расчета расстояний. Должно быть полем типа date, date_nanos или geo_point с параметрами index: true (по умолчанию) и doc_values: true (по умолчанию).
origin Обязательный Точка отсчета, используемая для расчета расстояний. Используйте дату или математическое выражение даты (например, now-1h) для полей даты или геопункт для полей geo_point.
pivot Обязательный Расстояние от исходной точки, при котором оценки получают половину значения увеличения. Используйте единицу времени (например, 10d) для полей даты или единицу расстояния (например, 1km) для географических полей. Для получения дополнительной информации см. раздел “Единицы”.
boost Необязательный Множитель для оценки релевантности соответствующих документов. Должен быть неотрицательным числом с плавающей запятой. По умолчанию 1.0.

Как рассчитываются оценки

Запрос distance_feature вычисляет оценку релевантности документа, используя следующую формулу: [ \text{score} = \text{boost} \cdot \frac {\text{pivot}} {\text{pivot} + \text{distance}} ]

где distance — это абсолютная разница между origin и значением поля.

Пропуск неконкурентных результатов

В отличие от других запросов, модифицирующих оценки, таких как запрос function_score, запрос distance_feature оптимизирован для эффективного пропуска неконкурентных результатов, когда отслеживание общего количества результатов (track_total_hits) отключено. Это позволяет улучшить производительность запросов, особенно при работе с большими объемами данных, так как система может сосредоточиться только на наиболее релевантных результатах.

2 - k-NN

Используйте запрос k-NN для выполнения поиска ближайших соседей по векторным полям.

Поля тела запроса

Укажите векторное поле в запросе k-NN и задайте дополнительные поля запроса в объекте векторного поля:

"knn": {
  "<vector_field>": {
    "vector": [<vector_values>],
    "k": <k_value>,
    ...
  }
}

Верхний уровень vector_field указывает на векторное поле, по которому будет выполняться запрос поиска. Следующая таблица перечисляет все поддерживаемые поля запроса.

Поле Тип данных Обязательный/Необязательный Описание
vector Массив чисел с плавающей запятой или байтов Обязательный Вектор запроса, используемый для векторного поиска. Тип данных элементов вектора должен соответствовать типу данных векторов, индексированных в поле knn_vector.
k Целое число Необязательный Количество ближайших соседей для возврата. Допустимые значения находятся в диапазоне [1, 10,000]. Обязательно, если не указаны max_distance или min_score.
max_distance Число с плавающей запятой Необязательный Максимальный порог расстояния для результатов поиска. Можно указать только одно из k, max_distance или min_score. Для получения дополнительной информации см. раздел “Радиальный поиск”.
min_score Число с плавающей запятой Необязательный Минимальный порог оценки для результатов поиска. Можно указать только одно из k, max_distance или min_score. Для получения дополнительной информации см. раздел “Радиальный поиск”.
filter Объект Необязательный Фильтр, который применяется к поиску k-NN. Для получения дополнительной информации см. раздел “Векторный поиск с фильтрами”. Важно: фильтр можно использовать только с движками faiss или lucene.
method_parameters Объект Необязательный Дополнительные параметры для тонкой настройки поиска:
- ef_search (Целое число): количество векторов для проверки (для метода hnsw)
- nprobes (Целое число): количество корзин для проверки (для метода ivf). Для получения дополнительной информации см. раздел “Указание параметров метода в запросе”.
rescore Объект или логическое значение Необязательный Параметры для настройки функциональности повторной оценки:
- oversample_factor (Число с плавающей запятой): контролирует, сколько кандидатных векторов извлекается перед повторной оценкой. Допустимые значения находятся в диапазоне [1.0, 100.0]. По умолчанию false для полей с режимом in_memory (без повторной оценки) и включено (с динамическими значениями) для полей с режимом on_disk. В режиме on_disk значение по умолчанию для oversample_factor определяется уровнем сжатия. Для получения дополнительной информации см. таблицу уровня сжатия. Чтобы явно включить повторную оценку с значением по умолчанию для oversample_factor равным 1.0, установите rescore в true. Для получения дополнительной информации см. раздел “Повторная оценка результатов”.
expand_nested_docs Логическое значение Необязательный Если true, извлекает оценки для всех документов вложенных полей в каждом родительском документе. Используется с вложенными запросами. Для получения дополнительной информации см. раздел “Векторный поиск с вложенными полями”.

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

Запрос для выполнения поиска ближайших соседей:

GET /my-vector-index/_search
{
  "query": {
    "knn": {
      "my_vector": {
        "vector": [1.5, 2.5],
        "k": 3
      }
    }
  }
}

Пример запроса: Вложенные поля

Запрос для выполнения поиска ближайших соседей во вложенных полях:

GET /my-vector-index/_search
{
  "_source": false,
  "query": {
    "nested": {
      "path": "nested_field",
      "query": {
        "knn": {
          "nested_field.my_vector": {
            "vector": [1, 1, 1],
            "k": 2,
            "expand_nested_docs": true
          }
        }
      },
      "inner_hits": {
        "_source": false,
        "fields": ["nested_field.color"]
      },
      "score_mode": "max"
    }
  }
}

Пример запроса: Радиальный поиск с max_distance

Следующий пример демонстрирует радиальный поиск с использованием max_distance:

GET /my-vector-index/_search
{
    "query": {
        "knn": {
            "my_vector": {
                "vector": [
                    7.1,
                    8.3
                ],
                "max_distance": 2
            }
        }
    }
}

Пример запроса: Радиальный поиск с min_score

Следующий пример демонстрирует радиальный поиск с использованием min_score:

GET /my-vector-index/_search
{
  "query": {
    "knn": {
      "my_vector": {
        "vector": [7.1, 8.3],
        "min_score": 0.95
      }
    }
  }
}

Указание параметров метода в запросе

Начиная с версии 2.16, вы можете предоставлять параметры метода в запросе поиска:

GET /my-vector-index/_search
{
  "size": 2,
  "query": {
    "knn": {
      "target-field": {
        "vector": [2, 3, 5, 6],
        "k": 2,
        "method_parameters": {
          "ef_search": 100
        }
      }
    }
  }
}

Эти параметры зависят от комбинации движка и метода, использованных для создания индекса. Следующие разделы предоставляют информацию о поддерживаемых параметрах метода.

Вы можете указать параметр ef_search при поиске в индексе, созданном с использованием метода hnsw. Параметр ef_search указывает количество векторов, которые необходимо проверить для нахождения k ближайших соседей. Более высокие значения ef_search улучшают полноту поиска за счет увеличения задержки поиска. Значение должно быть положительным.

Следующая таблица предоставляет информацию о параметре ef_search для поддерживаемых движков.

Движок Поддержка радиального запроса Примечания
nmslib (устаревший) Нет Если ef_search присутствует в запросе, он переопределяет настройку index.knn.algo_param.ef_search индекса.
faiss Да Если ef_search присутствует в запросе, он переопределяет настройку index.knn.algo_param.ef_search индекса.
lucene Нет При создании поискового запроса необходимо указать k. Если вы укажете и k, и ef_search, то будет передано большее значение. Если ef_search больше k, вы можете указать параметр size, чтобы ограничить окончательное количество результатов до k.

nprobes

Вы можете указать параметр nprobes при поиске в индексе, созданном с использованием метода ivf. Параметр nprobes указывает количество корзин, которые необходимо проверить для нахождения k ближайших соседей. Более высокие значения nprobes улучшают полноту поиска за счет увеличения задержки поиска. Значение должно быть положительным.

Следующая таблица предоставляет информацию о параметре nprobes для поддерживаемых движков.

Движок Примечания
faiss Если nprobes присутствует в запросе, он переопределяет значение, указанное при создании индекса.

Повторная оценка результатов

Вы можете тонко настроить поиск, предоставив параметры ef_search и oversample_factor.

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

Следующий запрос указывает параметры ef_search и oversample_factor:

GET /my-vector-index/_search
{
  "size": 2,
  "query": {
    "knn": {
      "my_vector_field": {
        "vector": [1.5, 5.5, 1.5, 5.5, 1.5, 5.5, 1.5, 5.5],
        "k": 10,
        "method_parameters": {
            "ef_search": 10
        },
        "rescore": {
            "oversample_factor": 10.0
        }
      }
    }
  }
}

3 - k-NN explain

При включении этот параметр предоставляет подробную информацию о процессе оценки для каждого результата поиска.

Запрос k-NN: Параметр explain

С версии 3.0 вы можете использовать параметр explain, чтобы понять, как рассчитываются, нормализуются и комбинируются оценки в запросах k-NN. При включении этот параметр предоставляет подробную информацию о процессе оценки для каждого результата поиска. Это включает в себя раскрытие используемых техник нормализации оценок, способы комбинирования различных оценок и расчеты для индивидуальных подзапросов. Этот всесторонний анализ упрощает понимание и оптимизацию результатов ваших запросов k-NN. Для получения дополнительной информации о параметре explain смотрите раздел API объяснения.

Обратите внимание, что использование параметра explain является ресурсоемкой операцией как по времени, так и по ресурсам. Для производственных кластеров рекомендуется использовать его экономно, в основном для устранения неполадок.

Использование параметра explain

Вы можете указать параметр explain в URL при выполнении полного запроса k-NN для движка Faiss, используя следующий синтаксис:

GET <index>/_search?explain=true
POST <index>/_search?explain=true

Для поиска k-NN с использованием движка Lucene параметр explain не возвращает подробное объяснение, как это делает движок Faiss.

Поддерживаемые типы запросов с параметром explain для движка Faiss:

  • Приблизительный поиск k-NN
  • Приблизительный поиск k-NN с точным поиском
  • Поиск на диске
  • Поиск k-NN с эффективной фильтрацией
  • Радиальный поиск
  • Поиск k-NN с термовым запросом

Для поиска k-NN с вложенными полями параметр explain не возвращает подробное объяснение, как это происходит с другими запросами.

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

Вы можете указать параметр explain как параметр запроса:

GET my-knn-index/_search?explain=true
{
  "query": {
    "knn": {
      "my_vector": {
        "vector": [2, 3, 5, 7],
        "k": 2
      }
    }
  }
}

Или вы можете указать параметр explain в теле запроса:

GET my-knn-index/_search
{
  "query": {
    "knn": {
      "my_vector": {
        "vector": [2, 3, 5, 7],
        "k": 2
      }
    }
  },
  "explain": true
}

Пример: Приблизительный поиск k-NN

{
  "took": 216038,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 88.4,
    "hits": [
      {
        "_shard": "[my-knn-index-1][0]",
        "_node": "VHcyav6OTsmXdpsttX2Yug",
        "_index": "my-knn-index-1",
        "_id": "5",
        "_score": 88.4,
        "_source": {
          "my_vector1": [
            2.5,
            3.5,
            5.5,
            7.4
          ],
          "price": 8.9
        },
        "_explanation": {
          "value": 88.4,
          "description": "the type of knn search executed was Approximate-NN",
          "details": [
            {
              "value": 88.4,
              "description": "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = innerproduct where score is computed as `-rawScore + 1` from:",
              "details": [
                {
                  "value": -87.4,
                  "description": "rawScore, returned from FAISS library",
                  "details": []
                }
              ]
            }
          ]
        }
      },
      {
        "_shard": "[my-knn-index-1][0]",
        "_node": "VHcyav6OTsmXdpsttX2Yug",
        "_index": "my-knn-index-1",
        "_id": "2",
        "_score": 84.7,
        "_source": {
          "my_vector1": [
            2.5,
            3.5,
            5.6,
            6.7
          ],
          "price": 5.5
        },
        "_explanation": {
          "value": 84.7,
          "description": "the type of knn search executed was Approximate-NN",
          "details": [
            {
              "value": 84.7,
              "description": "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = innerproduct where score is computed as `-rawScore + 1` from:",
              "details": [
                {
                  "value": -83.7,
                  "description": "rawScore, returned from FAISS library",
                  "details": []
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Пример: Приблизительный поиск k-NN с точным поиском

{
  "took": 87,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 84.7,
    "hits": [
      {
        "_shard": "[my-knn-index-1][0]",
        "_node": "MQVux8dZRWeznuEYKhMq0Q",
        "_index": "my-knn-index-1",
        "_id": "7",
        "_score": 84.7,
        "_source": {
          "my_vector2": [
            2.5,
            3.5,
            5.6,
            6.7
          ],
          "price": 5.5
        },
        "_explanation": {
          "value": 84.7,
          "description": "the type of knn search executed was Approximate-NN",
          "details": [
            {
              "value": 84.7,
              "description": "the type of knn search executed at leaf was Exact with spaceType = INNER_PRODUCT, vectorDataType = FLOAT, queryVector = [2.0, 3.0, 5.0, 6.0]",
              "details": []
            }
          ]
        }
      },
      {
        "_shard": "[my-knn-index-1][0]",
        "_node": "MQVux8dZRWeznuEYKhMq0Q",
        "_index": "my-knn-index-1",
        "_id": "8",
        "_score": 82.2,
        "_source": {
          "my_vector2": [
            4.5,
            5.5,
            6.7,
            3.7
          ],
          "price": 4.4
        },
        "_explanation": {
          "value": 82.2,
          "description": "the type of knn search executed was Approximate-NN",
          "details": [
            {
              "value": 82.2,
              "description": "the type of knn search executed at leaf was Exact with spaceType = INNER_PRODUCT, vectorDataType = FLOAT, queryVector = [2.0, 3.0, 5.0, 6.0]",
              "details": []
            }
          ]
        }
      }
    ]
  }

Пример: Поиск на диске

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 381.0,
    "hits" : [
      {
        "_shard" : "[my-vector-index][0]",
        "_node" : "pLaiqZftTX-MVSKdQSu7ow",
        "_index" : "my-vector-index",
        "_id" : "9",
        "_score" : 381.0,
        "_source" : {
          "my_vector_field" : [
            9.5,
            9.5,
            9.5,
            9.5,
            9.5,
            9.5,
            9.5,
            9.5
          ],
          "price" : 8.9
        },
        "_explanation" : {
          "value" : 381.0,
          "description" : "the type of knn search executed was Disk-based and the first pass k was 100 with vector dimension of 8, over sampling factor of 5.0, shard level rescoring enabled",
          "details" : [
            {
              "value" : 381.0,
              "description" : "the type of knn search executed at leaf was Approximate-NN with spaceType = HAMMING, vectorDataType = FLOAT, queryVector = [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5]",
              "details" : [ ]
            }
          ]
        }
      }
    ]
  }
}

Пример: поиск k-NN с эффективной фильтрацией

{
  "took" : 51,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.8620689,
    "hits" : [
      {
        "_shard" : "[products-shirts][0]",
        "_node" : "9epk8WoFT8yvnUI0tAaJgQ",
        "_index" : "products-shirts",
        "_id" : "8",
        "_score" : 0.8620689,
        "_source" : {
          "item_vector" : [
            2.4,
            4.0,
            3.0
          ],
          "size" : "small",
          "rating" : 8
        },
        "_explanation" : {
          "value" : 0.8620689,
          "description" : "the type of knn search executed was Approximate-NN",
          "details" : [
            {
              "value" : 0.8620689,
              "description" : "the type of knn search executed at leaf was Exact since filteredIds = 2 is less than or equal to K = 10 with spaceType = L2, vectorDataType = FLOAT, queryVector = [2.0, 4.0, 3.0]",
              "details" : [ ]
            }
          ]
        }
      },
      {
        "_shard" : "[products-shirts][0]",
        "_node" : "9epk8WoFT8yvnUI0tAaJgQ",
        "_index" : "products-shirts",
        "_id" : "6",
        "_score" : 0.029691212,
        "_source" : {
          "item_vector" : [
            6.4,
            3.4,
            6.6
          ],
          "size" : "small",
          "rating" : 9
        },
        "_explanation" : {
          "value" : 0.029691212,
          "description" : "the type of knn search executed was Approximate-NN",
          "details" : [
            {
              "value" : 0.029691212,
              "description" : "the type of knn search executed at leaf was Exact since filteredIds = 2 is less than or equal to K = 10 with spaceType = L2, vectorDataType = FLOAT, queryVector = [2.0, 4.0, 3.0]",
              "details" : [ ]
            }
          ]
        }
      }
    ]
  }
}

Пример: Радиальный поиск

GET my-knn-index/_search?explain=true
{
  "query": {
    "knn": {
      "my_vector": {
      "vector": [7.1, 8.3],
      "max_distance": 2
      }
    }
  }
}

Ответ:

{
  "took" : 376529,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.98039204,
    "hits" : [
      {
        "_shard" : "[knn-index-test][0]",
        "_node" : "c9b4aPe4QGO8eOtb8P5D3g",
        "_index" : "knn-index-test",
        "_id" : "1",
        "_score" : 0.98039204,
        "_source" : {
          "my_vector" : [
            7.0,
            8.2
          ],
          "price" : 4.4
        },
        "_explanation" : {
          "value" : 0.98039204,
          "description" : "the type of knn search executed was Radial with the radius of 2.0",
          "details" : [
            {
              "value" : 0.98039204,
              "description" : "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = l2 where score is computed as `1 / (1 + rawScore)` from:",
              "details" : [
                {
                  "value" : 0.020000057,
                  "description" : "rawScore, returned from FAISS library",
                  "details" : [ ]
                }
              ]
            }
          ]
        }
      },
      {
        "_shard" : "[knn-index-test][0]",
        "_node" : "c9b4aPe4QGO8eOtb8P5D3g",
        "_index" : "knn-index-test",
        "_id" : "3",
        "_score" : 0.9615384,
        "_source" : {
          "my_vector" : [
            7.3,
            8.3
          ],
          "price" : 19.1
        },
        "_explanation" : {
          "value" : 0.9615384,
          "description" : "the type of knn search executed was Radial with the radius of 2.0",
          "details" : [
            {
              "value" : 0.9615384,
              "description" : "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = l2 where score is computed as `1 / (1 + rawScore)` from:",
              "details" : [
                {
                  "value" : 0.040000115,
                  "description" : "rawScore, returned from FAISS library",
                  "details" : [ ]
                }
              ]
            }
          ]
        }
      }
    ]
  }
}

Пример: поиск k-NN с запросом по термину

GET my-knn-index/_search?explain=true
{
  "query": {
    "bool": {
      "should": [
        {
          "knn": {
            "my_vector2": { // vector field name
              "vector": [2, 3, 5, 6],
              "k": 2
            }
          }
        },
      {
        "term": {
            "price": "4.4"
          }
        }
      ]
    }  
  }
}

Ответ:

{
  "took" : 51,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 84.7,
    "hits" : [
      {
        "_shard" : "[my-knn-index-1][0]",
        "_node" : "c9b4aPe4QGO8eOtb8P5D3g",
        "_index" : "my-knn-index-1",
        "_id" : "7",
        "_score" : 84.7,
        "_source" : {
          "my_vector2" : [
            2.5,
            3.5,
            5.6,
            6.7
          ],
          "price" : 5.5
        },
        "_explanation" : {
          "value" : 84.7,
          "description" : "sum of:",
          "details" : [
            {
              "value" : 84.7,
              "description" : "the type of knn search executed was Approximate-NN",
              "details" : [
                {
                  "value" : 84.7,
                  "description" : "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = innerproduct where score is computed as `-rawScore + 1` from:",
                  "details" : [
                    {
                      "value" : -83.7,
                      "description" : "rawScore, returned from FAISS library",
                      "details" : [ ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      },
      {
        "_shard" : "[my-knn-index-1][0]",
        "_node" : "c9b4aPe4QGO8eOtb8P5D3g",
        "_index" : "my-knn-index-1",
        "_id" : "8",
        "_score" : 83.2,
        "_source" : {
          "my_vector2" : [
            4.5,
            5.5,
            6.7,
            3.7
          ],
          "price" : 4.4
        },
        "_explanation" : {
          "value" : 83.2,
          "description" : "sum of:",
          "details" : [
            {
              "value" : 82.2,
              "description" : "the type of knn search executed was Approximate-NN",
              "details" : [
                {
                  "value" : 82.2,
                  "description" : "the type of knn search executed at leaf was Approximate-NN with vectorDataType = FLOAT, spaceType = innerproduct where score is computed as `-rawScore + 1` from:",
                  "details" : [
                    {
                      "value" : -81.2,
                      "description" : "rawScore, returned from FAISS library",
                      "details" : [ ]
                    }
                  ]
                }
              ]
            },
            {
              "value" : 1.0,
              "description" : "price:[1082969293 TO 1082969293]",
              "details" : [ ]
            }
          ]
        }
      }
    ]
  }
}

Поля ответа

Ответ содержит следующие поля:

  • explanation: Объект объяснения, который включает следующие поля:
    • value: Содержит результат расчета.
    • description: Объясняет, какой тип расчета был выполнен. Для нормализации оценок информация в поле описания включает используемую технику нормализации или комбинации и соответствующую оценку.
    • details: Показывает любые подрасчеты, выполненные в процессе.

4 - neural

Используйте запрос neural для поиска по векторным полям с помощью текста или изображения в векторном поиске.

Поля тела запроса

Включите следующие поля запроса в neural query:

"neural": {
  "<vector_field>": {
    "query_text": "<query_text>",
    "query_image": "<image_binary>",
    "model_id": "<model_id>",
    "k": 100
  }
}

Верхний уровень vector_field указывает на векторное или семантическое поле, по которому будет выполняться запрос поиска. Следующая таблица перечисляет другие поля запроса neural.

Поле Тип данных Обязательный/Необязательный Описание
query_text Строка Необязательный Текст запроса, из которого будут генерироваться векторные эмбеддинги. Необходимо указать хотя бы одно из полей query_text или query_image.
query_image Строка Необязательный Строка, закодированная в base-64, соответствующая изображению запроса, из которого будут генерироваться векторные эмбеддинги. Необходимо указать хотя бы одно из полей query_text или query_image.
model_id Строка Необязательный, если целевое поле является семантическим. Обязательно, если целевое поле является полем knn_vector и значение по умолчанию для модели не установлено. Идентификатор модели, которая будет использоваться для генерации векторных эмбеддингов из текста запроса. Модель должна быть развернута в OpenSearch перед использованием в нейронном поиске. Не может быть указана вместе с semantic_field_search_analyzer.
k Целое число Необязательный Количество результатов, возвращаемых при поиске k-NN. Можно указать только одну переменную: k, min_score или max_distance. Если переменная не указана, по умолчанию используется k со значением 10.
min_score Число с плавающей запятой Необязательный Минимальный порог оценки для результатов поиска. Можно указать только одну переменную: k, min_score или max_distance. Для получения дополнительной информации см. раздел “Радиальный поиск”.
max_distance Число с плавающей запятой Необязательный Максимальный порог расстояния для результатов поиска. Можно указать только одну переменную: k, min_score или max_distance. Для получения дополнительной информации см. раздел “Радиальный поиск”.
filter Объект Необязательный Запрос, который можно использовать для уменьшения количества рассматриваемых документов. Для получения дополнительной информации о использовании фильтров см. раздел “Векторный поиск с фильтрами”.
method_parameters Объект Необязательный Дополнительные параметры для тонкой настройки поиска:
- ef_search (Целое число): количество векторов для проверки (для метода hnsw)
- nprobes (Целое число): количество корзин для проверки (для метода ivf). Для получения дополнительной информации см. раздел “Указание параметров метода в запросе”.
rescore Объект или логическое значение Необязательный Параметры для настройки функциональности повторной оценки:
- oversample_factor (Число с плавающей запятой): контролирует, сколько кандидатных векторов извлекается перед повторной оценкой. Допустимые значения находятся в диапазоне [1.0, 100.0]. По умолчанию false для полей с режимом in_memory (без повторной оценки) и включено (с динамическими значениями) для полей с режимом on_disk. В режиме on_disk значение по умолчанию для oversample_factor определяется уровнем сжатия. Для получения дополнительной информации см. таблицу уровня сжатия. Чтобы явно включить повторную оценку с значением по умолчанию для oversample_factor равным 1.0, установите rescore в true. Для получения дополнительной информации см. раздел “Повторная оценка результатов”.
expand_nested_docs Логическое Необязательное Если установлено в true, извлекает оценки для всех документов вложенных полей в каждом родительском документе. Используется с вложенными запросами.
semantic_field_search_analyzer Строка Необязательное Указывает анализатор для токенизации query_text при использовании модели разреженного кодирования. Допустимые значения: standard, bert-uncased и mbert-uncased. Не может использоваться вместе с model_id.
query_tokens Карта токенов (строка) к весу (число с плавающей точкой) Необязательное Сырой разреженный вектор в виде токенов и их весов. Используется в качестве альтернативы query_text для прямого ввода вектора. Необходимо указать либо query_text, либо query_tokens.

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

Следующий пример демонстрирует поиск с значением k равным 100 и фильтром, который включает диапазонный запрос и терминальный запрос:

GET /my-nlp-index/_search
{
  "query": {
    "neural": {
      "passage_embedding": {
        "query_text": "Hi world",
        "query_image": "iVBORw0KGgoAAAAN...",
        "k": 100,
        "filter": {
          "bool": {
            "must": [
              {
                "range": {
                  "rating": {
                    "gte": 8,
                    "lte": 10
                  }
                }
              },
              {
                "term": {
                  "parking": "true"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Следующий запрос поиска включает минимальный порог оценки min_score для k-NN радиального поиска, равный 0.95, и фильтр, который включает диапазонный запрос и терминальный запрос:

GET /my-nlp-index/_search
{
  "query": {
    "neural": {
      "passage_embedding": {
        "query_text": "Hi world",
        "query_image": "iVBORw0KGgoAAAAN...",
        "min_score": 0.95,
        "filter": {
          "bool": {
            "must": [
              {
                "range": {
                  "rating": {
                    "gte": 8,
                    "lte": 10
                  }
                }
              },
              {
                "term": {
                  "parking": "true"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Следующий запрос поиска включает максимальное расстояние max_distance, равное 10, и фильтр, который включает диапазонный запрос и терминальный запрос:

GET /my-nlp-index/_search
{
  "query": {
    "neural": {
      "passage_embedding": {
        "query_text": "Hi world",
        "query_image": "iVBORw0KGgoAAAAN...",
        "max_distance": 10,
        "filter": {
          "bool": {
            "must": [
              {
                "range": {
                  "rating": {
                    "gte": 8,
                    "lte": 10
                  }
                }
              },
              {
                "term": {
                  "parking": "true"
                }
              }
            ]
          }
        }
      }
    }
  }
}

Следующий пример демонстрирует поиск по семантическому полю с использованием плотной модели. Семантическое поле хранит информацию о модели в своей конфигурации. Нейронный запрос автоматически извлекает model_id из конфигурации семантического поля в индексе и переписывает запрос для нацеливания на соответствующее поле эмбеддинга:

GET /my-nlp-index/_search
{
  "query": {
    "neural": {
      "passage": {
        "query_text": "Hi world",
        "k": 100
      }
    }
  }
}

Следующий пример демонстрирует поиск по семантическому полю с использованием модели разреженного кодирования. Этот поиск использует разреженные эмбеддинги:

GET /my-nlp-index/_search
{
  "query": {
    "neural": {
      "passage": {
        "query_tokens": {
          "worlds": 0.57605183
        }
      }
    }
  }
}

Для получения дополнительной информации смотрите тип семантического поля.

5 - Нейронный разреженный запрос

Используйте нейронный разреженный запрос для поиска по векторному полю в нейронном разреженном поиске.

Вы можете выполнить запрос следующими способами:

  1. Предоставьте разреженные векторные эмбеддинги для сопоставления. Для получения дополнительной информации смотрите раздел “Нейронный разреженный поиск с использованием сырых векторов”:
"neural_sparse": {
  "<vector_field>": {
    "query_tokens": {
      "<token>": <weight>,
      ...
    }
  }
}
  1. Предоставьте текст для токенизации и использования для сопоставления. Для токенизации текста вы можете использовать следующие компоненты:
    • Встроенный анализатор DL модели:
"neural_sparse": {
  "<vector_field>": {
    "query_text": "<input text>",
    "analyzer": "bert-uncased"
  }
}
  • Модель токенизатора:
"neural_sparse": {
  "<vector_field>": {
    "query_text": "<input text>",
    "model_id": "<model ID>"
  }
}

Для получения дополнительной информации смотрите раздел “Автоматическая генерация разреженных векторных эмбеддингов”.

Поля тела запроса

Верхний уровень vector_field указывает на векторное поле, по которому будет выполняться запрос поиска. Необходимо указать либо query_text, либо query_tokens для определения входных данных. Следующие поля могут быть использованы для настройки запроса:

Поле Тип данных Обязательное/Необязательное Описание
query_text Строка Необязательное Текст запроса, который будет преобразован в разреженные векторные эмбеддинги. Необходимо указать либо query_text, либо query_tokens.
analyzer Строка Необязательное Используется с query_text. Указывает встроенный анализатор DL модели для токенизации текста запроса. Допустимые значения: bert-uncased и mbert-uncased. По умолчанию используется bert-uncased. Не может использоваться одновременно с model_id.
model_id Строка Необязательное Используется с query_text. Идентификатор модели разреженного кодирования (для режима би-кодировщика) или токенизатора (для режима только документа), используемый для генерации векторных эмбеддингов из текста запроса. Модель/токенизатор должна быть развернута в OpenSearch перед использованием в нейронном разреженном поиске. Не может использоваться одновременно с analyzer.
query_tokens Карта токенов (строка) к весу (число с плавающей точкой) Необязательное Сырой разреженный вектор в виде токенов и их весов. Используется в качестве альтернативы query_text для прямого ввода вектора. Необходимо указать либо query_text, либо query_tokens.
max_token_score Число с плавающей точкой Необязательное (устарело) Этот параметр устарел с версии OpenSearch 2.12. Он поддерживается только для обратной совместимости и больше не влияет на функциональность. Параметр все еще может быть указан в запросах, но его значение не имеет значения. Ранее использовался как теоретическая верхняя граница оценки для всех токенов в словаре.

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

Поиск с использованием текста, токенизированного анализатором

Чтобы выполнить поиск, используя текст, токенизированный анализатором, укажите анализатор в запросе. Анализатор должен быть совместим с моделью, которую вы использовали для анализа текста во время загрузки:

GET my-nlp-index/_search
{
  "query": {
    "neural_sparse": {
      "passage_embedding": {
        "query_text": "Hi world",
        "analyzer": "bert-uncased"
      }
    }
  }
}

Для получения дополнительной информации смотрите раздел “Анализаторы DL модели”.

Поиск с использованием текста без указания анализатора

Если вы не укажете анализатор, будет использован анализатор по умолчанию bert-uncased:

GET my-nlp-index/_search
{
  "query": {
    "neural_sparse": {
      "passage_embedding": {
        "query_text": "Hi world"
      }
    }
  }
}

Поиск с использованием текста, токенизированного моделью токенизатора

Чтобы выполнить поиск, используя текст, токенизированный моделью токенизатора, укажите идентификатор модели в запросе:

GET my-nlp-index/_search
{
  "query": {
    "neural_sparse": {
      "passage_embedding": {
        "query_text": "Hi world",
        "model_id": "aP2Q8ooBpBj3wT4HVS8a"
      }
    }
  }
}

Поиск с использованием разреженного вектора

Чтобы выполнить поиск, используя разреженный вектор, укажите разреженный вектор в параметре query_tokens:

GET my-nlp-index/_search
{
  "query": {
    "neural_sparse": {
      "passage_embedding": {
        "query_tokens": {
          "hi": 4.338913,
          "planets": 2.7755864,
          "planet": 5.0969057,
          "mars": 1.7405145,
          "earth": 2.6087382,
          "hello": 3.3210192
        }
      }
    }
  }
}

6 - Перколяция

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

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

Основные моменты

  • Вы можете перколировать документ, предоставленный в строке, или извлечь существующий документ из индекса.
  • Документ и сохраненные запросы должны использовать одни и те же имена и типы полей.
  • Вы можете комбинировать перколяцию с фильтрацией и оценкой, чтобы создать сложные системы соответствия.
  • Запросы перколяции считаются дорогими запросами и будут выполняться только если настройка кластера search.allow_expensive_queries установлена в true (по умолчанию). Если эта настройка установлена в false, запросы перколяции будут отклонены.

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

Запросы перколяции полезны в различных сценариях реального времени. Некоторые распространенные случаи использования включают:

  • Уведомления для электронной коммерции: Пользователи могут зарегистрировать интерес к продуктам, например, “Уведомите меня, когда новые ноутбуки Apple будут в наличии”. Когда новые документы о продуктах индексируются, система находит всех пользователей с соответствующими сохраненными запросами и отправляет уведомления.

  • Уведомления о вакансиях: Соискатели сохраняют запросы на основе предпочтительных должностей или местоположений, и новые вакансии сопоставляются с этими запросами для триггера уведомлений.

  • Системы безопасности и оповещения: Перколируйте входящие данные журналов или событий по сохраненным правилам или паттернам аномалий.

  • Фильтрация новостей: Сопоставляйте входящие статьи с сохраненными профилями тем, чтобы классифицировать или доставлять релевантный контент.

Как работает перколяция

Сохраненные запросы хранятся в специальном типе поля перколятора. Документы сравниваются со всеми сохраненными запросами. Каждый соответствующий запрос возвращается с его _id. Если включено выделение, также возвращаются совпадающие текстовые фрагменты. Если отправляется несколько документов, поле _percolator_document_slot отображает соответствующий документ.

Пример запроса перколяции

{
  "query": {
    "percolate": {
      "field": "query",
      "document": {
        "title": "Новый ноутбук Apple",
        "price": 1500,
        "availability": "в наличии"
      }
    }
  }
}

В этом примере запрос перколяции ищет сохраненные запросы, которые соответствуют документу о новом ноутбуке Apple.

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

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

Создание индекса для хранения сохраненных запросов

Сначала создайте индекс и настройте его маппинги с типом поля перколятора для хранения сохраненных запросов:

PUT /my_percolator_index
{
  "mappings": {
    "properties": {
      "query": {
        "type": "percolator"
      },
      "title": {
        "type": "text"
      }
    }
  }
}

Добавление запроса, соответствующего “apple” в поле title

Добавьте запрос, который соответствует слову “apple” в поле заголовка:

POST /my_percolator_index/_doc/1
{
  "query": {
    "match": {
      "title": "apple"
    }
  }
}

Добавление запроса, соответствующего “banana” в поле title

Добавьте запрос, который соответствует слову “banana” в поле заголовка:

POST /my_percolator_index/_doc/2
{
  "query": {
    "match": {
      "title": "banana"
    }
  }
}

Перколяция встроенного документа

Проверьте встроенный документ против сохраненных запросов:

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "document": {
        "title": "Fresh Apple Harvest"
      }
    }
  }
}

Ответ

Ответ предоставляет сохраненный запрос перколяции, который ищет документы, содержащие слово “apple” в поле заголовка, идентифицированный по _id: 1:

{
  ...
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.13076457,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.13076457,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0
          ]
        }
      }
    ]
  }
}

Перколяция с несколькими документами

Чтобы протестировать несколько документов в одном запросе, используйте следующий запрос:

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "documents": [
        { "title": "Banana flavoured ice-cream" },
        { "title": "Apple pie recipe" },
        { "title": "Banana bread instructions" },
        { "title": "Cherry tart" }
      ]
    }
  }
}

Ответ

Поле _percolator_document_slot помогает вам идентифицировать каждый документ (по индексу), соответствующий каждому сохраненному запросу:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.54726034,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.54726034,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            1
          ]
        }
      },
      {
        "_index": "my_percolator_index",
        "_id": "2",
        "_score": 0.31506687,
        "_source": {
          "query": {
            "match": {
              "title": "banana"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0,
            2
          ]
        }
      }
    ]
  }
}

Перколяция существующего индексированного документа

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

Создание отдельного индекса для ваших документов

Создайте индекс для хранения документов:

PUT /products
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      }
    }
  }
}

Добавление документа

Добавьте документ:

POST /products/_doc/1
{
  "title": "Banana Smoothie Special"
}

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

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

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "index": "products",
      "id": "1"
    }
  }
}

Вы должны предоставить как индекс, так и идентификатор при использовании сохраненного документа.

Перколяция пакетов (несколько документов)

Вы можете проверить несколько документов в одном запросе:

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "documents": [
        { "title": "Apple event coming soon" },
        { "title": "Banana farms expand" },
        { "title": "Cherry season starts" }
      ]
    }
  }
}

Ответ

Каждое совпадение указывает на соответствующий документ в поле _percolator_document_slot:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.46484798,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "2",
        "_score": 0.46484798,
        "_source": {
          "query": {
            "match": {
              "title": "banana"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            1
          ]
        }
      },
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.41211313,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0
          ]
        }
      }
    ]
  }
}

Многоуровневая перколяция с использованием именованного запроса

Вы можете перколировать разные документы внутри именованного запроса:

GET /my_percolator_index/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "percolate": {
            "field": "query",
            "document": {
              "title": "Apple pie recipe"
            },
            "name": "apple_doc"
          }
        },
        {
          "percolate": {
            "field": "query",
            "document": {
              "title": "Banana bread instructions"
            },
            "name": "banana_doc"
          }
        }
      ]
    }
  }
}

Ответ

Параметр name добавляется к полю _percolator_document_slot, чтобы предоставить соответствующий запрос:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.13076457,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.13076457,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot_apple_doc": [
            0
          ]
        }
      },
      {
        "_index": "my_percolator_index",
        "_id": "2",
        "_score": 0.13076457,
        "_source": {
          "query": {
            "match": {
              "title": "banana"
            }
          }
        },
        "fields": {
          "_percolator_document_slot_banana_doc": [
            0
          ]
        }
      }
    ]
  }
}

Этот подход позволяет вам настраивать более индивидуальную логику запросов для отдельных документов. В следующем примере поле title запрашивается в первом документе, а поле description запрашивается во втором документе. Также предоставляется параметр boost:

GET /my_percolator_index/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "constant_score": {
            "filter": {
              "percolate": {
                "field": "query",
                "document": {
                  "title": "Apple pie recipe"
                },
                "name": "apple_doc"
              }
            },
            "boost": 1.0
          }
        },
        {
          "constant_score": {
            "filter": {
              "percolate": {
                "field": "query",
                "document": {
                  "description": "Banana bread with honey"
                },
                "name": "banana_doc"
              }
            },
            "boost": 3.0
          }
        }
      ]
    }
  }
}

Сравнение пакетной перколяции и именованной перколяции

Обе методы — пакетная перколяция (с использованием документов) и именованная перколяция (с использованием bool и name) — могут использоваться для перколяции нескольких документов, но они различаются по тому, как результаты маркируются, интерпретируются и контролируются. Они предоставляют функционально схожие результаты, но с важными структурными различиями, описанными в следующей таблице.

Характеристика Пакетная (документы) Именованная (bool + percolate + name)
Формат ввода Один клауз перколяции, массив документов Несколько клауз перколяции, по одному на документ
Прослеживаемость по документу По индексу слота (0, 1, …) По имени (apple_doc, banana_doc)
Поле ответа для слота совпадения _percolator_document_slot: [0] _percolator_document_slot_<name>: [0]
Префикс выделения 0_title, 1_title apple_doc_title, banana_doc_title
Индивидуальный контроль по документу Не поддерживается Можно настроить каждую клаузу
Поддержка увеличений и фильтров Нет Да (по каждой клаузе)
Производительность Лучше для больших партий Немного медленнее при большом количестве клауз
Случай использования Массовое соответствие, большие потоки событий Прослеживание по документам, тестирование, индивидуальный контроль

Подсветка совпадений

Запросы перколяции обрабатывают подсветку иначе, чем обычные запросы:

  • В обычном запросе документ хранится в индексе, и поисковый запрос используется для подсветки совпадающих терминов.
  • В запросе перколяции роли меняются: сохраненные запросы (в индексе перколятора) используются для подсветки документа.

Это означает, что документ, предоставленный в поле document или documents, является целью для подсветки, и запросы перколяции определяют, какие разделы будут подсвечены.

Подсветка одного документа

Этот пример использует ранее определенные запросы в my_percolator_index. Используйте следующий запрос для подсветки совпадений в поле заголовка:

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "document": {
        "title": "Apple banana smoothie"
      }
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}

Ответ

Совпадения подсвечиваются в зависимости от соответствующего запроса:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.13076457,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.13076457,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0
          ]
        },
        "highlight": {
          "title": [
            "<em>Apple</em> banana smoothie"
          ]
        }
      },
      {
        "_index": "my_percolator_index",
        "_id": "2",
        "_score": 0.13076457,
        "_source": {
          "query": {
            "match": {
              "title": "banana"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0
          ]
        },
        "highlight": {
          "title": [
            "Apple <em>banana</em> smoothie"
          ]
        }
      }
    ]
  }
}

Подсветка нескольких документов

При перколяции нескольких документов с использованием массива documents каждому документу присваивается индекс слота. Ключи подсветки принимают следующую форму, где <slot> — это индекс документа в вашем массиве documents:

"<slot>_<fieldname>": [ ... ]

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

POST /my_percolator_index/_search
{
  "query": {
    "percolate": {
      "field": "query",
      "documents": [
        { "title": "Apple pie recipe" },
        { "title": "Banana smoothie ideas" }
      ]
    }
  },
  "highlight": {
    "fields": {
      "title": {}
    }
  }
}

Ответ

Ответ содержит поля подсветки с префиксами, соответствующими слотам документов, такими как 0_title и 1_title:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.31506687,
    "hits": [
      {
        "_index": "my_percolator_index",
        "_id": "1",
        "_score": 0.31506687,
        "_source": {
          "query": {
            "match": {
              "title": "apple"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            0
          ]
        },
        "highlight": {
          "0_title": [
            "<em>Apple</em> pie recipe"
          ]
        }
      },
      {
        "_index": "my_percolator_index",
        "_id": "2",
        "_score": 0.31506687,
        "_source": {
          "query": {
            "match": {
              "title": "banana"
            }
          }
        },
        "fields": {
          "_percolator_document_slot": [
            1
          ]
        },
        "highlight": {
          "1_title": [
            "<em>Banana</em> smoothie ideas"
          ]
	   }
      }
    ]
  }
}

Параметры запроса перколяции

Запрос перколяции поддерживает следующие параметры:

Параметр Обязательный/Необязательный Описание
field Обязательный Поле, содержащее сохраненные запросы перколяции.
document Необязательный Один встроенный документ для сопоставления с сохраненными запросами.
documents Необязательный Массив нескольких встроенных документов для сопоставления с сохраненными запросами.
index Необязательный Индекс, содержащий документ, с которым вы хотите сопоставить.
id Необязательный Идентификатор документа для извлечения из индекса.
routing Необязательный Значение маршрутизации, используемое при извлечении документа.
preference Необязательный Предпочтение для маршрутизации шардов при извлечении документа.
name Необязательный Имя, присвоенное клаузе перколяции. Полезно при использовании нескольких клауз перколяции в запросе bool.

7 - script query

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

Используйте запрос скрипта для фильтрации документов на основе пользовательского условия, написанного на языке скриптов Painless. Этот запрос возвращает документы, для которых скрипт оценивается как истинный, что позволяет использовать сложную логику фильтрации, которую нельзя выразить с помощью стандартных запросов.

Запрос скрипта является вычислительно затратным и должен использоваться с осторожностью. Используйте его только при необходимости и убедитесь, что параметр search.allow_expensive_queries включен (по умолчанию установлен в true). Для получения дополнительной информации смотрите раздел “Дорогие запросы”.

Пример

Создайте индекс с именем products со следующими настройками:

PUT /products
{
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "price": { "type": "float" },
      "rating": { "type": "float" }
    }
  }
}

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

POST /products/_bulk
{ "index": { "_id": 1 } }
{ "title": "Беспроводные наушники", "price": 99.99, "rating": 4.5 }
{ "index": { "_id": 2 } }
{ "title": "Bluetooth колонка", "price": 79.99, "rating": 4.8 }
{ "index": { "_id": 3 } }
{ "title": "Наушники с шумоподавлением", "price": 199.99, "rating": 4.7 }

Базовый запрос скрипта

Верните продукты с рейтингом выше 4.6:

POST /products/_search
{
  "query": {
    "script": {
      "script": {
        "source": "doc['rating'].value > 4.6"
      }
    }
  }
}

Возвращенные результаты будут включать только документы с рейтингом выше 4.6:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "products",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "Bluetooth колонка",
          "price": 79.99,
          "rating": 4.8
        }
      },
      {
        "_index": "products",
        "_id": "3",
        "_score": 1,
        "_source": {
          "title": "Наушники с шумоподавлением",
          "price": 199.99,
          "rating": 4.7
        }
      }
    ]
  }
}

Параметры

Запрос скрипта принимает следующие параметры верхнего уровня.

Параметр Обязательный/Необязательный Описание
script.source Обязательный Код скрипта, который оценивается как истинный или ложный.
script.params Необязательный Пользовательские параметры, на которые ссылается скрипт.

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

Вы можете использовать params для безопасной передачи значений, используя кэширование компиляции скриптов:

POST /products/_search
{
  "query": {
    "script": {
      "script": {
        "source": "doc['price'].value < params.max_price",
        "params": {
          "max_price": 100
        }
      }
    }
  }
}

Возвращенные результаты будут включать только документы с ценой менее 100:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 1,
        "_source": {
          "title": "Беспроводные наушники",
          "price": 99.99,
          "rating": 4.5
        }
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "Bluetooth колонка",
          "price": 79.99,
          "rating": 4.8
        }
      }
    ]
  }
}

Объединение нескольких условий

Используйте следующий запрос для поиска продуктов с рейтингом выше 4.5 и ценой ниже 100:

POST /products/_search
{
  "query": {
    "script": {
      "script": {
        "source": "doc['rating'].value > 4.5 && doc['price'].value < 100"
      }
    }
  }
}

Только документы, соответствующие требованиям, будут возвращены:

{
  "took": 12,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "products",
        "_id": "2",
        "_score": 1,
        "_source": {
          "title": "Bluetooth колонка",
          "price": 79.99,
          "rating": 4.8
        }
      }
    ]
  }
}

8 - Запрос с оценкой скрипта

Используйте запрос script_score, чтобы настроить расчет оценки, используя скрипт.

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

Пример

Например, следующий запрос создает индекс, содержащий один документ:

PUT testindex1/_doc/1
{
  "name": "John Doe",
  "multiplier": 0.5
}

Вы можете использовать запрос match, чтобы вернуть все документы, содержащие “John” в поле имени:

GET testindex1/_search
{
  "query": {
    "match": {
      "name": "John"
    }
  }
}

В ответе документ 1 имеет оценку 0.2876821:

{
  "took": 7,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "testindex1",
        "_id": "1",
        "_score": 0.2876821,
        "_source": {
          "name": "John Doe",
          "multiplier": 0.5
        }
      }
    ]
  }
}

Теперь давайте изменим оценку документа, используя скрипт, который вычисляет оценку как значение поля _score, умноженное на значение поля multiplier. В следующем запросе вы можете получить текущую релевантность документа в переменной _score, а значение множителя как doc['multiplier'].value:

GET testindex1/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": { 
            "name": "John" 
        }
      },
      "script": {
        "source": "_score * doc['multiplier'].value"
      }
    }
  }
}

В ответе оценка для документа 1 составляет половину от первоначальной оценки:

{
  "took": 8,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.14384104,
    "hits": [
      {
        "_index": "testindex1",
        "_id": "1",
        "_score": 0.14384104,
        "_source": {
          "name": "John Doe",
          "multiplier": 0.5
        }
      }
    ]
  }
}

Параметры

Запрос script_score поддерживает следующие параметры верхнего уровня.

Параметр Тип данных Описание
query Объект Запрос, используемый для поиска. Обязательный.
script Объект Скрипт, используемый для вычисления оценки документов, возвращаемых запросом. Обязательный.
min_score Число с плавающей запятой Исключает документы с оценкой ниже min_score из результатов. Необязательный.
boost Число с плавающей запятой Увеличивает оценки документов на заданный множитель. Значения меньше 1.0 уменьшают релевантность, а значения больше 1.0 увеличивают релевантность. По умолчанию 1.0.

Оценки релевантности, вычисленные запросом script_score, не могут быть отрицательными.

Настройка вычисления оценки с помощью встроенных функций

Чтобы настроить вычисление оценки, вы можете использовать одну из встроенных функций Painless. Для каждой функции OpenSearch предоставляет один или несколько методов Painless, которые вы можете использовать в контексте оценки скрипта. Вы можете вызывать методы Painless, перечисленные в следующих разделах, напрямую, без использования имени класса или имени экземпляра.

Сатурация

Функция сатурации вычисляет сатурацию как score = value / (value + pivot), где value — это значение поля, а pivot выбирается так, чтобы оценка была больше 0.5, если value больше pivot, и меньше 0.5, если value меньше pivot. Оценка находится в диапазоне (0, 1). Чтобы применить функцию сатурации, вызовите следующий метод Painless:

double saturation(double <field-value>, double <pivot>)

ПРИМЕР

Следующий пример запроса ищет текст “neural search” в индексе статей. Он комбинирует оригинальную оценку релевантности документа с значением article_rank, которое сначала преобразуется с помощью функции сатурации:

GET articles/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": { "article_name": "neural search" }
      },
      "script": {
        "source": "_score + saturation(doc['article_rank'].value, 11)"
      }
    }
  }
}

Сигмоид

Аналогично функции сатурации, функция сигмоид вычисляет оценку как score = value^exp / (value^exp + pivot^exp), где value — это значение поля, exp — это коэффициент масштабирования степени, а pivot выбирается так, чтобы оценка была больше 0.5, если value больше pivot, и меньше 0.5, если value меньше pivot. Чтобы применить функцию сигмоид, вызовите следующий метод Painless:

double sigmoid(double <field-value>, double <pivot>, double <exp>)

Пример

Следующий пример запроса ищет текст “neural search” в индексе статей. Он комбинирует оригинальную оценку релевантности документа со значением article_rank, которое сначала преобразуется с помощью функции сигмоид:

GET articles/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": { "article_name": "neural search" }
      },
      "script": {
        "source": "_score + sigmoid(doc['article_rank'].value, 11, 2)"
      }
    }
  }
}

Случайная оценка

Функция случайной оценки генерирует равномерно распределенные случайные оценки в диапазоне [0, 1). Чтобы узнать, как работает эта функция, смотрите раздел “Функция случайной оценки”. Чтобы применить функцию случайной оценки, вызовите один из следующих методов Painless:

double randomScore(int <seed>): Использует внутренние идентификаторы документов Lucene в качестве значений семени.
double randomScore(int <seed>, String <field-name>)

Пример

Следующий запрос использует функцию random_score с семенем и полем:

GET articles/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": { "article_name": "neural search" }
      },
      "script": {
        "source": "randomScore(20, '_seq_no')"
      }
    }
  }
}

Функции затухания

С помощью функций затухания вы можете оценивать результаты на основе близости или недавности. Чтобы узнать больше, смотрите раздел “Функции затухания”. Вы можете вычислять оценки, используя экспоненциальную, гауссову или линейную кривую затухания. Чтобы применить функцию затухания, вызовите один из следующих методов Painless в зависимости от типа поля:

Числовые поля:

double decayNumericGauss(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)
double decayNumericExp(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)
double decayNumericLinear(double <origin>, double <scale>, double <offset>, double <decay>, double <field-value>)

Геопоинтовые поля:

double decayGeoGauss(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)
double decayGeoExp(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)
double decayGeoLinear(String <origin>, String <scale>, String <offset>, double <decay>, GeoPoint <field-value>)

Поля даты:

double decayDateGauss(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)
double decayDateExp(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)
double decayDateLinear(String <origin>, String <scale>, String <offset>, double <decay>, JodaCompatibleZonedDateTime <field-value>)

Пример: Числовые поля

Следующий запрос использует функцию экспоненциального затухания на числовом поле:

GET articles/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": {
          "article_name": "neural search"
        }
      },
      "script": {
        "source": "decayNumericExp(params.origin, params.scale, params.offset, params.decay, doc['article_rank'].value)",
        "params": {
          "origin": 50,
          "scale": 20,
          "offset": 30,
          "decay": 0.5
        }
      }
    }
  }
}
Пример: Геопоинтовые поля

Следующий запрос использует функцию гауссового затухания на геопоинтовом поле:

GET hotels/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": {
          "name": "hotel"
        }
      },
      "script": {
        "source": "decayGeoGauss(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
        "params": {
          "origin": "40.71,74.00",
          "scale":  "300ft",
          "offset": "200ft",
          "decay": 0.25
        }
      }
    }
  }
}

Пример: Поля даты

Следующий запрос использует функцию линейного затухания на поле даты:

GET blogs/_search
{
  "query": {
    "script_score": {
      "query": {
        "match": {
          "name": "opensearch"
        }
      },
      "script": {
        "source": "decayDateLinear(params.origin, params.scale, params.offset, params.decay, doc['date_posted'].value)",
        "params": {
          "origin":  "2022-04-24",
          "scale":  "6d",
          "offset": "1d",
          "decay": 0.25
        }
      }
    }
  }
}

Функции частоты термина

Функции частоты термина предоставляют статистику на уровне термина в источнике скрипта оценки. Вы можете использовать эту статистику для реализации пользовательских алгоритмов извлечения информации и ранжирования, таких как умножение или сложение оценки по популярности во время запроса. Чтобы применить функцию частоты термина, вызовите один из следующих методов Painless:

  • int termFreq(String <field-name>, String <term>): Извлекает частоту термина в поле для конкретного термина.
  • long totalTermFreq(String <field-name>, String <term>): Извлекает общую частоту термина в поле для конкретного термина.
  • long sumTotalTermFreq(String <field-name>): Извлекает сумму общих частот термина в поле.

Пример

Следующий запрос вычисляет оценку как общую частоту термина для каждого поля в списке полей, умноженную на значение множителя:

GET /demo_index_v1/_search
{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "script_score": {
        "script": {
          "source": """
            for (int x = 0; x < params.fields.length; x++) {
              String field = params.fields[x];
              if (field != null) {
                return params.multiplier * totalTermFreq(field, params.term);
              }
            }
            return params.default_value;
          """,
          "params": {
              "fields": ["title", "description"],
              "term": "ai",
              "multiplier": 2,
              "default_value": 1
          }
        }
      }
    }
  }
}

9 - Запрос шаблона

Используйте запрос шаблона для создания поисковых запросов, которые содержат переменные-заполнители.

Используйте запрос шаблона для создания поисковых запросов, которые содержат переменные-заполнители. Заполнители указываются с помощью синтаксиса “${variable_name}” (обратите внимание, что переменные должны быть заключены в кавычки). Когда вы отправляете поисковый запрос, эти заполнители остаются неразрешенными до тех пор, пока они не будут обработаны процессорами запросов поиска. Этот подход особенно полезен, когда ваш начальный поисковый запрос содержит данные, которые необходимо преобразовать или сгенерировать во время выполнения.

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

Для полного примера смотрите раздел “Переписывание запросов с использованием запросов шаблонов”.

Пример

Следующий пример показывает запрос шаблона k-NN с заполнителем “vector”: “${text_embedding}”. Заполнитель “${text_embedding}” будет заменен эмбеддингами, сгенерированными процессором запросов ml_inference из текстового поля ввода:

GET /template-knn-index/_search?search_pipeline=my_knn_pipeline
{
  "query": {
    "template": {
      "knn": {
        "text_embedding": {
          "vector": "${text_embedding}", // Заполнитель для векторного поля
          "k": 2
        }
      }
    }
  },
  "ext": {
    "ml_inference": {
      "text": "sneakers" // Входной текст для процессора ml_inference
    }
  }
}

Конфигурация процессора запросов поиска

Чтобы использовать запрос шаблона с процессором запросов поиска, вам необходимо настроить конвейер поиска. Следующая конфигурация является примером для процессора запросов ml_inference. input_map сопоставляет поля документа с входами модели. В этом примере поле источника ext.ml_inference.text в документе сопоставляется с полем inputText — ожидаемым входным полем для модели. output_map сопоставляет выходы модели с полями документа. В этом примере поле выходного эмбеддинга из модели сопоставляется с полем назначения text_embedding в вашем документе:

PUT /_search/pipeline/my_knn_pipeline
{
  "request_processors": [
    {
      "ml_inference": {
        "model_id": "Sz-wFZQBUpPSu0bsJTBG",
        "input_map": [
          {
            "inputText": "ext.ml_inference.text" // Сопоставить входной текст из запроса
          }
        ],
        "output_map": [
          {
            "text_embedding": "embedding" // Сопоставить выходные данные с заполнителем
          }
        ]
      }
    }
  ]
}

После выполнения процессора запросов ml_inference запрос поиска переписывается. Поле вектора содержит эмбеддинги, сгенерированные процессором, а поле text_embedding содержит выходные данные процессора:

GET /template-knn-1/_search
{
  "query": {
    "template": {
      "knn": {
        "text_embedding": {
          "vector": [0.6328125, 0.26953125, ...], 
          "k": 2
        }
      }
    }
  },
  "ext": {
    "ml_inference": {
      "text": "sneakers",
      "text_embedding": [0.6328125, 0.26953125, ...] 
    }
  }
}

Ограничения

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

10 - Обертка

Запрос обертки позволяет отправлять полный запрос в формате JSON, закодированном в Base64.

Запрос обертки позволяет отправлять полный запрос в формате JSON, закодированном в Base64. Это полезно, когда запрос необходимо встроить в контексты, которые поддерживают только строковые значения.

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

Пример

Создайте индекс с именем products со следующими настройками:

PUT /products
{
  "mappings": {
    "properties": {
      "title": { "type": "text" }
    }
  }
}

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

POST /products/_bulk
{ "index": { "_id": 1 } }
{ "title": "Беспроводные наушники с шумоподавлением" }
{ "index": { "_id": 2 } }
{ "title": "Bluetooth колонка" }
{ "index": { "_id": 3 } }
{ "title": "Наушники накладного типа с глубоким басом" }

Закодируйте следующий запрос в формате Base64:

echo -n '{ "match": { "title": "headphones" } }' | base64

Выполните закодированный запрос:

POST /products/_search
{
  "query": {
    "wrapper": {
      "query": "eyAibWF0Y2giOiB7ICJ0aXRsZSI6ICJoZWFkcGhvbmVzIiB9IH0="
    }
  }
}

Ответ

Ответ содержит два соответствующих документа:

{
  ...
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 0.20098841,
    "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 0.20098841,
        "_source": {
          "title": "Беспроводные наушники с шумоподавлением"
        }
      },
      {
        "_index": "products",
        "_id": "3",
        "_score": 0.18459359,
        "_source": {
          "title": "Наушники накладного типа с глубоким басом"
        }
      }
    ]
  }
}