加载中

_search API

提示

本页重点介绍使用 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"
          }
        }
      }
    ]
  }
}
		

您可以使用以下选项来自定义搜索。

查询 DSL
Query DSL 支持多种查询类型,您可以混搭使用它们以获取所需的结果。查询类型包括:

聚合
您可以使用搜索聚合来获取搜索结果的统计信息和其他分析数据。聚合可帮助您回答以下问题:

  • 我的服务器的平均响应时间是多少?
  • 我的网络上的用户访问最多的前几个 IP 地址是什么?
  • 按客户划分的总交易收入是多少?

搜索多个数据流和索引
您可以使用逗号分隔的值和类似 grep 的索引模式在同一个请求中搜索多个数据流和索引。您甚至可以提高特定索引的搜索结果权重。请参阅使用查询搜索多个数据流和索引

分页搜索结果
默认情况下,搜索仅返回前 10 个匹配的命中结果。要检索更多或更少的文档,请参阅分页搜索结果

检索选定字段
搜索响应的 hits.hits 属性包含每个命中项的完整文档 _source。如果只想检索 _source 或其他字段的子集,请参阅检索选定字段

排序搜索结果
默认情况下,搜索命中结果会按 _score 排序,这是一个衡量每个文档与查询匹配程度的相关性得分。要自定义这些得分的计算,请使用 script_score 查询。要按其他字段值对搜索命中结果进行排序,请参阅对搜索结果进行排序

运行异步搜索
Elasticsearch 搜索旨在快速处理大量数据,通常在几毫秒内返回结果。因此,搜索默认是同步的。搜索请求会等待完整的结果,然后才返回响应。

但是,对于跨大型数据集或多集群的搜索,获取完整结果可能需要更长的时间。

为避免长时间等待,您可以改为运行异步(async)搜索。异步搜索允许您立即检索长时间运行的部分结果,并在稍后获取完整结果。

您可以不用先对数据进行索引然后再搜索,而是定义仅作为搜索查询一部分存在的运行时字段。您可以在搜索请求中指定一个 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 下面是一个值为 Sundaykey。该查询根据 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应用于每个分片,从该分片上的查询阶段开始时计算。它不会对读取模型的其他部分强制执行全局搜索级别的超时。如果在某个分片上超出了超时值,它将返回部分结果,并且搜索响应会被标记为 "timed_out": true

{
 "took" : 11,
  "timed_out" : true,
  "_shards" : {
    "total" : 40,
    "successful" : 40,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 98393,
      "relation" : "eq"
    },
    // ...
  }
}
		
  1. 可能不完整的值

如果某个特定的搜索请求应该报错而不是返回部分结果,请考虑将 default_allow_partial_results 设置设为 false

您可以通过配置 search.default_search_timeout 集群设置,为所有搜索请求设置一个回退的集群范围默认超时。在这种情况下,请求将使用任务取消 API 被取消。

注意

search.default_search_timeout 设置的分辨率敏感度由 thread_pool.estimated_time_interval 设置决定,其默认值为 200ms。这意味着 search.default_search_timeout 的最小有意义影响阈值也将是 200ms。Elastic 建议不要覆盖此专家设置,因为它具有深远的影响。

您可以使用任务管理 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": ...
  }
}
		
  1. 匹配查询的总命中数。
  2. 计数是准确的(例如 "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": ...
  }
}
		
  1. 有 42 个文档匹配查询
  2. 并且计数是准确的 ("eq")

... 表明 total 中返回的命中数是准确的。

如果匹配查询的总命中数大于 track_total_hits 中设置的值,则响应中的总命中数将表明返回的值是一个下限

{
  "_shards": ...
  "hits": {
    "max_score": 1.0,
    "total": {
      "value": 100,
      "relation": "gte"
    },
    "hits": ...
  }
}
		
  1. 至少有 100 个文档匹配查询
  2. 这是一个下限 ("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": ...
  }
}
		
  1. 总命中数未知。

最后,您可以通过在请求中将 "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,因为聚合是在后过滤(post filtering)之前应用的。

由于 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 返回给客户端之前。这意味着它包括在线程池中等待、在整个集群中执行分布式搜索以及收集所有结果所花费的时间。

_shards.failed 表示有多少个分片未能成功为搜索请求返回结果。_shards.failures 仅在发生分片故障时返回,其中包含一个对象数组,带有诸如索引名称、分片编号、节点 ID 以及失败原因等详细信息。

"_shards": {
  "total": 5,
  "successful": 1,
  "skipped": 0,
  "failed": 4,
  "failures": [
    {
      "shard": 0,
      "index": "<index_name>",
      "node": "<node_id>",
      "reason": {
        "type": "node_not_connected_exception",
        "reason": "[<node_name>][<ip>:<port>] Node not connected"
      }
    },
    {
      "shard": 1,
      "index": "<index_name>",
      "node": null,
      "reason": {
        "type": "no_shard_available_action_exception",
        "index_uuid": "<index_uuid>",
        "shard": "1",
        "index": "<index_name>"
      }
    }
  ]
}
		

分片故障会按 indexexception 进行去重。如果相同的异常在同一个索引上多次发生,即使多个分片失败,它也只会报告在 _shards.failures 中一次。因此,_shards.failures 中的条目数可能会小于 _shards.failed 中的值。

© . This website operates independently and is not affiliated with or endorsed by Elasticsearch B.V. All brand names, logos, and trademarks are the property of their respective owners.