elasticsearch-php使用scroll深度分页处理数据(附代码)

本文探讨了在Elasticsearch中使用Scroll替代from+size进行大数据分页查询的优化策略,详细介绍了PHP实现Scroll游标的代码示例,并讨论了查询性能、内存管理和灵活性等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

      在刚开始学习ES的时候,觉得自带的from+size就足够使用了,但是在后续的学习中,不断看到一种说法,就是from+size,在要获取10000+10的时候就很影响性能。既然我们使用elasticsearch来处理大数据,那取10000条数据简直不要太随便,况且size默认不能超过10000,超过的话还要设置index.max_result_window参数,实在麻烦。所以博主这里使用scroll来实现数据的遍历查询。

相关链接:
Elasticsearch:from&size返回值最大记录的修改设置
Elasticsearch——分页查询From&Size VS scroll

相关概念请看上面两篇博文,咱们这里不一一赘述了,直接开始php操作

二、操作实例

1、在es-php使用scroll的文档

官方scroll文档:https://www.elastic.co/guide/cn/elasticsearch/php/current/search_operations.html#scrolling%E6%B8%B8%E6%A0%87%E6%9F%A5%E8%AF%A2

2、代码

 public function getIndexByTime($start,$end)
    {
        $start = strtotime($start) + 600;  // 冗余10分钟的数据
        $end =  strtotime($end);
        //组装搜索的索引
        $params = [
            'index' => $date_arr['index'], //多索引一起用,逗号隔开以数组的形式传过去,实测可以
            'type' => '_doc',  // type必须保持一致,且索引建立之后,无法更改索引
            "scroll" => "30s",   //这个代表每次翻页的时间间隔
            "size" => 1000,  //代表每次分页查询的条数
            'body' => [
                "_source" => [
                    "includes" => ["pixel.is50mClient","pixel.newbie", "pixel.channel", "pixel.os", "pixel.type", "pixel.user_id", "pixel.uuid", "*country_code2","clientip", "timestamp","@timestamp"],   //查询的字段,最好是把自己需要的字段都列出来,不要查太多冗余字段
                ],
                'query' => [
                    "bool" => [
                        "filter" => [
                            "range" => [
                                "@timestamp" => [
                                    "gt" => $start_range,
                                    "lt" => $end_range,
                                ]
                            ],
                        ],
                    ]
                ]
            ]
        ];
        $repos =  $this->client->search($params);
        while (isset($repos['hits']['hits']) && count($repos['hits']['hits']) > 0) {
            foreach($repos['hits']['hits'] as $key=>$v)
            {
             // 这里写上你的逻辑
            $scroll_id = $repos['_scroll_id'];
            $repos = $this->client->scroll([    //这里通过while循环,取得上次的scroll_id,继续查询,直到查不出来数据位置
                    "scroll_id" => $scroll_id,
                    "scroll" => "30s"
                ]
            );
        }
    }

大概的代码如上,可以参照注释部分理解。

三、需要注意的地方

1、出现内存不够的情况,报错

Out of memory (allocated 364904448) (tried to allocate 262144 bytes)

      这个报错是php的报错,也就是查出的内存超过了php设置的内存。一般我们本地的内存设置成128M是够用的。所以出现这个情况优先考虑自己是不是操作查出的数组太频繁,foreach数组占用大量内存等。

2、搜索字段少一些

博主在出现内存告急之后试了下:

当搜索字段是全字段的时候,size超过200条就出现内存不足的情况
当搜索字段只列出需要的部分,size设置400条就出现内存不足的情况
当搜索字段只有一个的时候,size部分设置1000都可以

      综上所述,我们可以知道,在查询的时候,查出的字段要尽量的少,其次是size设置成合适的大小。(这部分只是举个例子,内存告急是代码部分的问题,修改之后就好了。)
优化数组内存部分:https://blog.youkuaiyun.com/LJFPHP/article/details/90053455

3、不够灵活

      当结果足够大的时候, scroll 性能更佳。但是不灵活和 scroll_id 难管理问题存在。使用 scroll 必须是按照顺序一页一页进行翻阅,如果是无规则的翻页,它的性能消耗也是极大的。这部分我们可以理解为类似于抖音视频的那种样子,我们看的时候只能往下拉而不能直接选择跳到多少页。因为跳页操作对于大数据来说是非常耗费性能的,对scroll来说也一样。所以大家要根据自己的实际需求去选择分页的方式。

      博主这里的数据对实时性要求不是很高,也不需要进行跳页操作,所以选用了scroll的方式,大家仁者见仁智者见智吧。加油!

end

<think>好的,我现在需要解决用户提出的问题:在使用Elasticsearchscroll分页时返回的数据不完整。首先,我得回忆一下scroll分页的基本原理和常见问题。 用户提到数据不完整,可能的原因有几个。首先,scroll的存活时间(keep_alive)设置是否合理。如果scroll的上下文在下次请求前过期,可能导致数据丢失。比如,如果keep_alive设为1分钟,但处理时间超过这个时间,那么后续请求就会失败。所以需要检查keep_alive参数是否足够长,或者是否能够在处理过程中及时续期。 其次,分页大小(size参数)可能设置得过大。虽然Elasticsearch允许较大的size,但过大的值可能导致单个分片处理数据量超出限制,从而返回部分数据。需要确认size是否在合理范围内,比如不超过10000,或者根据集群配置调整。 另外,索引的变更也可能影响scroll的结果。scroll快照是在初始请求时创建的,如果在滚动过程中有数据写入、更新或删除,这些变更不会反映在后续的结果中。但用户的问题是不全,可能更可能是数据scroll期间被删除,导致某些文档缺失。需要确认在scroll期间是否有数据变动,并考虑是否需要使用对实时性要求更高的分页方式,比如search_after。 还可能存在网络或客户端处理的问题。比如,客户端在处理分页时没有正确获取所有批次,或者在解析响应时出错。需要检查客户端代码是否正确循环获取所有scroll_id,直到没有更多结果为止。 接下来,我需要参考用户提供的引用内容。引用[4]提到修改max_result_window可以调整返回结果的最大数量,但scroll本身不受这个参数限制,所以可能不相关。引用[2]说明深度分页的性能问题,但scroll设计用于深度分页,应该能处理大量数据,但需要正确使用。 解决方案可能包括:调整keep_alive时间,确保在数据处理期间scroll上下文有效;检查分页大小是否符合集群配置;确保在scroll期间索引没有频繁变化;验证客户端是否正确处理所有批次的数据。 最后,需要验证这些解决方案,比如延长keep_alive,减少size,或者在scroll期间避免数据修改,同时检查客户端代码是否正确处理scroll流程。</think>### 解决Elasticsearch Scroll分页数据不完整的方案 #### 1. 确认Scroll上下文存活时间(keep_alive) Scroll分页通过创建快照上下文实现深度分页,但上下文存活时间需合理设置。若存活时间过短,可能导致后续请求时上下文已过期,从而丢失数据。建议: - 在初始化scroll时设置足够长的`keep_alive`,例如`1m`(1分钟),并根据数据处理耗时动态调整。 - 每次获取下一时,可通过`scroll_id`续期上下文,保持活跃状态[^3]。 #### 2. 检查分页大小(size)限制 单个scroll请求的`size`参数需合理配置: - 避免单次请求数据量过大,超过分片处理能力。建议分页大小不超过1000。 - 若需获取全部数据,需循环调用scroll接口直到返回`hits.hits`为空[^2]。 #### 3. 处理索引动态变更的影响 Scroll快照基于初始请求时的索引状态,若分页过程中有数据写入或删除,可能导致部分数据未包含在结果中: - 若业务允许,尽量在scroll期间暂停数据变更操作- 若需实时性,改用`search_after`分页,结合时间戳或唯一排序字段[^1]。 #### 4. 验证客户端处理逻辑 确保客户端正确处理所有scroll批次: - 示例代码(Python): ```python from elasticsearch import Elasticsearch es = Elasticsearch() scroll_id = None data = [] # 初始化scroll response = es.search( index="your_index", body={"query": {"match_all": {}}}, scroll="2m", size=100 ) scroll_id = response['_scroll_id'] data.extend(response['hits']['hits']) # 循环获取所有数据 while len(response['hits']['hits']) > 0: response = es.scroll(scroll_id=scroll_id, scroll="2m") scroll_id = response['_scroll_id'] data.extend(response['hits']['hits']) ``` #### 5. 调整集群配置(极端情况) 若数据量极大(如超过默认内存限制),可调整集群配置: - 修改`elasticsearch.yml`中的`max_result_window`(但scroll不受此参数限制,此处为兜底方案)[^4]。 - 增加节点内存或优化索引分片策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铁柱同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值