快速掌握Elasticsearch检索之二:滚动查询(scrool)获取全量数据(golang)

Elasticsearch8.17.0在mac上的安装

Kibana8.17.0在mac上的安装

Elasticsearch检索方案之一:使用from+size实现分页

1、滚动查询的使用场景

滚动查询区别于上一篇文章介绍的使用from、size分页检索,最大的特点是,它能够检索超过10000条外的所有文档,可以理解为是一种全量检索的技术方案,也正是因为这种特性,使得滚动查询的代价非常高昂,检索过程消耗大量的内存,所以对于实时检索的场景,滚动查询是不适用的。

那滚动查询使用在什么场景呢?主要是应用在离线、检索全量数据,对于实时性要求不高的场景,比如一个数据平台,前台页面展示的数据用来预览,可以使用from+size分页查询,以提升检索效率以及平台的用户体验,如果还需要检索全量数据用于二次使用,那么后台离线检索全量就需要使用滚动查询以获取到全量数据,这将是一个耗费大量资源和时间的过程。

2、使用Kibana直观体验滚动查询

初始化滚动查询:

GET /new_tag_202411/_search?scroll=1m
{"size": 10,"sort":[{"doc_id":{"order": "asc"}}]
}

检索条件设置返回2条数据,按【doc_id】字段升序排列,doc_id分别为1-10的文档。

scroll=1m,表示Elasticsearch允许等待的最长时间是1分钟,如果在一分钟之内,接下来的 scroll 请求没有到达的话,那么当前请求的上下文将会失效:

 从上图返回可以看出,有一个【_scroll_id】字段,这个字段非常重要,接下来的滚动查询需要使用这个字段:

第一次滚动,返回doc_id从11开始的数据,第二次滚动时,需要使用第一次滚动返回的【_scroll_id】替换滚动请求,数据从doc_id为21的数据开始返回,之后循环这个过程,直到检索到全部数据。

注意一点,在测试过程中,我创建了多次滚动查询,发现scrool_id特别像,大家别误以为scrool_id没变,比如以下三个scrool_id,每个id只有3个字符不一样:

FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFng3akdDTWthVFZLVTE0ODhLdGdaR1EAAAAAAAAWbhZZZEloTnlyU1FGaTgxQV9QR1pXTUdR

FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFng3akdDTWthVFZLVTE0ODhLdGdaR1EAAAAAAAActhZZZEloTnlyU1FGaTgxQV9QR1pXTUdR

FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFng3akdDTWthVFZLVTE0ODhLdGdaR1EAAAAAAAAjDxZZZEloTnlyU1FGaTgxQV9QR1pXTUdR

3、代码实现滚动查询(golang)

首先是初始化一个滚动查询:

res, err := client.Search(client.Search.WithIndex("new_tag_202411"),client.Search.WithBody(strings.NewReader(dslQuery.BuildJson())),client.Search.WithScroll(time.Minute*1),
)

这行代码:

client.Search.WithScroll(time.Minute*1)

就是在设置滚动查询上下文的有效时间,其他几行很容易理解。

这几行代码执行完成后,除了能拿到检索数据,还能拿到scroll_id。之后就可以进行滚动查询:

for {docs = Documents{}res, err = client.Scroll(client.Scroll.WithScrollID(scrollId),client.Scroll.WithScroll(time.Minute),)if err != nil {fmt.Println("scroll err:", err.Error())return}err = json.NewDecoder(res.Body).Decode(&docs)if err != nil {fmt.Println("json decode err:", err)return}if len(docs.Hits.Hits) == 0 {break}fmt.Println("search count:", len(docs.Hits.Hits))scrollId = docs.ScrollID
}

这里要注意的一点是,循环滚动时,每个轮次,必须更新scrool_id为上一次滚动返回的值,如上面最后一行代码。

L17-L19行的代码,表示已经查出所有数据,本次没有数据了,同时循环结束。

4、一个必须要考虑的问题

对于滚动查询,前面也说过,会创建一个上下文,当es中存在的上下文数量超过一定限制后,将无法再次创建滚动查询,从而无法检索数据,这个【限制】es默认是500个,我们可以通过es的api查看当前系统中已经创建的上下文数量:

