Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Поиск данных ›Приложения Elastic Search

API и шаблоны поиска приложений

Ваши приложения поиска используют шаблоны поиска для выполнения поисковых запросов. Шаблоны помогают уменьшить сложность, предоставляя только параметры шаблона, при этом используя всю мощь языка запросов Elasticsearch для формулирования запросов. Шаблоны могут быть установлены при создании или обновлении приложения поиска и могут быть настраиваемы. Этот шаблон можно редактировать или обновлять в любое время с помощью вызова API Put Search Application.

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

  • Упрощают запросы
  • Уменьшают размер запроса
  • Обеспечивают безопасность и производительность, так как запрос предварительно определён и не может быть произвольно изменён

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

Шаблоны поиска используют язык шаблонов Mustache. Переменные Mustache обычно заключены в двойные фигурные скобки, например: {{my-var}}.

Узнайте больше, прочитав о шаблонах поиска.

Пример шаблона по умолчанию

Если с приложением поиска не сохранён ни один шаблон, при поиске будет применён минимальный шаблон поиска по умолчанию. Шаблон по умолчанию реализует простой сценарий поиска.

Для создания приложения поиска с шаблоном по умолчанию выполните запрос на создание или обновление приложения поиска без указания шаблона:

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1",
            "index2"
        ]
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1", "index2"],
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": ["index1", "index2"]
}

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

resp = client.search_application.get(
    name="my_search_application",
)
print(resp)
const response = await client.searchApplication.get({
  name: "my_search_application",
});
console.log(response);
GET _application/search_application/my_search_application

В этом случае ответ будет:

{
  "name": "my_search_application",
  "indices": [
    "index1",
    "index2"
  ],
  "updated_at_millis": 1715802354482,
  "template": {
    "script": {
      "source": """{
  "query": {
    "query_string": {
        "query": "{{query_string}}",
        "default_field": "{{default_field}}"
        }
    }
}
""",
      "lang": "mustache",
      "params": {
        "default_field": "*",
        "query_string": "*"
      }
    }
  }
}

Шаблон по умолчанию очень минималистичен:

{
  "template": {
    "script": {
      "source": {
        "query": {
          "query_string": {
            "query": "{{query_string}}",
            "default_field": "{{default_field}}"
          }
        }
      },
      "params": {
        "query_string": "*",
        "default_field": "*"
      }
    }
  }
}

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

Этот шаблон не поддерживает дополнительные параметры, включая from, size или boost. Если вам необходимо использовать их, вы можете настроить шаблон, связанный с вашим приложением поиска, соответственно, чтобы включить их как параметры.

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

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

resp = client.search_application.render_query(
    name="my_search_application",
)
print(resp)
const response = await client.transport.request({
  method: "POST",
  path: "/_application/search_application/my_search_application/_render_query",
});
console.log(response);
POST _application/search_application/my_search_application/_render_query

вернёт:

{
  "query": {
    "query_string": {
      "query": "*",
      "default_field": "*",
      "fields": []
    }
  }
}

Это использует параметры по умолчанию, которые были определены в шаблоне. Вы также можете указать один или несколько параметров в вызове отрисовки, например:

resp = client.search_application.render_query(
    name="my_search_application",
    params={
        "query_string": "rock climbing"
    },
)
print(resp)
const response = await client.transport.request({
  method: "POST",
  path: "/_application/search_application/my_search_application/_render_query",
  body: {
    params: {
      query_string: "rock climbing",
    },
  },
});
console.log(response);
POST _application/search_application/my_search_application/_render_query
{
  "params": {
    "query_string": "rock climbing"
  }
}

вернёт:

{
  "query": {
    "query_string": {
      "query": "rock climbing",
      "default_field": "*",
      "fields": []
    }
  }
}

В этом случае параметр {{query_string}} был заменён значением rock climbing, а параметр {{default_field}} не был указан, поэтому использовалось значение по умолчанию *.

