搜索 API 和模板
Elastic Stack Serverless
您的 搜索应用程序 使用 搜索模板 来执行搜索。模板通过仅公开模板参数来帮助降低复杂性,同时使用 Elasticsearch 的查询 DSL 的全部功能来制定查询。模板可以在创建或更新搜索应用程序时设置,并且可以自定义。可以使用 Put Search Application API API 调用随时编辑或更新此模板。
简而言之,您创建带有参数而不是特定硬编码搜索值的搜索模板。在搜索时,您传入这些参数的实际值,从而实现自定义搜索,而无需重写整个查询结构。搜索应用程序模板
- 简化查询请求
- 减少请求大小
- 确保安全性和性能,因为查询是预定义的,不能随意更改
本文档提供信息和示例模板,以帮助您开始使用 搜索应用程序 以用于其他用例。这些模板旨在易于修改以满足您的需求。使用模板创建搜索应用程序后,您可以使用此模板搜索您的搜索应用程序。
如果搜索应用程序未存储任何模板,则将在搜索时应用最小的 默认搜索模板。默认模板实现了简单的搜索用例。
要使用默认模板创建搜索应用程序,请发出 创建或更新搜索应用程序 请求,而不指定模板
PUT _application/search_application/my_search_application
{
"indices": ["index1", "index2"]
}
然后,您可以使用 get search application API 调用来查看您新创建的搜索应用程序,其中还将包括为您创建的默认模板
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
。如果您需要使用这些,您可以相应地自定义与搜索应用程序关联的模板,以将其作为参数包含在内。
您可以通过查看模板来查看参数及其默认值,但是如果您使用各种参数 搜索您的搜索应用程序,查看将生成的查询也可能很有价值。
您可以使用 render search application query 来查看此模板将生成的查询,包括使用默认参数。例如,在没有参数的情况下搜索搜索应用程序
POST _application/search_application/my_search_application/_render_query
将返回
{
"query": {
"query_string": {
"query": "*",
"default_field": "*",
"fields": []
}
}
}
这使用与模板一起定义的默认参数。您还可以为 render 调用指定一个或多个参数,例如
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}}
参数,因此使用了默认值 *
。
当您实际执行没有参数的搜索时,它将执行 render 调用返回的底层查询。在这种情况下,没有参数的搜索将返回所有结果,其方式类似于对 /_search
的无参数调用。
POST _application/search_application/my_search_application/_search
使用 query_string
和/或 default_field
参数进行搜索将执行 query_string
查询。
默认模板可能会在搜索应用程序功能的未来版本中更改。
尝试本文档中的其他一些示例来尝试特定用例,或者尝试创建您自己的示例!
与搜索应用程序交互的最简单方法是使用随其创建和存储的搜索模板。每个搜索应用程序都有一个与之关联的模板,该模板定义搜索条件、参数和默认值。
您可以使用 搜索应用程序搜索 API 将搜索请求发送到搜索应用程序。
使用默认模板,搜索看起来像这样
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 Search Application。这将自动使关联的别名保持最新,并确保将索引正确添加到搜索应用程序。
我们创建了许多示例来探索特定的用例。使用这些作为创建自己的搜索模板的起点。
以下模板支持对指定字段和 boost 进行 multi_match
搜索
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
}
}
}
}
使用此模板的搜索查询可能如下所示
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
。
此示例支持 [倒数排序融合 (RRF)]](elasticsearch://reference/elasticsearch/rest-apis/reciprocal-rank-fusion.md) 方法,用于组合 BM25 和 ELSER 搜索。倒数排序融合可以持续改进不同搜索算法的组合结果。它优于所有其他排序算法,并且通常超过最佳的单个结果,而无需校准。
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。
此模板的示例查询将类似于以下示例
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
}
}
}
Elastic Learned Sparse EncodeR (ELSER) 通过文本扩展来提高搜索相关性,从而实现语义搜索。此实验性模板要求为一个或多个字段启用 ELSER。有关如何使用 ELSER 的更多信息,请参阅 使用 ELSER 进行语义搜索。在这种情况下,ELSER 在 title
和 description
字段上启用。
此示例提供了一个可用于各种搜索应用程序场景的模板:文本搜索、ELSER 或上述所有场景。如果没有指定参数,它还提供了一个简单的默认 query_string
查询。
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
}
}
}
}
使用此模板的文本搜索查询可能如下所示
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 搜索查询将类似于以下示例
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 搜索查询将类似于以下示例
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 值
上述的提升应该足以满足许多用例,但在某些情况下,向模板添加 重新评分 (rescore) 查询或 索引提升 (index boost) 可能是有益的。请记住使用 put search application 命令 更新您的搜索应用程序以使用新模板。
最后,使用此模板的无参数搜索将退回到返回所有文档的默认搜索
POST _application/search_application/my_search_application/_search
此示例支持精简版的 ELSER 搜索。
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。
此模板的示例查询将类似于以下示例
POST _application/search_application/my_search_application/_search
{
"params": {
"query_string": "Where is the best place for mountain climbing?"
}
}
此示例支持 k-最近邻 (kNN) 搜索。
支持精确 kNN 搜索的模板如下例所示
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": []
}
}
}
}
使用此模板的搜索查询如下例所示
POST _application/search_application/my_search_application/_search
{
"params": {
"field": "price",
"operator": "gte",
"value": 500
}
}
支持近似 kNN 搜索的模板如下例所示
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"]
}
}
}
}
使用此模板的搜索查询如下例所示
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"]
}
}