GET /_nodes/stats/indices/search

默认情况下,只要【open_contexts】值小于500,都能正常进行滚动查询,如果已经创建了500个上下文,就会出现问题,下面测试一下,利用代码,创建500个上下文:

 如上图,上下文已经创建500个,运行代码,再次执行滚动查询的动作:

无法查出任何数据,但是以下代码也无任何的报错:

res, err := client.Search(client.Search.WithIndex("new_tag_202411"),client.Search.WithBody(strings.NewReader(dslQuery.BuildJson())),client.Search.WithScroll(time.Minute*100),
)
if err != nil {fmt.Println("search err:", err.Error())return
}

没有走到err分支,经过调试发现,res的结构中的http状态码变了,我们加一行打印:

res, err := client.Search(client.Search.WithIndex("new_tag_202411"),client.Search.WithBody(strings.NewReader(dslQuery.BuildJson())),client.Search.WithScroll(time.Minute*100),)if err != nil {fmt.Println("search err:", err.Error())return}fmt.Println("resp code:", res.StatusCode)err = json.NewDecoder(res.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}

 运行结果如下:

状态码由正常值0变成了429,所以,在执行滚动查询时,我们需要加上对状态码的判断,以捕获到上下文超限的情况,否则没有检索到数据,还以为系统出bug了呢。

这个问题就是滚动查询的一个短板,系统用户量大了,发起滚动查询一旦超过500,就会影响用户检索数据,当然了,es还是有其他解决方案来进行全量的数据检索,还是那句话,下一篇文章再写。

5、所有代码

github:GitHub - liupengh3c/career 

代码位于以下文件:

https://github.com/liupengh3c/career/blob/main/elastic/scrool/main.go

代码也粘过来吧:

