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

一、前言

      在刚开始学习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.csdn.net/LJFPHP/article/details/90053455

3、不够灵活

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

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

end

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Elasticsearch 中,深度分页功能的使用需要考虑到性能问题。一般来说,建议不要使用过深的分页,以避免对 Elasticsearch 的性能造成负面影响。 以下是在 Elasticsearch使用深度分页的方法: 1. 使用 scroll API 进行深度分页查询 scroll API 可以在内存中存储搜索上下文,而不是在每个请求之间重新计算。这使得在大数据集上进行深度分页查询变得更加有效。 示例代码: ``` SearchRequest searchRequest = new SearchRequest("indexName"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchSourceBuilder.size(100); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); String scrollId = searchResponse.getScrollId(); SearchHit[] searchHits = searchResponse.getHits().getHits(); while (searchHits != null && searchHits.length > 0) { SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); scrollRequest.scroll(TimeValue.timeValueMinutes(1L)); SearchResponse scrollResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT); scrollId = scrollResponse.getScrollId(); searchHits = scrollResponse.getHits().getHits(); // Do something with searchHits } ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); clearScrollRequest.addScrollId(scrollId); client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); ``` 在上面的示例中,size 参数设置为 100,表示每次检索返回 100 个结果。scroll API 的 scroll 参数设置为 1 分钟,表示在这段时间内保持搜索上下文。 2. 使用 search_after 参数进行深度分页查询 search_after 参数可以用来指定上一次搜索的最后一个结果,以便从下一个结果开始进行分页查询。 示例代码: ``` SearchRequest searchRequest = new SearchRequest("indexName"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchSourceBuilder.size(100); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] searchHits = searchResponse.getHits().getHits(); while (searchHits != null && searchHits.length > 0) { SearchHit lastHit = searchHits[searchHits.length - 1]; searchSourceBuilder.searchAfter(lastHit.getSortValues()); searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); searchHits = searchResponse.getHits().getHits(); // Do something with searchHits } ``` 在上面的示例中,size 参数设置为 100,表示每次检索返回 100 个结果。search_after 参数使用上一次搜索的最后一个结果的排序值。 总之,深度分页查询在 Elasticsearch 中的实现需要考虑性能问题,建议使用 scroll API 或 search_after 参数来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

铁柱同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值