Elasticsearch - 搜索你的数据

运行搜索

你可以使用搜索API搜索 Elasticsearch 数据流或索引中存储的数据。

该 API 可以运行两种类型的搜索,具体取决于你如何提供查询

  • URI 搜索
    • 通过查询参数提供查询。URI 搜索往往更简单,最适合测试。
  • 请求体搜索
    • 通过 API 请求的 JSON body 提供查询。这些查询是用 查询DSL 编写的。我们建议在大多数生产用例中使用请求体搜索。

如果同时在 URI 和请求正文中指定查询,则搜索 API 请求仅运行 URI 查询。

运行 URI 搜索

你可以使用搜索 API 的 q查询字符串参数 在请求的 URI 中运行搜索。该 q 参数仅接受以 Lucene 的查询字符串语法编写的查询。

例子:

首先,向 Elasticsearch 索引添加一些数据。

以下 bulk API 将一些示例用户日志数据添加到 user_logs_00001 索引。


示例

$response = $client->bulk([
‘body’ => [
[
‘index’ => [
‘_index’ => ‘user_logs_00001’,
‘_id’ => 1,
],
],
[
‘@timestamp’ => ‘2020-12-06T11:04:05.000Z’,
‘user’ => [
‘id’ => ‘vlb44hny’,
],
‘message’ => ‘Login attempt failed’,
],

[
‘index’ => [
‘_index’ => ‘user_logs_00001’,
‘_id’ => 2,
],
],
[
‘@timestamp’ => ‘2020-12-07T11:06:07.000Z’,
‘user’ => [
‘id’ => ‘8a4f500d’,
],
‘message’ => ‘Login successful’,
],

[
‘index’ => [
‘_index’ => ‘user_logs_00001’,
‘_id’ => 3,
],
],
[
‘@timestamp’ => ‘2020-12-07T11:07:08.000Z’,
‘user’ => [
‘id’ => ‘l7gk7f82’,
],
‘message’ => ‘Logout successful’,
],
],
]);

echo json_encode($response, JSON_PRETTY_PRINT);

现在你可以使用 URI 搜索来匹配一个 user.idl7gk7f82 的文档,请注意查询通过 q 查询参数来指定。

1
2
3
4
5
6
$response = $client->search([
'index' => 'user_logs_00001',
'q' => 'user.id:8a4f500d',
]);

echo json_encode($response, JSON_PRETTY_PRINT);

响应结果的 hits.hits 属性包含了匹配到的文档。

运行一个请求体查询

你也可以通过 查询DSL 语法来传递一个 query 请求体参数进行查询。


示例

$response = $client->search([
‘index’ => ‘user_logs_00001’,
‘body’ => [
‘query’ => [
‘match’ => [
‘message’ => ‘登录成功’,
],
],
]
]);

echo json_encode($response, JSON_PRETTY_PRINT);

API 返回以下响应:

hits.hits 属性包含匹配的文档。默认情况下,响应按这些匹配的文档 _score 的相关性得分排序,该得分衡量每个文档与查询的匹配程度。


响应

{
“took”: 1,
“timed_out”: false,
“_shards”: {
“total”: 1,
“successful”: 1,
“skipped”: 0,
“failed”: 0
},
“hits”: {
“total”: {
“value”: 3,
“relation”: “eq”
},
“max_score”: 0.9983525,
“hits”: [
{
“_index”: “user_logs_00001”,
“_type”: “_doc”,
“_id”: “2”,
“_score”: 0.9983525,
“_source”: {
“@timestamp”: “2020-12-07T11:06:07.000Z”,
“user”: {
“id”: “8a4f500d”
},
“message”: “Login successful”
}
},
{
“_index”: “user_logs_00001”,
“_type”: “_doc”,
“_id”: “3”,
“_score”: 0.49917626,
“_source”: {
“@timestamp”: “2020-12-07T11:07:08.000Z”,
“user”: {
“id”: “l7gk7f82”
},
“message”: “Logout successful”
}
},
{
“_index”: “user_logs_00001”,
“_type”: “_doc”,
“_id”: “1”,
“_score”: 0.42081726,
“_source”: {
“@timestamp”: “2020-12-06T11:04:05.000Z”,
“user”: {
“id”: “vlb44hny”
},
“message”: “Login attempt failed”
}
}
]
}
}

