_search
API
Elastic Stack Serverless
本页重点介绍使用 Query DSL 语法的 _search
API。有关搜索用例的替代 Elastic 查询语法的概述,请参阅构建搜索查询。
搜索由一个或多个查询组成,这些查询被组合并发送到 Elasticsearch。与搜索查询匹配的文档将在响应的命中或搜索结果中返回。
搜索还可以包含用于更好地处理其查询的附加信息。例如,搜索可以限制为特定索引,或者仅返回特定数量的结果。
您可以使用搜索 API来搜索和聚合存储在 Elasticsearch 数据流或索引中的数据。 API 的 query
请求正文参数接受用Query DSL编写的查询。
以下请求使用match
查询搜索my-index-000001
。此查询匹配 user.id
值为 kimchy
的文档。
GET /my-index-000001/_search
{
"query": {
"match": {
"user.id": "kimchy"
}
}
}
API 响应会在 hits.hits
属性中返回与查询匹配的前 10 个文档。
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "my-index-000001",
"_id": "kxWFcnMByiguvud1Z8vC",
"_score": 1.3862942,
"_source": {
"@timestamp": "2099-11-15T14:12:12",
"http": {
"request": {
"method": "get"
},
"response": {
"bytes": 1070000,
"status_code": 200
},
"version": "1.1"
},
"message": "GET /search HTTP/1.1 200 1070000",
"source": {
"ip": "127.0.0.1"
},
"user": {
"id": "kimchy"
}
}
}
]
}
}
您可以使用以下选项自定义搜索。
Query DSL
Query DSL支持各种查询类型,您可以混合和匹配这些类型以获得所需的结果。 查询类型包括
聚合
您可以使用搜索聚合来获取搜索结果的统计信息和其他分析信息。 聚合可以帮助您回答以下问题:
- 我的服务器的平均响应时间是多少?
- 我的网络上用户命中的顶级 IP 地址是什么?
- 每个客户的总交易收入是多少?
搜索多个数据流和索引
您可以使用逗号分隔的值和类 grep 的索引模式在同一请求中搜索多个数据流和索引。 您甚至可以提升来自特定索引的搜索结果。 请参阅使用查询搜索多个数据流和索引。
分页搜索结果
默认情况下,搜索仅返回前 10 个匹配的命中。 要检索更多或更少的文档,请参阅分页搜索结果。
检索选定的字段
搜索响应的 hits.hits
属性包括每个命中的完整文档_source
。 要仅检索 _source
或其他字段的子集,请参阅检索选定的字段。
对搜索结果进行排序
默认情况下,搜索命中按 _score
排序,_score
是一种相关性评分,用于衡量每个文档与查询的匹配程度。 要自定义这些分数的计算,请使用script_score
查询。 要按其他字段值对搜索命中进行排序,请参阅对搜索结果进行排序。
运行异步搜索
Elasticsearch 搜索旨在快速处理大量数据,通常在几毫秒内返回结果。 因此,默认情况下搜索是同步的。 搜索请求会等待完整的结果,然后才返回响应。
但是,对于跨大型数据集或多个集群的搜索,完整的结果可能需要更长的时间。
为避免长时间等待,您可以改为运行异步搜索。 通过异步搜索,您可以立即检索长时间运行的搜索的部分结果,并在以后获取完整的结果。
您可以定义仅作为搜索查询一部分存在的运行时字段,而不是索引数据,然后搜索它。 您可以在搜索请求中指定 runtime_mappings
部分来定义运行时字段,该字段可以选择包括 Painless 脚本。
例如,以下查询定义了一个名为 day_of_week
的运行时字段。 包含的脚本根据 @timestamp
字段的值计算星期几,并使用 emit
返回计算的值。
该查询还包括一个对 day_of_week
进行操作的词项聚合。
GET /my-index-000001/_search
{
"runtime_mappings": {
"day_of_week": {
"type": "keyword",
"script": {
"source":
"""emit(doc['@timestamp'].value.dayOfWeekEnum
.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"""
}
}
},
"aggs": {
"day_of_week": {
"terms": {
"field": "day_of_week"
}
}
}
}
响应包括一个基于 day_of_week
运行时字段的聚合。 在 buckets
下是一个 key
,其值为 Sunday
。 该查询根据 day_of_week
运行时字段中定义的脚本动态计算此值,而无需对该字段进行索引。
{
...
***
"aggregations" : {
"day_of_week" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "Sunday",
"doc_count" : 5
}
]
}
}
}
默认情况下,搜索请求不会超时。 该请求会等待来自每个分片的完整结果,然后再返回响应。
虽然异步搜索专为长时间运行的搜索而设计,但您也可以使用 timeout
参数指定您希望每个分片完成的等待时间。 每个分片都会在指定的时间段内收集命中。 如果在该时间段结束时未完成收集,则 Elasticsearch 仅使用在该时间点之前累积的命中。 搜索请求的总体延迟取决于搜索所需的分片数量以及并发分片请求的数量。
GET /my-index-000001/_search
{
"timeout": "2s",
"query": {
"match": {
"user.id": "kimchy"
}
}
}
要为所有搜索请求设置集群范围的默认超时,请使用集群设置 API配置 search.default_search_timeout
。 如果在请求中未传递 timeout
参数,则使用此全局超时持续时间。 如果全局搜索超时在搜索请求完成之前到期,则使用任务取消取消该请求。 search.default_search_timeout
设置默认为 -1
(无超时)。
您可以使用任务管理 API取消搜索请求。 当客户端的 HTTP 连接关闭时,Elasticsearch 也会自动取消搜索请求。 我们建议您设置客户端,以便在中止或超时搜索请求时关闭 HTTP 连接。
通常,如果不访问所有匹配项,则无法准确计算总命中数,这对于匹配大量文档的查询来说成本很高。 通过 track_total_hits
参数,您可以控制应如何跟踪总命中数。 考虑到通常足以获得命中数的下限,例如“至少有 10000 个命中”,因此默认设置为 10,000
。 这意味着请求将准确地计算总命中数,最高可达 10,000
个命中。 如果您在达到特定阈值后不需要准确的命中数,这是一个加快搜索速度的好方法。
设置为 true
时,搜索响应将始终准确地跟踪与查询匹配的命中数(例如,当 track_total_hits
设置为 true 时,total.relation
将始终等于 "eq"
)。 否则,搜索响应中 "total"
对象中返回的 "total.relation"
将确定应如何解释 "total.value"
。 "gte"
值表示 "total.value"
是与查询匹配的总命中的下限,"eq"
值表示 "total.value"
是准确的计数。
GET my-index-000001/_search
{
"track_total_hits": true,
"query": {
"match" : {
"user.id" : "elkbee"
}
}
}
... 返回
{
"_shards": ...
"timed_out": false,
"took": 100,
"hits": {
"max_score": 1.0,
"total" : {
"value": 2048,
"relation": "eq"
},
"hits": ...
}
}
- 与查询匹配的总命中数。
- 计数是准确的(例如,
"eq"
表示等于)。
也可以将 track_total_hits
设置为整数。 例如,以下查询将准确地跟踪与查询匹配的总命中数,最高可达 100 个文档
GET my-index-000001/_search
{
"track_total_hits": 100,
"query": {
"match": {
"user.id": "elkbee"
}
}
}
响应中的 hits.total.relation
将指示 hits.total.value
中返回的值是准确的 ("eq"
) 还是总数的下限 ("gte"
)。
例如,以下响应
{
"_shards": ...
"timed_out": false,
"took": 30,
"hits": {
"max_score": 1.0,
"total": {
"value": 42,
"relation": "eq"
},
"hits": ...
}
}
- 42 个文档匹配查询
- 并且计数是准确的 (
"eq"
)
... 表明 total
中返回的命中数是准确的。
如果匹配查询的命中总数大于 track_total_hits
中设置的值,则响应中的总命中数将指示返回的值是下限
{
"_shards": ...
"hits": {
"max_score": 1.0,
"total": {
"value": 100,
"relation": "gte"
},
"hits": ...
}
}
- 至少有 100 个文档匹配查询
- 这是一个下限 (
"gte"
)。
如果您根本不需要跟踪总命中数,可以通过将此选项设置为 false
来缩短查询时间
GET my-index-000001/_search
{
"track_total_hits": false,
"query": {
"match": {
"user.id": "elkbee"
}
}
}
... 返回
{
"_shards": ...
"timed_out": false,
"took": 10,
"hits": {
"max_score": 1.0,
"hits": ...
}
}
- 总命中数未知。
最后,您可以通过在请求中将 "track_total_hits"
设置为 true
来强制进行精确计数。
track_total_hits
参数允许您用命中计数准确性来换取性能。一般来说,track_total_hits
的值越低,查询速度就越快,而 false
返回最快的结果。将 track_total_hits
设置为 true 将导致 Elasticsearch 返回精确的命中计数,这可能会损害查询性能,因为它禁用了 Max WAND 优化。
如果您只想知道是否有任何文档匹配特定查询,您可以将 size
设置为 0
,以表明我们对搜索结果不感兴趣。您还可以将 terminate_after
设置为 1
,以表明只要找到第一个匹配的文档(每个分片),就可以终止查询执行。
GET /_search?q=user.id:elkbee&size=0&terminate_after=1
terminate_after
始终在 post_filter
之后应用,并在分片上收集到足够的命中数时停止查询以及聚合执行。虽然聚合上的文档计数可能无法反映响应中的 hits.total
,因为聚合是在后过滤之前应用的。
由于 size
设置为 0
,因此响应将不包含任何命中。hits.total
将等于 0
,表示没有匹配的文档,或者大于 0
,表示在提前终止时,至少有许多文档匹配查询。此外,如果查询提前终止,则 terminated_early
标志将在响应中设置为 true
。某些查询能够直接从索引统计信息中检索命中计数,这要快得多,因为它不需要执行查询。在这些情况下,不会收集任何文档,返回的 total.hits
将高于 terminate_after
,并且 terminated_early
将设置为 false
。
{
"took": 3,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 1,
"successful": 1,
"skipped" : 0,
"failed": 0
},
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": null,
"hits": []
}
}
响应中的 took
时间包含此请求进行处理所花费的毫秒数,从节点收到查询后立即开始,直到所有搜索相关工作完成并在上述 JSON 返回给客户端之前为止。这意味着它包括在线程池中等待、在整个集群中执行分布式搜索和收集所有结果所花费的时间。