elasticsearch 使用from+size深度分页性能问题解决方案

news2025/1/27 5:36:29

问题分析

在 Elasticsearch 中,使用 from 和 size 参数进行分页查询时,深度分页(即请求非常高的页面号码)会导致性能问题,原因主要包括以下几点:

1. 数据扫描量增加

  • 跳过大量文档:当你使用 from 参数来请求第 N 页的数据时,Elasticsearch 必须先扫描并跳过 (from - 1) * size 个文档才能开始收集实际需要返回的文档。例如,如果你请求第 100 页,每页 10 个结果,那么 Elasticsearch 需要跳过前 990 个文档。这在数据量大的情况下会显著增加查询时间和资源使用。

2. 排序和聚合的开销

  • 排序复杂度:如果查询涉及排序(特别是基于非索引字段或需要复杂计算的排序),Elasticsearch 需要对所有跳过的文档进行排序操作,这增加了计算成本。

  • 聚合操作:如果查询同时涉及聚合操作,每个分片都可能需要处理所有数据来计算聚合结果,然后再进行合并,这进一步放大了性能开销。

3. 内存消耗

  • 内存压力:在深度分页的情况下,Elasticsearch 需要在内存中保持大量文档的状态(特别是如果 size 设置得较大),这可能会导致内存不足(Out of Memory, OOM)错误,尤其是在处理大规模数据集时。

4. 网络传输

  • 数据传输:虽然主要是内部网络,但在分布式环境下,协调节点需要从多个分片节点收集数据,这些数据传输量会随着分页深度的增加而增加。

5. 协调节点的负担

  • 协调和合并:协调节点需要从所有相关的分片中收集结果,并将这些结果合并排序。这在深度分页时会变成一个相当重的任务,因为它需要处理更多数据。

6. 默认限制

  • max_result_window:Elasticsearch 默认限制 from + size 不能超过 10,000。这是因为系统设计上不鼓励深度分页,超过这个限制会导致查询失败,除非你调整了这个设置,但这也只是治标不治本。

解决方案:

  1. Scroll API:

    使用 Scroll API 可以进行分批查询,避免深度分页的开销。Scroll API 在每个查询阶段存储状态,使得后续请求不必从头开始查询。适合后台批处理任务,如数据迁移,但不适用于实时搜索,因为它不反映索引的实时变化。
  2. Search After:

    这是一种基于游标的分页方式,利用上一页的最后一个结果作为下一页查询的起点。每个文档需要一个全局唯一值(如 _id)来确保排序的一致性。适用于用户实时、高并发查询需求,因为它可以反映索引的实时变化。
  3. 调整 max_result_window:

    • 虽然不是一种解决深度分页的长期策略,但通过增加 index.max_result_window 设置可以临时提高分页限制。不过,这仍然会增加资源消耗和潜在的OOM风险。

  4. Time-Based Pagination:

    • 如果数据有时间属性,可以根据时间范围进行分页,这样可以避免大量数据的扫描,提高查询效率。
  5. Shard-Based Pagination:

    • 针对分布式环境,通过利用分片来分页,可以在分布式环境下更好地管理查询负载。

注意事项:

1. Scroll API

Scroll API 适用于处理大量结果的场景,通过保持搜索上下文,连续获取下一批结果。

  • 优点:适合大批量数据处理,如数据导出、离线分析。
  • 缺点:不适合实时数据更新。
import org.elasticsearch.action.search.*;
import org.elasticsearch.client.*;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.SearchHit;

import java.io.IOException;

public class ElasticSearchScroll {
    private RestHighLevelClient client;

    public ElasticSearchScroll(RestHighLevelClient client) {
        this.client = client;
    }

    public void scrollSearch(String indexName) throws IOException {
        final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchAllQuery())
                .size(1000); // Batch size
        SearchRequest searchRequest = new SearchRequest(indexName)
                .scroll(scroll)
                .source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        String scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();

        while (searchHits != null && searchHits.length > 0) {
            for (SearchHit hit : searchHits) {
                System.out.println(hit.getSourceAsString());
            }

            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(scroll);
            searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            scrollId = searchResponse.getScrollId();
            searchHits = searchResponse.getHits().getHits();
        }

        ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
        clearScrollRequest.addScrollId(scrollId);
        client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
    }
}
2. Search After