package mainimport ("fmt""os""strings""time""github.com/elastic/go-elasticsearch/v8"jsoniter "github.com/json-iterator/go""github.com/liupengh3c/esbuilder"
)// 最外层数据结构
type Documents struct {ScrollID string      `json:"_scroll_id"`Shards   Shards      `json:"_shards"`Hits     HitOutLayer `json:"hits"`TimedOut bool        `json:"timed_out"`Took     int         `json:"took"`
}
type Shards struct {Failed     int `json:"failed"`Skipped    int `json:"skipped"`Successful int `json:"successful"`Total      int `json:"total"`
}
type HitOutLayer struct {Hits     []Hits  `json:"hits"`MaxScore float64 `json:"max_score"`Total    Total   `json:"total"`
}
type Hits struct {ID     string         `json:"_id"`Index  string         `json:"_index"`Score  float64        `json:"_score"`Source map[string]any `json:"_source"`Type   string         `json:"_type"`
}
type Total struct {Relation string `json:"relation"`Value    int    `json:"value"`
}func main() {client, err := NewEsClient()if err != nil {fmt.Println("create client err:", err.Error())return}fmt.Println("connect success")for i := 0; i < 510; i++ {ScrollSearch(client)}
}
func NewEsClient() (*elasticsearch.Client, error) {cert, _ := os.ReadFile("/Users/liupeng/Documents/study/elasticsearch-8.17.0/config/certs/http_ca.crt")client, err := elasticsearch.NewClient(elasticsearch.Config{Username:  "elastic",Password:  "XBS=adqa799j_Aoz=A+h",Addresses: []string{"https://127.0.0.1:9200"},CACert:    cert,})if err != nil {// fmt.Println("create client err:", err.Error())return client, err}return client, nil
}func ScrollSearch(client *elasticsearch.Client) {var json = jsoniter.ConfigCompatibleWithStandardLibrarydocs := Documents{}dslQuery := esbuilder.NewDsl()boolQuery := esbuilder.NewBoolQuery()dslQuery.SetOrder(esbuilder.NewSortQuery("doc_id", "asc"))dslQuery.SetQuery(boolQuery)dslQuery.SetSize(10000)res, err := client.Search(client.Search.WithIndex("new_tag_202411"),client.Search.WithBody(strings.NewReader(dslQuery.BuildJson())),client.Search.WithScroll(time.Minute*20),)if err != nil {fmt.Println("search err:", err.Error())return}err = json.NewDecoder(res.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}fmt.Println("search count:", len(docs.Hits.Hits))scrollId := docs.ScrollIDfor {docs = Documents{}res, err = client.Scroll(client.Scroll.WithScrollID(scrollId),client.Scroll.WithScroll(time.Minute),)if err != nil {fmt.Println("scroll err:", err.Error())return}err = json.NewDecoder(res.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}defer res.Body.Close()if res.StatusCode == 429 {fmt.Println("scroll contexts is more than 500")return}if len(docs.Hits.Hits) == 0 {break}fmt.Println("search count:", len(docs.Hits.Hits))scrollId = docs.ScrollID}client.ClearScroll(client.ClearScroll.WithScrollID(scrollId),)
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【分布式文件存储系统Minio】2024.12保姆级教程

文章目录 1.介绍1.分布式文件系统2.基本概念 2.环境搭建1.访问网址2.账号密码都是minioadmin3.创建一个桶4.**Docker安装miniomc突破7天限制**1.拉取镜像2.运行容器3.进行配置1.格式2.具体配置 4.查看桶5.给桶开放权限 3.搭建minio模块1.创建一个oss模块1.在sun-common下创建2.…

2021.12.28基于UDP同信的相关流程

作业 1、将TCP的CS模型再敲一遍 服务器 #include <myhead.h> #define PORT 8888 #define IP "192.168.124.123" int main(int argc, const char *argv[]) {//创建套接字//绑定本机IP和端口号//监听客户端请求//接收客户端连接请求//收发消息//创建套接字int…

StarRocks 存算分离在得物的降本增效实践

编者荐语&#xff1a; 得物优化数据引擎布局&#xff0c;近期将 4000 核 ClickHouse 迁移至自建 StarRocks&#xff0c;成本降低 40%&#xff0c;查询耗时减半&#xff0c;集群稳定性显著提升。本文详解迁移实践与成果&#xff0c;文末附丁凯剑老师 StarRocks Summit Asia 2024…

vue视频录制 限制大小,限制时长

<template><div style"height: 100vh;background: #000;"><span style"color: #fff;font-size: 18px;">切换数量&#xff1a;{{ devices.length }}</span><video ref"video" autoplay muted playsinline></vid…

若依框架之简历pdf文档预览功能

一、前端 &#xff08;1&#xff09;安装插件vue-pdf&#xff1a;npm install vue-pdf &#xff08;2&#xff09;引入方式&#xff1a;import pdf from "vue-pdf"; &#xff08;3&#xff09;components注入方式&#xff1a;components:{pdf} &#xff08;4&…

永磁同步电机负载估计算法--自适应龙伯格观测器

一、原理介绍 龙贝格扰动观测器的参数可以通过带宽配置法进行整定&#xff0c;将观测器带宽设为L&#xff0c;选取大的L可以加快观测器的收敛速度&#xff0c;但是L过大会导致系统阶跃响应出现超调、稳态性能差等问题。因此&#xff0c;在龙贝格观测器中引入表征系统状态变量x…

Python机器学习笔记(十七、分箱、离散化、线性模型与树)

数据表示的最佳方法&#xff1a;取决于数据的语义&#xff0c;所使用的模型种类。 线性模型与基于树的模型&#xff08;决策树、梯度提升树和随机森林&#xff09;是两种成员很多同时又非常常用的模 型&#xff0c;它们在处理不同的特征表示时就具有非常不同的性质。我们使用w…

Spring Boot介绍、入门案例、环境准备、POM文件解读

文章目录 1.Spring Boot(脚手架)2.微服务3.环境准备3.1创建SpringBoot项目3.2导入SpringBoot相关依赖3.3编写一个主程序&#xff1b;启动Spring Boot应用3.4编写相关的Controller、Service3.5运行主程序测试3.6简化部署 4.Hello World探究4.1POM文件4.1.1父项目4.1.2父项目的父…

嵌入式入门Day35

网络编程 Day2 套接字socket基于TCP通信的流程服务器端客户端TCP通信API 基于UDP通信的流程服务器端客户端 作业 套接字socket socket套接字本质是一个特殊的文件&#xff0c;在原始的Linux中&#xff0c;它和管道&#xff0c;消息队列&#xff0c;共享内存&#xff0c;信号等…

安卓系统主板_迷你安卓主板定制开发_联发科MTK安卓主板方案

安卓主板搭载联发科MT8766处理器&#xff0c;采用了四核Cortex-A53架构&#xff0c;高效能和低功耗设计。其在4G网络待机时的电流消耗仅为10-15mA/h&#xff0c;支持高达2.0GHz的主频。主板内置IMG GE832 GPU&#xff0c;运行Android 9.0系统&#xff0c;内存配置选项丰富&…

centos,789使用mamba快速安装R及语言包devtools

如何进入R语言运行环境请参考&#xff1a;Centos7_miniconda_devtools安装_R语言入门之R包的安装_r语言devtools包怎么安装-CSDN博客 在R里面使用安装devtools经常遇到依赖问题&#xff0c;排除过程过于费时&#xff0c;使用conda安装包等待时间长等。下面演示centos,789都是一…

人工智能(AI)简史:推动新时代的科技力量

一、人工智能简介 人工智能&#xff08;AI&#xff0c;Artificial Intelligence&#xff09;是计算机科学的一个分支&#xff0c;旨在研究和开发可以模拟、扩展或增强人类智能的系统。它涉及多种技术和方法&#xff0c;包括机器学习、深度学习、自然语言处理&#xff08;NLP&a…

【笔记】在虚拟机中通过apache2给一个主机上配置多个web服务器

&#xff08;配置出来的web服务器又叫虚拟主机……&#xff09; 下载apache2 sudo apt update sudo apt install apache2 &#xff08;一&#xff09;ip相同 web端口不同的web服务器 进入 /var/www/html 创建站点一和站点二的目录文件&#xff08;目录文件名自定义哈&#x…

linux装git

前言 以 deepin 深度系统为例&#xff0c;安装命 令行版 Git 非常简单。 安装 注意&#xff1a;需要输入账号密码&#xff0c;否则无法进行。 打开终端&#xff0c;执行如下命令即可。 sudo apt-get install git成功 如下图所示&#xff0c;输入 git &#xff0c;命令识别即…

【Spark】架构与核心组件:大数据时代的必备技能(下)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《大数据前沿&#xff1a;技术与应用并进》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是Apache Spark 2、Spark 的应用场景&…

NLP中的神经网络基础

一&#xff1a;多层感知器模型 1&#xff1a;感知器 解释一下&#xff0c;为什么写成 wxb>0 &#xff0c;其实原本是 wx > t ,t就是阈值&#xff0c;超过这个阈值fx就为1&#xff0c;现在把t放在左边。 在感知器里面涉及到两个问题&#xff1a; 第一个&#xff0c;特征提…

第十一章 图论

题目描述&#xff1a; 阿里这学期修了计算机组织和架构课程。他了解到指令之间可能存在依赖关系&#xff0c;比如WAR&#xff08;读后写&#xff09;、WAW、RAW。 如果两个指令之间的距离小于安全距离&#xff0c;则会导致危险&#xff0c;从而可能导致错误的结果。因此&#…

嵌入式系统 第七讲 ARM-Linux内核

• 7.1 ARM-Linux内核简介 • 内核&#xff1a;是一个操作系统的核心。是基于硬件的第一层软件扩充&#xff0c; 提供操作系统的最基本的功能&#xff0c;是操作系统工作的基础&#xff0c;它负责管理系统的进程、内存、设备驱动程序、文件和网络系统&#xff0c; 决定着系统的…

win11蓝屏死机 TPM-WMI

1. 打开win11的事件查看器&#xff0c;定位错误 最近两次都是 KB5016061&#xff1a;安全启动数据库和 DBX 变量更新事件 - Microsoft 支持 事件源 TPM-WMI 事件 ID 1796 2. 解决方案 打开注册表&#xff1a;计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Contro…

Linux命令——3.网络与用户

文章目录 一、网络1.网络测试与诊断2.网络接口配置3.无线网络配置4.防火墙与网络管理6.防火墙管理1&#xff09;firewalld命令2&#xff09;iptables命令 二、用户和群组1.管理员模式2.用户账户管理1&#xff09;useradd创建2&#xff09;usermod修改3&#xff09;userdel 删除…