搜索多个数据流和索引

要搜索多个数据流和索引,请将它们作为逗号分隔的值添加到搜索 API 请求路径中。


示例
以下请求搜索 user_logs_00001user_logs_00002 索引。

$response = $client->search([
‘index’ => ‘user_logs_00001,user_logs_00002’,
‘body’ => [
‘query’ => [
‘match’ => [
‘message’ => ‘Login Successful’,
],
],
]
]);

echo json_encode($response, JSON_PRETTY_PRINT);

你也可以使用通配符 * 模式搜索多个数据流和索引。


示例

$response = $client->search([
‘index’ => ‘user_logs*’,
‘body’ => [
‘query’ => [
‘match’ => [
‘message’ => ‘Login Successful’,
],
],
]
]);

echo json_encode($response, JSON_PRETTY_PRINT);

要搜索集群中的所有数据流和索引,请从请求路径中省略目标。或者,你可以使用 _all*


示例

$response = $client->search([
‘index’ => ‘’, // 搜索全部索引
// ‘index’ => ‘_all’, // 搜索全部索引
// ‘index’ => ‘*’, // 搜索全部索引
‘body’ => [
‘query’ => [
‘match’ => [
‘message’ => ‘Login Successful’,
],
],
]
]);

echo json_encode($response, JSON_PRETTY_PRINT);

分页搜索结果

默认情况下,搜索 API 返回前 10 个匹配的文档。

要分页显示更多结果,可以使用搜索 API sizefrom 参数。该 size 参数是要返回匹配文档的数量。该 from 是从完整结果集开始的零索引偏移量,该偏移量指示要开始使用的文档。


示例
以下搜索 API 请求将 from 偏移量设置为 5,表示请求偏移量或跳过前五个匹配文档。
size 参数是 20,这意味着该请求最多可返回 20 个文档,开始偏移。

$response = $client->search([
‘index’ => ‘*’,
‘body’ => [
‘query’ => [
‘term’ => [
‘user.id’ => ‘8a4f500d’,
],
],
],
‘from’ => 5,
‘size’ => 20,
]);

echo json_encode($response, JSON_PRETTY_PRINT);

默认情况下,你不能使用 fromsize 参数分页浏览超过 10000 个文档。使用 index.max_result_window 索引设置来设置此限制。

深度分页或一次请求许多结果可能会导致搜索缓慢。结果在返回之前先进行排序。由于搜索请求通常跨越多个分片,因此每个分片必须生成自己的排序结果。然后必须对这些单独的结果进行合并和排序,以确保总体排序顺序正确。

作为深度分页的替代方法,我们建议使用 scrollsearch_after 参数。

Elasticsearch 使用 Lucene 的内部文档 ID 作为平局。这些内部文档 ID 在相同数据的副本之间可能完全不同。在进行分页时,您可能偶尔会看到排序顺序相同的文档的顺序不一致。

检索选定的字段

默认情况下,搜索响应中的每个 _source 匹配都包括 document,这是对文档建立索引时提供的整个 JSON 对象。如果在搜索响应中仅需要某些源字段,则可以使用 source-filtering 来限制返回源的哪些部分。

仅使用文档源返回字段有一些限制:

  • _source 不包含多字段或字段别名。同样,源中的字段也不包含使用 copy_to 映射参数复制的值。
  • 由于 _source 在 Lucene 中存储为单个字段,因此即使只需要少量字段,也必须加载和解析整个源对象。

为了避免这些限制,你可以:

  • 使用 docvalue_fields 参数获取选定字段的值。当返回相当少量的支持 doc 值的字段(例如关键字和日期)时,这是一个不错的选择。
  • 使用 sorted_fields 参数获取特定存储字段的值。(使用 store 映射选项的字段。)