Когда вы фактически выполняете поиск без параметров, он выполнит базовый запрос, возвращённый вызовом отрисовки. В данном случае поиск без параметров вернёт все результаты, аналогично вызову /_search без параметров.

resp = client.search_application.search(
    name="my_search_application",
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
});
console.log(response);
POST _application/search_application/my_search_application/_search

Поиск с параметрами query_string и/или default_field выполнит запрос query_string.

Шаблон по умолчанию может быть изменён в будущих версиях функции «Приложения поиска».

Попробуйте другие примеры в этом документе, чтобы поэкспериментировать со специфическими случаями использования, или попробуйте создать свои собственные!

Поиск в приложении поиска

Поиск по шаблону

Самый простой способ взаимодействия с приложением поиска — использование созданного и сохранённого шаблона поиска. Каждое приложение поиска имеет один связанный с ним шаблон, который определяет критерии поиска, параметры и значения по умолчанию.

Вы отправляете запросы на поиск в приложение поиска, используя API поиска приложения поиска.

С шаблоном по умолчанию поиск выглядит так:

resp = client.search_application.search(
    name="my_search_application",
    params={
        "query_string": "kayaking"
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    query_string: "kayaking",
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "query_string": "kayaking"
  }
}

В этом примере мы переопределили значение параметра query_string по умолчанию *. Поскольку мы не указали default_field, значение этого параметра останется *.

Поиск по псевдониму

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

Если имя вашего приложения поиска — my_search_application, ваш псевдоним будет my_search_application. Вы можете выполнить поиск с помощью API поиска.

Поиск между кластерами

Приложения поиска в настоящее время не поддерживают поиск между кластерами, так как невозможно добавить индекс или шаблон индекса удалённого кластера к псевдониму индекса.

Вы должны использовать API управления приложениями поиска для обновления своего приложения, а не напрямую использовать API Elasticsearch, такие как API псевдонима. Например, используйте PUT Search Application с параметром indices. Это автоматически сохранит связанный псевдоним в актуальном состоянии и гарантирует, что индексы будут добавлены в приложение поиска должным образом.

Примеры шаблонов поиска

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

