搜索应用程序搜索 API 和模板

编辑

您的搜索应用程序使用搜索模板来执行搜索。模板通过仅公开模板参数来帮助降低复杂性,同时使用 Elasticsearch 查询 DSL 的全部功能来制定查询。模板可以在创建或更新搜索应用程序时设置,并且可以自定义。可以使用 Put 搜索应用程序 API API 调用随时编辑或更新此模板。

简而言之,您可以使用参数而不是特定的硬编码搜索值来创建搜索模板。在搜索时,您传入这些参数的实际值,从而实现自定义搜索,而无需重写整个查询结构。搜索应用程序模板

  • 简化查询请求
  • 减小请求大小
  • 确保安全性和性能,因为查询是预定义的,不能任意更改

本文档提供信息和示例模板,以帮助您开始使用搜索应用程序以进行其他用例。这些模板旨在易于修改以满足您的需求。使用模板创建搜索应用程序后,您可以使用此模板搜索您的搜索应用程序。

搜索模板使用 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": "*"
      }
    }
  }
}

这可能有助于初始探索搜索模板,但您可能需要更新它。

此模板不支持其他参数,包括 fromsizeboost。如果需要使用这些参数,可以相应地自定义与您的搜索应用程序关联的模板,以将其作为参数包括在内。

您可以通过查看模板来查看参数及其默认值,但如果您使用各种参数搜索您的搜索应用程序,查看将生成的查询也可能很有价值。

您可以使用渲染搜索应用程序查询来查看此模板将生成的查询,包括默认参数。例如,使用不带任何参数搜索搜索应用程序

resp = client.search_application.render_query(
    name="my_search_application",
    body=None,
)
print(resp)
const response = await client.searchApplication.renderQuery({
  name: "my_search_application",
  body: null,
});
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",
    body={
        "params": {
            "query_string": "rock climbing"
        }
    },
)
print(resp)
const response = await client.searchApplication.renderQuery({
  name: "my_search_application",
  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 来更新您的应用程序,而直接使用 Elasticsearch API,例如别名 API。例如,使用带有 indices 参数的 PUT 搜索应用程序。这将自动使关联的别名保持最新,并确保将索引正确添加到搜索应用程序。

搜索模板示例

编辑

我们创建了许多示例来探索特定用例。将这些用作创建您自己的搜索模板的起点。

文本搜索示例
编辑

以下模板支持在指定字段和 boost 上进行 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}
     ]
  }
}

可以使用新的/不同的字段和 boost 来覆盖 text_fields 参数,以试验最适合您用例的配置。此模板还通过参数支持分页和 explain

文本搜索 + ELSER(带 RRF)
编辑

此示例支持用于组合 BM25 和 ELSER 搜索的倒数排名融合 (RRF)] 方法。倒数排名融合可以持续改进不同搜索算法的组合结果。它优于所有其他排名算法,并且通常无需校准即可超越最佳的单个结果。

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 部署的模型 ID。

此模板的示例查询将如下所示

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 进行语义搜索。在这种情况下,已在 titledescription 字段上启用 ELSER。

此示例提供了一个可用于各种搜索应用程序场景的单个模板:文本搜索、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 搜索结果的评分预计会明显不同,这使得排名具有挑战性。要为您的数据集找到最佳的搜索结果组合,我们建议试验示例模板中提供的 boost 值

  • text_query_boost 以整体提升 BM25 查询
  • boost 字段以提升单个文本搜索字段
  • min_score 参数以省略置信度明显较低的结果

上述 boost 应该足以满足许多用例,但在某些情况下,向模板添加 重新评分 查询或索引提升可能会有所帮助。请记住使用put 搜索应用程序命令来更新您的搜索应用程序,以使用新模板。

最后,使用此模板的无参数搜索将回退到返回所有文档的默认搜索

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 部署的模型 ID。

此模板的示例查询将如下所示

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"]
  }
}