你可以在以下各节中找到有关这些方法的更多详细信息:

  • 源过滤
  • 文件值栏位
  • 储存栏位

源过滤

你可以使用该 _source 参数选择返回源的哪些字段。这称为源过滤。

如下的搜索请求设置 _source 请求体参数为 false,这样请求结果里就不会包含 _source 字段。


示例

$response = $client->search([
‘index’ => ‘*’,
‘body’ => [
‘query’ => [
‘term’ => [
‘user.id’ => ‘8a4f500d’,
],
],
],
‘_source’ => false,
]);

echo json_encode($response, JSON_PRETTY_PRINT);

也可以通过 * 通配符来让搜索 API 返回对应的字段,下面的请求返回的响应结果中的 _source 字段只会包含 obj 字段以及它的属性:


示例

$response = $client->search([
‘index’ => ‘‘,
‘body’ => [
‘query’ => [
‘term’ => [
‘user.id’ => ‘8a4f500d’,
],
],
],
‘_source’ => ‘obj.
‘,
]);

echo json_encode($response, JSON_PRETTY_PRINT);

你也可以通过数组指定多个字段名匹配的模式,如下的请求会返回 obj1obj2 字段和它们的属性:


示例

$response = $client->search([
‘index’ => ‘‘,
‘body’ => [
‘query’ => [
‘term’ => [
‘user.id’ => ‘8a4f500d’,
],
],
],
‘_source’ => [‘obj1.
‘, ‘obj2.*’],
]);

echo json_encode($response, JSON_PRETTY_PRINT);

为了更好地控制,你可以指定一个对象,该对象在参数中包含 includesexcludes 模式的数组 _source

如果 includes 指定了属性,则仅返回与其模式之一匹配的源字段。你可以使用 excludes 属性从此子集中排除字段。

如果 includes 未指定该属性,则返回整个文档源,不包括与该 excludes 属性中的模式匹配的任何字段。

以下搜索 API 请求仅返回 obj1obj2 字段及属性的源,不包括任何子 description 字段。


示例

$response = $client->search([
‘index’ => ‘‘,
‘body’ => [
‘query’ => [
‘term’ => [
‘user.id’ => ‘8a4f500d’,
],
],
],
‘_source’ => [
‘includes’ => [
‘obj1.
‘,
‘obj2.‘,
],
‘excludes’ => [
.description’,
],
],
]);

echo json_encode($response, JSON_PRETTY_PRINT);

docvalue_fields

你可以使用 docvalue_fields 参数返回搜索响应中一个或多个字段的 doc-values

Doc 值存储与 _source 相同的值,但是在磁盘上基于列的结构中进行了优化,该结构针对排序和聚合进行了优化。由于每个字段都是单独存储的,因此 Elasticsearch 仅读取所请求的字段值,并且可以避免加载整个文档。

默认情况下,将为支持的字段存储文档值。但是,texttext_annotated 字段不支持 doc 值。

以下搜索请求使用该 docvalue_fields 参数来检索以下字段的 doc 值:

  • 名称以 my_ip 开头的字段
  • my_keyword_field
  • 名称以 _date_field 结尾的字段



$response = $client->search([
‘index’ => ‘‘,
‘body’ => [
‘query’ => [
‘match_all’ => (object)[
],
],
‘docvalue_fields’ => [
‘my_ip
‘,
[
‘field’ => ‘my_keyword_field’,
],
[
‘field’ => ‘*_date_field’,
‘format’ => ‘epoch_millis’,
],
],
],
]);

echo json_encode($response, JSON_PRETTY_PRINT);
  • 通配符 patten,用于匹配以字符串形式指定的字段名称
  • 通配符 patten,用于匹配指定为对象的字段名称
  • 使用对象符号,可以使用 format 参数指定字段的返回 doc 值格式。日期字段支持日期格式,数值字段支持 DecimalFormat 模式。其他字段数据类型不支持该 format 参数。

储存栏位

也可以使用 store 映射选项存储单个字段的值。你可以使用 stored_fields 参数将这些存储的值包括在搜索响应中。