Следующий шаблон поддерживает поиск multi_match по указанным полям и коэффициентам повышения:

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1",
            "index2"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n      {\n        \"query\": {\n          \"multi_match\": {\n            \"query\": \"{{query_string}}\",\n            \"fields\": [{{#text_fields}}\"{{name}}^{{boost}}\",{{/text_fields}}]\n          }\n        },\n        \"explain\": \"{{explain}}\",\n        \"from\": \"{{from}}\",\n        \"size\": \"{{size}}\"\n      }\n      ",
                "params": {
                    "query_string": "*",
                    "text_fields": [
                        {
                            "name": "title",
                            "boost": 10
                        },
                        {
                            "name": "description",
                            "boost": 5
                        }
                    ],
                    "explain": False,
                    "from": 0,
                    "size": 10
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1", "index2"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n      {\n        "query": {\n          "multi_match": {\n            "query": "{{query_string}}",\n            "fields": [{{#text_fields}}"{{name}}^{{boost}}",{{/text_fields}}]\n          }\n        },\n        "explain": "{{explain}}",\n        "from": "{{from}}",\n        "size": "{{size}}"\n      }\n      ',
        params: {
          query_string: "*",
          text_fields: [
            {
              name: "title",
              boost: 10,
            },
            {
              name: "description",
              boost: 5,
            },
          ],
          explain: false,
          from: 0,
          size: 10,
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": ["index1", "index2"],
  "template": {
    "script": {
      "lang": "mustache",
      "source": """
      {
        "query": {
          "multi_match": {
            "query": "{{query_string}}",
            "fields": [{{#text_fields}}"{{name}}^{{boost}}",{{/text_fields}}]
          }
        },
        "explain": "{{explain}}",
        "from": "{{from}}",
        "size": "{{size}}"
      }
      """,
      "params": {
        "query_string": "*",
        "text_fields": [
          {"name": "title", "boost": 10},
          {"name": "description", "boost": 5}
        ],
        "explain": false,
        "from": 0,
        "size": 10
      }
    }
  }
}

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

resp = client.search_application.search(
    name="my_search_application",
    params={
        "size": 5,
        "query_string": "mountain climbing",
        "text_fields": [
            {
                "name": "title",
                "boost": 10
            },
            {
                "name": "description",
                "boost": 2
            },
            {
                "name": "state",
                "boost": 1
            }
        ]
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    size: 5,
    query_string: "mountain climbing",
    text_fields: [
      {
        name: "title",
        boost: 10,
      },
      {
        name: "description",
        boost: 2,
      },
      {
        name: "state",
        boost: 1,
      },
    ],
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "size": 5,
    "query_string": "mountain climbing",
    "text_fields": [
          {"name": "title", "boost": 10},
          {"name": "description", "boost": 2},
          {"name": "state", "boost": 1}
     ]
  }
}

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

Поиск текста + ELSER с RRF

Этот пример поддерживает метод взаимного ранжирования (RRF) для объединения поисков BM25 и ELSER. Взаимное ранжирование постоянно улучшает комбинированные результаты различных алгоритмов поиска. Оно превосходит все другие алгоритмы ранжирования и часто превосходит лучшие индивидуальные результаты без калибровки.

resp = client.search_application.put(
    name="my-search-app",
    search_application={
        "indices": [
            "index1"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n      {\n        \"retriever\": {\n          \"rrf\": {\n            \"retrievers\": [\n              {{#text_fields}}\n              {\n                \"standard\": {\n                  \"query\": {\n                    \"match\": {\n                      \"{{.}}\": \"{{query_string}}\"\n                    }\n                  }\n                }\n              },\n              {{/text_fields}}\n              {{#elser_fields}}\n              {\n                \"standard\": {\n                  \"query\": {\n                    \"sparse_vector\": {\n                      \"field\": \"ml.inference.{{.}}_expanded.predicted_value\",\n                      \"inference_id\": \"<elser_inference_id>\",\n                      \"query\": \"{{query_string}}\"\n                    }\n                  }\n                }\n              },\n              {{/elser_fields}}\n            ],\n            \"rank_window_size\": {{rrf.rank_window_size}},\n            \"rank_constant\": {{rrf.rank_constant}}\n          }\n        }\n      }\n      ",
                "params": {
                    "elser_fields": [
                        "title",
                        "meta_description"
                    ],
                    "text_fields": [
                        "title",
                        "meta_description"
                    ],
                    "query_string": "",
                    "rrf": {
                        "rank_window_size": 100,
                        "rank_constant": 60
                    }
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my-search-app",
  search_application: {
    indices: ["index1"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n      {\n        "retriever": {\n          "rrf": {\n            "retrievers": [\n              {{#text_fields}}\n              {\n                "standard": {\n                  "query": {\n                    "match": {\n                      "{{.}}": "{{query_string}}"\n                    }\n                  }\n                }\n              },\n              {{/text_fields}}\n              {{#elser_fields}}\n              {\n                "standard": {\n                  "query": {\n                    "sparse_vector": {\n                      "field": "ml.inference.{{.}}_expanded.predicted_value",\n                      "inference_id": "<elser_inference_id>",\n                      "query": "{{query_string}}"\n                    }\n                  }\n                }\n              },\n              {{/elser_fields}}\n            ],\n            "rank_window_size": {{rrf.rank_window_size}},\n            "rank_constant": {{rrf.rank_constant}}\n          }\n        }\n      }\n      ',
        params: {
          elser_fields: ["title", "meta_description"],
          text_fields: ["title", "meta_description"],
          query_string: "",
          rrf: {
            rank_window_size: 100,
            rank_constant: 60,
          },
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my-search-app
{
  "indices": [
    "index1"
  ],
  "template": {
    "script": {
      "lang": "mustache",
      "source": """
      {
        "retriever": {
          "rrf": {
            "retrievers": [
              {{#text_fields}}
              {
                "standard": {
                  "query": {
                    "match": {
                      "{{.}}": "{{query_string}}"
                    }
                  }
                }
              },
              {{/text_fields}}
              {{#elser_fields}}
              {
                "standard": {
                  "query": {
                    "sparse_vector": {
                      "field": "ml.inference.{{.}}_expanded.predicted_value",
                      "inference_id": "<elser_inference_id>",
                      "query": "{{query_string}}"
                    }
                  }
                }
              },
              {{/elser_fields}}
            ],
            "rank_window_size": {{rrf.rank_window_size}},
            "rank_constant": {{rrf.rank_constant}}
          }
        }
      }
      """,
      "params": {
        "elser_fields": ["title", "meta_description"],
        "text_fields": ["title", "meta_description"],
        "query_string": "",
        "rrf": {
          "rank_window_size": 100,
          "rank_constant": 60
        }
      }
    }
  }
}

Замените <elser_model_id> на идентификатор модели вашей развёртывания ELSER.

Пример запроса для этого шаблона будет выглядеть следующим образом:

resp = client.search_application.search(
    name="my-search-app",
    params={
        "query_string": "What is the most popular brand of coffee sold in the United States?",
        "elser_fields": [
            "title",
            "meta_description"
        ],
        "text_fields": [
            "title",
            "meta_description"
        ],
        "rrf": {
            "rank_window_size": 50,
            "rank_constant": 25
        }
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my-search-app",
  params: {
    query_string:
      "What is the most popular brand of coffee sold in the United States?",
    elser_fields: ["title", "meta_description"],
    text_fields: ["title", "meta_description"],
    rrf: {
      rank_window_size: 50,
      rank_constant: 25,
    },
  },
});
console.log(response);
POST _application/search_application/my-search-app/_search
{
  "params": {
    "query_string": "What is the most popular brand of coffee sold in the United States?",
    "elser_fields": ["title", "meta_description"],
    "text_fields": ["title", "meta_description"],
    "rrf": {
      "rank_window_size": 50,
      "rank_constant": 25
    }
  }
}
Поиск текста + ELSER

Elastic Learned Sparse EncodeR (ELSER) улучшает релевантность поиска за счёт расширения текста, что позволяет выполнять семантический поиск. Этот экспериментальный шаблон требует включения ELSER для одного или нескольких полей. Обратитесь к Семантический поиск с ELSER для получения дополнительной информации о том, как использовать ELSER. В данном случае ELSER включён для полей title и description.

Этот пример предоставляет один шаблон, который можно использовать для различных сценариев поиска: поиск по тексту, ELSER или оба вместе. Он также предоставляет простой по умолчанию query_string запрос, если параметры не указаны.

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1",
            "index2"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n      {\n        \"query\": {\n          \"bool\": {\n            \"should\": [\n              {{#text}}\n              {\n                \"multi_match\": {\n                  \"query\": \"{{query_string}}\",\n                  \"fields\": [{{#text_fields}}\"{{name}}^{{boost}}\",{{/text_fields}}],\n                  \"boost\": \"{{text_query_boost}}\"\n                }\n              },\n              {{/text}}\n              {{#elser}}\n              {{#elser_fields}}\n              {\n                \"sparse_vector\": {\n                  \"field\": \"ml.inference.{{.}}_expanded.predicted_value\",\n                  \"inference_id\": \"<elser_inference_id>\",\n                  \"query\": \"{{query_string}}\"\n                }\n              },\n              {{/elser_fields}}\n              { \"bool\": { \"must\": [] } },\n              {{/elser}}\n              {{^text}}\n              {{^elser}}\n              {\n                \"query_string\": {\n                  \"query\": \"{{query_string}}\",\n                  \"default_field\": \"{{default_field}}\",\n                  \"default_operator\": \"{{default_operator}}\",\n                  \"boost\": \"{{text_query_boost}}\"\n                }\n              },\n              {{/elser}}\n              {{/text}}\n              { \"bool\": { \"must\": [] } }\n              ],\n            \"minimum_should_match\": 1\n          }\n        },\n        \"min_score\": \"{{min_score}}\",\n        \"explain\": \"{{explain}}\",\n        \"from\": \"{{from}}\",\n        \"size\": \"{{size}}\"\n      }\n      ",
                "params": {
                    "text": False,
                    "elser": False,
                    "elser_fields": [
                        {
                            "name": "title",
                            "boost": 1
                        },
                        {
                            "name": "description",
                            "boost": 1
                        }
                    ],
                    "text_fields": [
                        {
                            "name": "title",
                            "boost": 10
                        },
                        {
                            "name": "description",
                            "boost": 5
                        },
                        {
                            "name": "state",
                            "boost": 1
                        }
                    ],
                    "query_string": "*",
                    "text_query_boost": 4,
                    "default_field": "*",
                    "default_operator": "OR",
                    "explain": False,
                    "from": 0,
                    "size": 10,
                    "min_score": 0
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1", "index2"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n      {\n        "query": {\n          "bool": {\n            "should": [\n              {{#text}}\n              {\n                "multi_match": {\n                  "query": "{{query_string}}",\n                  "fields": [{{#text_fields}}"{{name}}^{{boost}}",{{/text_fields}}],\n                  "boost": "{{text_query_boost}}"\n                }\n              },\n              {{/text}}\n              {{#elser}}\n              {{#elser_fields}}\n              {\n                "sparse_vector": {\n                  "field": "ml.inference.{{.}}_expanded.predicted_value",\n                  "inference_id": "<elser_inference_id>",\n                  "query": "{{query_string}}"\n                }\n              },\n              {{/elser_fields}}\n              { "bool": { "must": [] } },\n              {{/elser}}\n              {{^text}}\n              {{^elser}}\n              {\n                "query_string": {\n                  "query": "{{query_string}}",\n                  "default_field": "{{default_field}}",\n                  "default_operator": "{{default_operator}}",\n                  "boost": "{{text_query_boost}}"\n                }\n              },\n              {{/elser}}\n              {{/text}}\n              { "bool": { "must": [] } }\n              ],\n            "minimum_should_match": 1\n          }\n        },\n        "min_score": "{{min_score}}",\n        "explain": "{{explain}}",\n        "from": "{{from}}",\n        "size": "{{size}}"\n      }\n      ',
        params: {
          text: false,
          elser: false,
          elser_fields: [
            {
              name: "title",
              boost: 1,
            },
            {
              name: "description",
              boost: 1,
            },
          ],
          text_fields: [
            {
              name: "title",
              boost: 10,
            },
            {
              name: "description",
              boost: 5,
            },
            {
              name: "state",
              boost: 1,
            },
          ],
          query_string: "*",
          text_query_boost: 4,
          default_field: "*",
          default_operator: "OR",
          explain: false,
          from: 0,
          size: 10,
          min_score: 0,
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": [
    "index1",
    "index2"
  ],
  "template": {
    "script": {
      "lang": "mustache",
      "source": """
      {
        "query": {
          "bool": {
            "should": [
              {{#text}}
              {
                "multi_match": {
                  "query": "{{query_string}}",
                  "fields": [{{#text_fields}}"{{name}}^{{boost}}",{{/text_fields}}],
                  "boost": "{{text_query_boost}}"
                }
              },
              {{/text}}
              {{#elser}}
              {{#elser_fields}}
              {
                "sparse_vector": {
                  "field": "ml.inference.{{.}}_expanded.predicted_value",
                  "inference_id": "<elser_inference_id>",
                  "query": "{{query_string}}"
                }
              },
              {{/elser_fields}}
              { "bool": { "must": [] } },
              {{/elser}}
              {{^text}}
              {{^elser}}
              {
                "query_string": {
                  "query": "{{query_string}}",
                  "default_field": "{{default_field}}",
                  "default_operator": "{{default_operator}}",
                  "boost": "{{text_query_boost}}"
                }
              },
              {{/elser}}
              {{/text}}
              { "bool": { "must": [] } }
              ],
            "minimum_should_match": 1
          }
        },
        "min_score": "{{min_score}}",
        "explain": "{{explain}}",
        "from": "{{from}}",
        "size": "{{size}}"
      }
      """,
      "params": {
        "text": false,
        "elser": false,
        "elser_fields": [
          {"name": "title", "boost": 1},
          {"name": "description", "boost": 1}
        ],
        "text_fields": [
          {"name": "title", "boost": 10},
          {"name": "description", "boost": 5},
          {"name": "state", "boost": 1}
        ],
        "query_string": "*",
        "text_query_boost": 4,
        "default_field": "*",
        "default_operator": "OR",
        "explain": false,
        "from": 0,
        "size": 10,
        "min_score": 0
      }
    }
  }
}

Запрос поиска по тексту, использующий этот шаблон, может выглядеть так:

resp = client.search_application.search(
    name="my_search_application",
    params={
        "text": True,
        "size": 5,
        "query_string": "mountain climbing",
        "text_fields": [
            {
                "name": "title",
                "boost": 10
            },
            {
                "name": "description",
                "boost": 5
            },
            {
                "name": "state",
                "boost": 1
            }
        ]
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    text: true,
    size: 5,
    query_string: "mountain climbing",
    text_fields: [
      {
        name: "title",
        boost: 10,
      },
      {
        name: "description",
        boost: 5,
      },
      {
        name: "state",
        boost: 1,
      },
    ],
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "text": true,
    "size": 5,
    "query_string": "mountain climbing",
    "text_fields": [
          {"name": "title", "boost": 10},
          {"name": "description", "boost": 5},
          {"name": "state", "boost": 1}
     ]
  }
}

Запрос поиска с помощью ELSER, использующий этот шаблон, будет выглядеть следующим образом:

resp = client.search_application.search(
    name="my_search_application",
    params={
        "elser": True,
        "query_string": "where is the best mountain climbing?",
        "elser_fields": [
            {
                "name": "title",
                "boost": 1
            },
            {
                "name": "description",
                "boost": 1
            }
        ]
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    elser: true,
    query_string: "where is the best mountain climbing?",
    elser_fields: [
      {
        name: "title",
        boost: 1,
      },
      {
        name: "description",
        boost: 1,
      },
    ],
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "elser": true,
    "query_string": "where is the best mountain climbing?",
    "elser_fields": [
      {"name": "title", "boost": 1},
      {"name": "description", "boost": 1}
    ]
  }
}

Запрос поиска по тексту и с использованием ELSER, использующий этот шаблон, будет выглядеть следующим образом:

resp = client.search_application.search(
    name="my_search_application",
    params={
        "elser": True,
        "text": True,
        "query_string": "where is the best mountain climbing?",
        "elser_fields": [
            {
                "name": "title",
                "boost": 1
            },
            {
                "name": "description",
                "boost": 1
            }
        ],
        "text_query_boost": 4,
        "min_score": 10
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    elser: true,
    text: true,
    query_string: "where is the best mountain climbing?",
    elser_fields: [
      {
        name: "title",
        boost: 1,
      },
      {
        name: "description",
        boost: 1,
      },
    ],
    text_query_boost: 4,
    min_score: 10,
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "elser": true,
    "text": true,
    "query_string": "where is the best mountain climbing?",
    "elser_fields": [
      {"name": "title", "boost": 1},
      {"name": "description", "boost": 1}
    ],
    "text_query_boost": 4,
    "min_score": 10
  }
}

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

  • text_query_boost для усиления запроса BM25 в целом
  • boost полей для усиления отдельных текстовых полей поиска
  • min_score параметр для исключения результатов с существенно низкой уверенностью

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

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

resp = client.search_application.search(
    name="my_search_application",
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
});
console.log(response);
POST _application/search_application/my_search_application/_search
Поиск с использованием ELSER

Этот пример поддерживает упрощённую версию поиска с использованием ELSER.

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1",
            "index2"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n        {\n          \"query\": {\n            \"bool\": {\n              \"should\": [\n                {{#elser_fields}}\n                {\n                  \"sparse_vector\": {\n                      \"field\": \"ml.inference.{{.}}_expanded.predicted_value\",\n                      \"inference_id\": \"<elser_inference_id>\",\n                      \"query\": \"{{query_string}}\"\n                    }\n                },\n                {{/elser_fields}}\n                ]\n            }\n          },\n          \"min_score\": \"{{min_score}}\"\n        }\n        ",
                "params": {
                    "query_string": "*",
                    "min_score": "10",
                    "elser_fields": [
                        {
                            "name": "title"
                        },
                        {
                            "name": "description"
                        }
                    ]
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1", "index2"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n        {\n          "query": {\n            "bool": {\n              "should": [\n                {{#elser_fields}}\n                {\n                  "sparse_vector": {\n                      "field": "ml.inference.{{.}}_expanded.predicted_value",\n                      "inference_id": "<elser_inference_id>",\n                      "query": "{{query_string}}"\n                    }\n                },\n                {{/elser_fields}}\n                ]\n            }\n          },\n          "min_score": "{{min_score}}"\n        }\n        ',
        params: {
          query_string: "*",
          min_score: "10",
          elser_fields: [
            {
              name: "title",
            },
            {
              name: "description",
            },
          ],
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": [
    "index1",
    "index2"
    ],
    "template": {
      "script": {
        "lang": "mustache",
        "source": """
        {
          "query": {
            "bool": {
              "should": [
                {{#elser_fields}}
                {
                  "sparse_vector": {
                      "field": "ml.inference.{{.}}_expanded.predicted_value",
                      "inference_id": "<elser_inference_id>",
                      "query": "{{query_string}}"
                    }
                },
                {{/elser_fields}}
                ]
            }
          },
          "min_score": "{{min_score}}"
        }
        """,
        "params": {
          "query_string": "*",
          "min_score": "10",
          "elser_fields": [
            {
              "name": "title"
            },
            {
              "name": "description"
            }
            ]
        }
      }
    }
}

Замените <elser_model_id> на идентификатор модели вашего развертывания ELSER.

Пример запроса для этого шаблона будет выглядеть следующим образом:

resp = client.search_application.search(
    name="my_search_application",
    params={
        "query_string": "Where is the best place for mountain climbing?"
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    query_string: "Where is the best place for mountain climbing?",
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
  {
    "params": {
      "query_string": "Where is the best place for mountain climbing?"
    }
  }
Поиск kNN

Этот пример поддерживает поиск k ближайших соседей (kNN)

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

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n        {\n          \"query\": {\n            \"script_score\": {\n              \"query\": {\n                \"bool\": {\n                  \"filter\": {\n                    \"range\": {\n                      \"{{field}}\": {\n                        \"{{operator}}\": {{value}}\n                      }\n                    }\n                  }\n                }\n              },\n              \"script\": {\n                \"source\": \"cosineSimilarity({{#toJson}}query_vector{{/toJson}}, '{{dense_vector_field}}') + 1.0\"\n              }\n            }\n          }\n        }\n        ",
                "params": {
                    "field": "price",
                    "operator": "gte",
                    "value": 1000,
                    "dense_vector_field": "product-vector",
                    "query_vector": []
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n        {\n          "query": {\n            "script_score": {\n              "query": {\n                "bool": {\n                  "filter": {\n                    "range": {\n                      "{{field}}": {\n                        "{{operator}}": {{value}}\n                      }\n                    }\n                  }\n                }\n              },\n              "script": {\n                "source": "cosineSimilarity({{#toJson}}query_vector{{/toJson}}, \'{{dense_vector_field}}\') + 1.0"\n              }\n            }\n          }\n        }\n        ',
        params: {
          field: "price",
          operator: "gte",
          value: 1000,
          dense_vector_field: "product-vector",
          query_vector: [],
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": [
    "index1"
  ],
  "template": {
    "script": {
      "lang": "mustache",
      "source": """
        {
          "query": {
            "script_score": {
              "query": {
                "bool": {
                  "filter": {
                    "range": {
                      "{{field}}": {
                        "{{operator}}": {{value}}
                      }
                    }
                  }
                }
              },
              "script": {
                "source": "cosineSimilarity({{#toJson}}query_vector{{/toJson}}, '{{dense_vector_field}}') + 1.0"
              }
            }
          }
        }
        """,
      "params": {
        "field": "price",
        "operator": "gte",
        "value": 1000,
        "dense_vector_field": "product-vector",
        "query_vector": []
      }
    }
  }
}

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

resp = client.search_application.search(
    name="my_search_application",
    params={
        "field": "price",
        "operator": "gte",
        "value": 500
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    field: "price",
    operator: "gte",
    value: 500,
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "field": "price",
    "operator": "gte",
    "value": 500
  }
}

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

resp = client.search_application.put(
    name="my_search_application",
    search_application={
        "indices": [
            "index1"
        ],
        "template": {
            "script": {
                "lang": "mustache",
                "source": "\n      {\n          \"knn\": {\n            \"field\": \"{{knn_field}}\",\n            \"query_vector\": {{#toJson}}query_vector{{/toJson}},\n            \"k\": \"{{k}}\",\n            \"num_candidates\": {{num_candidates}}\n          },\n          \"fields\": {{#toJson}}fields{{/toJson}}\n      }\n      ",
                "params": {
                    "knn_field": "image-vector",
                    "query_vector": [],
                    "k": 10,
                    "num_candidates": 100,
                    "fields": [
                        "title",
                        "file-type"
                    ]
                }
            }
        }
    },
)
print(resp)
const response = await client.searchApplication.put({
  name: "my_search_application",
  search_application: {
    indices: ["index1"],
    template: {
      script: {
        lang: "mustache",
        source:
          '\n      {\n          "knn": {\n            "field": "{{knn_field}}",\n            "query_vector": {{#toJson}}query_vector{{/toJson}},\n            "k": "{{k}}",\n            "num_candidates": {{num_candidates}}\n          },\n          "fields": {{#toJson}}fields{{/toJson}}\n      }\n      ',
        params: {
          knn_field: "image-vector",
          query_vector: [],
          k: 10,
          num_candidates: 100,
          fields: ["title", "file-type"],
        },
      },
    },
  },
});
console.log(response);
PUT _application/search_application/my_search_application
{
  "indices": [
    "index1"
  ],
  "template": {
    "script": {
      "lang": "mustache",
      "source": """
      {
          "knn": {
            "field": "{{knn_field}}",
            "query_vector": {{#toJson}}query_vector{{/toJson}},
            "k": "{{k}}",
            "num_candidates": {{num_candidates}}
          },
          "fields": {{#toJson}}fields{{/toJson}}
      }
      """,
      "params": {
        "knn_field": "image-vector",
        "query_vector": [],
        "k": 10,
        "num_candidates": 100,
        "fields": ["title", "file-type"]
      }
    }
  }
}

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

resp = client.search_application.search(
    name="my_search_application",
    params={
        "knn_field": "image-vector",
        "query_vector": [
            -5,
            9,
            -12
        ],
        "k": 10,
        "num_candidates": 100,
        "fields": [
            "title",
            "file-type"
        ]
    },
)
print(resp)
const response = await client.searchApplication.search({
  name: "my_search_application",
  params: {
    knn_field: "image-vector",
    query_vector: [-5, 9, -12],
    k: 10,
    num_candidates: 100,
    fields: ["title", "file-type"],
  },
});
console.log(response);
POST _application/search_application/my_search_application/_search
{
  "params": {
    "knn_field": "image-vector",
        "query_vector": [-5, 9, -12],
        "k": 10,
        "num_candidates": 100,
        "fields": ["title", "file-type"]
  }
}

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-application-api.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API