ElasticSearch使用Scroll检索大规模数据

目录

本文属于介绍 NWPC 消息平台 系列文章。

默认配置下 ElasticSearch 单个查询只能返回一页 (page) 数据,默认一页大小为 10000。 想要检索大规模数据,有多种方式。 本文介绍使用 scroll API 获取大规模数据的方法。

标准查询

查询 2020 年 12 月 GRAPES TYM 系统的所有产品消息。 TYM 系统一天运行 4 次,每个时次生成 121 个产品,理论上 12 月一共有 4 * 121 * 31 = 15004 个消息。

请求 API

POST /2020-12/_search

请求体

{
  "query": {
    "term" : {
      "data.system": "grapes_tym"
    }
  },
  "sort": {
    "time": "asc"
  }
}

查询结果如下 (省略返回条目)。 可以看到只查询到 10000 个结果。

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [
      "...skip..."
    ]
  }
}

Scroll 查询

ElasticSearch 提供 Scroll API 支持使用单个查询返回大量数据,甚至可以返回数据全集, 类似关系型数据库中的 curser。

请求 API 中指定 scroll 参数,告知 ElasticSearch 服务器保存当前查询内容 (search context) 的持续时间。 下面的请求中 1m 表示保存 1 分钟。

POST /2020-12/_search?scroll=1m

请求体与标准查询相同

{
  "query": {
    "term" : {
      "data.system": "grapes_tym"
    }
  },
  "sort": {
    "time": "asc"
  }
}

返回结果显示检索找到 15003 个数据。 注:因为数据按消息生成时间字段 time 分布在不同索引中,查询得到的总数据量可能比理论数据量少。

返回结果中的 _scroll_id 字段表示当前查询的 ID 号,使用该 ID 号可以继续获取该查询的文档。

{
  "_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFGlsT2YwSFlCUGp5MzZGa0xWa3FuAAAAAAAxr0MWZk9kZ3V3Q0NUYTZEYU5zY0kwWF9YUQ==",
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 15003,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      "...skip..."
    ]
  }
}

使用 scroll_id 再次获取前面查询的文档

POST /_search/scroll   

查询体

{
  "scroll" : "1m",                                                                 
  "scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFGlsT2YwSFlCUGp5MzZGa0xWa3FuAAAAAAAxr0MWZk9kZ3V3Q0NUYTZEYU5zY0kwWF9YUQ" 
}

返回结果与前次查询类似

{
  "_scroll_id" : "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFGlsT2YwSFlCUGp5MzZGa0xWa3FuAAAAAAAxr0MWZk9kZ3V3Q0NUYTZEYU5zY0kwWF9YUQ",
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 15003,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      "...skip..."
    ]
  }
}

多次执行该步骤,可以获取查询对应的所有文档。

实现

本节介绍如何在 elasticsearch-py 中使用 scroll API。

创建 SCROLL API 查询

result = client.search(
    index="2020-12",
    body={
      "query": {
        "term" : {
          "data.system": "grapes_tym"
        }
      },
      "sort": {
        "time": "asc"
      }
    },
    scroll="1m",
)

从返回结果中获取 scroll_id

scroll_id = result["_scroll_id"]

继续当前查询

result = client.scroll(
    scroll="1m",
    scroll_id=scroll_id
)

参考

官方文档:

https://www.elastic.co/guide/en/elasticsearch/reference/7.4/search-request-body.html#request-body-search-scroll

项目示例:

nwpc-oper/nwpc-message-tool