Search After 使用最后一个结果的排序值作为下一个查询的起点,避免了传统分页中的偏移操作。

  • 优点:适合实时数据分页,避免了大偏移量带来的性能问题。
  • 缺点:需要排序字段唯一(通常使用复合排序,如 _id)。
import org.elasticsearch.action.search.*;
import org.elasticsearch.client.*;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;

public class ElasticSearchSearchAfter {
    private RestHighLevelClient client;

    public ElasticSearchSearchAfter(RestHighLevelClient client) {
        this.client = client;
    }

    public void searchAfterPagination(String indexName, int pageSize) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder()
                .query(QueryBuilders.matchAllQuery())
                .size(pageSize)
                .sort("timestamp", SortOrder.ASC)
                .sort("_id", SortOrder.ASC); // Ensure unique sort

        SearchRequest searchRequest = new SearchRequest(indexName)
                .source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] searchHits = searchResponse.getHits().getHits();

        while (searchHits.length > 0) {
            for (SearchHit hit : searchHits) {
                System.out.println(hit.getSourceAsString());
            }

            // Get the last sort value
            Object[] sortValues = searchHits[searchHits.length - 1].getSortValues();

            searchSourceBuilder.searchAfter(sortValues);
            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            searchHits = searchResponse.getHits().getHits();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2283236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用python-docx包进行多文件word文字、字符批量替换

1、首先下载pycharm。 2、改为中文。 3、安装python-docx包。 搜索包名字,安装。 4、新建py文件,写程序。 from docx import Documentdef replace1(array1):# 替换词典(标签值按实际情况修改)dic {替换词1: array1[0], 替换…

Excel 技巧17 - 如何计算倒计时,并添加该倒计时的数据条(★)

本文讲如何计算倒计时,并添加该倒计时的数据条。 1,如何计算倒计时 这里也要用公式 D3 - TODAY() 显示为下面这个样子的 然后右键该单元格,选 设置单元格格式 然后点 常规 这样就能显示出还书倒计时的日数了。 下拉适用到其他单元格。 2&a…

2025.1.21——八、[HarekazeCTF2019]Avatar Uploader 2(未完成) 代码审计|文件上传

题目来源:buuctf [HarekazeCTF2019]Avatar Uploader 2 一、打开靶机,整理信息 跟Avatar Uploader 1 题目长得一样,先上传相同文件看看情况,另外这道题还有源码,可以看看 二、解题思路 step 1:上传同类…

ChatGPT接入苹果全家桶:开启智能新时代

最近,科技界最重磅的消息莫过于ChatGPT正式接入苹果iOS生态系统!这意味着苹果用户将能够直接在iPhone、iPad和Mac上体验到这款强大的AI代码生成器带来的便利,开启一个全新的智能时代。这篇文章将深入探讨ChatGPT与苹果生态的整合,…

易语言模拟真人鼠标轨迹算法 - 防止游戏检测

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序,它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言,原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势: 模拟…

一部手机如何配置内网电脑同时访问内外网

做过运维的朋友都知道,最麻烦的是运维电脑不能远程,每次都得现场进行维护,明明客户那边有可以访问内网的电脑,怎么操作能将这台电脑能访问跟到外网呢,这样不就能通过远程软件远程了吗?嘿嘿。按以下步骤试试…

直线拟合例子 ,岭回归拟合直线

目录 直线拟合,算出离群点 岭回归拟合直线: 直线拟合,算出离群点 import cv2 import numpy as np# 输入的点 points np.array([[51, 149],[122, 374],[225, 376],[340, 382],[463, 391],[535, 298],[596, 400],[689, 406],[821, 407] ], dtypenp.float32)# 使用…

ansible自动化运维实战--script、unarchive和shell模块(6)

文章目录 一、script模块1.1、功能1.2、常用参数1.3、举例 二、unarchive模块2.1、功能2.2、常用参数2.3、举例 三、shell模块3.1、功能3.2、常用参数3.3、举例 一、script模块 1.1、功能 Ansible 的 script 模块允许你在远程主机上运行本地的脚本文件,其提供了一…

【落羽的落羽 数据结构篇】算法复杂度

文章目录 一、数据结构和算法简介二、算法复杂度1. 时间复杂度2. 空间复杂度 一、数据结构和算法简介 数据结构是计算机存储、组织数据的方式,指相互之间存在一种或多种特定关系的数据元素的集合。没有一种单一的数据结构对所有用途都有用,所以我们要学…

ubuntu16.04 VSCode下cmake+clang+lldb调试c++

VSCode下cmakeclanglldb调试c Ubuntu16.04 安装OpenCV4.5.4 文章目录 VSCode下cmakeclanglldb调试c1.安装clangclangdcmake2、打开VSCode,安装扩展插件3、编译4、Debug4.1 创建launch.json。4.2 配置setting.json 5. vscode安装配置clang-format插件5.1 Linux系统安…

第十五届蓝桥杯大赛软件赛省赛Java 大学 B 组(1、2题)

1.报数游戏 问题描述 小蓝和朋友们在玩一个报数游戏。由于今年是 2024 年,他们决定要从小到大轮流报出是 20或 24 倍数的正整数。前 10 个被报出的数是:20,24,40,48,60,72,80,96,100,120。请问第 202420242024个被报出的数是多少? 答案提交 这是一道结果…

【opencv】第9章 直方图与匹配

第9章 直方图与匹配 9.1 图像直方图概述 直方图广泛运用于很多计算机视觉运用当中,通过标记帧与帧之间显著的边 缘和颜色的统计变化,来检测视频中场景的变化。在每个兴趣点设置一个有相近 特征的直方图所构成“标签”,用以确定图像中的兴趣点。边缘、色…

多版本并发控制:MVCC的作用和基本原理

多版本并发控制:MVCC的作用和基本原理 1、MVCC简介1.1 快照读与当前读的区别1.1.1 快照读1.1.2 当前读 1.2 数据库的读写问题1.3 MVCC的作用 2、MVCC实现原理之ReadView2.1 什么是ReadView2.2 ReadView的设计思路2.3 MVCC整体操作流程 1、MVCC简介 1.1 快照读与当前…

SPDK vhost介绍

目录 1. vhost技术的背景与动机Virtio 介绍virtio-blk数据路径为例 2. vhost技术的核心原理2.1 vhost-kernel2.2 vhost-user举例 2.3 SPDK vhostvhost的优势IO请求处理数据传输控制链路调整 3. SPDK vhost的实现与配置3.1 环境准备3.2 启动SPDK vhost服务3.3 创建虚拟块设备3.4…

LMI Gocator GO_SDK VS2019引用配置

LMI SDK在VS2019中的引用是真的坑爹,总结一下经验,希望后来的人能少走弯路.大致内容如下: (1) 环境变量 (2)C/C 附加包含目录 E:\GWQ\Gocator\GO_SDK\Gocator\GoSdk E:\GWQ\Gocator\GO_SDK\Platform\kApi (3&#…

C语言初阶--折半查找算法

目录 练习1:在一个有序数组中查找具体的某个数字n 练习2:编写代码,演示多个字符从两端移动,向中间汇聚 练习3:简单编写代码实现,模拟用户登录情景,并且只能登录三次 练习4:猜数字…

网安加·百家讲坛 | 樊山:数据安全之威胁建模

作者简介:樊山,锦联世纪教育能源工业互联网数字安全CSM(新能源运维师)课程特聘培训讲师,哈尔滨工业大学(深圳)信飞合创数据合规联合实验室特聘专家,武汉赛博网络安全人才研究中心资深专家;近24年…

基于Springboot + vue实现的在线装修管理系统

“前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站:人工智能学习网站” 💖学习知识需费心, 📕整理归纳更费神。 🎉源码免费人人喜…

利用大型语言模型在量化投资中实现自动化策略

“Automate Strategy Finding with LLM in Quant investment” 论文地址:https://arxiv.org/pdf/2409.06289 摘要 这个新提出的量化股票投资框架,利用大型语言模型(LLMs)与多智能体系统相结合的方法,通过LLMs从包括数…

vue3+uniapp开发鸿蒙初体验

去年7月20号,uniapp官网就已经开始支持鸿蒙应用开发了,话不多说,按照现有规则进行配置实现一下鸿蒙开发效果; 本文基于macOS Monterey 版本 12.6.5实现 开发鸿蒙的前置准备 这里就直接说我的版本: DevEco Studio 5.…