Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)

Elasticsearch8.17.0在mac上的安装

Kibana8.17.0在mac上的安装

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

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

1、search_after检索

在前面的文章介绍了from+size的普通分页查询,以及scroll滚动查询获取全量数据,其弥补了from+size只能检索1W条以内的数据的缺憾,但是滚动查询本身也存在缺陷,当es滚动上下文大于500,则无法再次进行检索,此时search_after应运而生,它是带着使命来的。

2、使用Kibana了解search_after使用方法

说明:本地es中的数据共11000条,doc_id字段从1-11000,方便说明问题。

首先构造一个排序查询:

GET /new_tag_202411/_search
{"size": 10,"sort": [{"doc_id": {"order": "asc"}}]
}

这个检索请求发出后,返回的数据【doc_id】从1开始,每次10条,也就是返回doc_id从1-10的数据,这里着重列出返回的第10条数据:

为什么列出第10条数据,因此search_after需要第10条(检索出的最后一条)数据的sort字段的值作为输入:

GET /new_tag_202411/_search
{"size": 10,"sort": [{"doc_id": {"order": "asc"}}],"search_after": [10] // 将第一个检索请求返回的sort字段的值放入此字段
}

这时,检索返回将从doc_id为11的数据开始返回:

 

之后再将本次返回的最后一条数据sort字段放入下一次的检索条件中,继续下一次的检索,从此周而复始,直到检索完全部数据,这个逻辑和scroll滚动查询替换scroll_id的道理是一样的。

注意,使用search_after进行查询时,from必须设置为0或者-1,否则会报错:

3、esbuilder自研dsl库支持search_after字段

我自己开发的esbuilder库之前没有支持search_after字段,因为之前不知道这个功能😄😄,库地址:

github.com/liupengh3c/esbuilder

search_after字段为一个数组,数组类型都为常规的整形、字符串,相对来说比较简单,因此在dsl结构体中直接增加该字段:

type dsl struct {QueryDsl    query    `json:"query"`Source      []string `json:"_source,omitempty"`Size        int64    `json:"size,omitempty"`From        int64    `json:"from,omitempty"`OrderItems  []query  `json:"sort,omitempty"`TrackTotal  bool     `json:"track_total_hits,omitempty"`SearchAfter []any    `json:"search_after,omitempty"`
}

之后实现reciver method,支持对该字段进行赋值:

func (dsl *dsl) SetSearchAfter(searchAfter []any) *dsl {dsl.SearchAfter = searchAfterreturn dsl
}

本小节的内容与search_after的使用关系不大,看不明白也没关系,可以跳过,如果想了解的话可以留言,看到后我一定会第一时间回复。

4、利用search_after全量检索的代码实现(golang)

第一步构造一个带有排序的检索请求,排序的字段最好是每个文档的值唯一:

第二步,设计死循环进行查询,同时获取每次检索结果最后一条sort字段的值赋值给search_after字段,直接检索出所有数据:

for {fmt.Println(dslQuery.BuildJson())search := esapi.SearchRequest{Index: []string{"new_tag_202411"},Body:  strings.NewReader(dslQuery.BuildJson()),}resp, err = search.Do(context.Background(), client)if err != nil {fmt.Println("search err:", err.Error())return}err = json.NewDecoder(resp.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}if len(docs.Hits.Hits) == 0 {fmt.Println("no more data")break}fmt.Println("检索数据数量:", len(docs.Hits.Hits), "doc_id:", docs.Hits.Hits[len(docs.Hits.Hits)-1].Source["doc_id"])dslQuery.SetSearchAfter(docs.Hits.Hits[len(docs.Hits.Hits)-1].Sort)
}

其中,最重要的一行代码:

dslQuery.SetSearchAfter(docs.Hits.Hits[len(docs.Hits.Hits)-1].Sort)

这行代码是在每轮次中更新search_after参数,否则无法实现滚动查询的效果,无法检索全量数据。

为了方便观察,我们将size设置为1000,每次检索1000条,增加打印dsl语句以及检索到数据量、doc_id值:

从上面的打印可以看到,search_after的值一直在更新,这样才能达到检索全量的目标,doc_id值的变化也可以从侧面看出整个全量检索的过程,目标达成啦~~~~~。

5、全部实例代码

github地址:

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

代码:

package main
import ("context""fmt""os""strings""time""github.com/elastic/go-elasticsearch/v7/esapi""github.com/elastic/go-elasticsearch/v8"jsoniter "github.com/json-iterator/go""github.com/liupengh3c/esbuilder"
)
// 最外层数据结构
type Documents struct {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"`Sort   []any          `json:"sort"`
}
type Total struct {Relation string `json:"relation"`Value    int    `json:"value"`
}
func main() {SearchFromSize()
}
func SearchFromSize() {st := time.Now()defer func() {fmt.Println("cost:", time.Since(st).Milliseconds(), "ms")}()var json = jsoniter.ConfigCompatibleWithStandardLibrarydocs := Documents{}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:  "xpE4DQGWE9bCkoj7WXYE",Addresses: []string{"https://127.0.0.1:9200"},CACert:    cert,})if err != nil {fmt.Println("create client err:", err.Error())return}dslQuery := esbuilder.NewDsl()boolQuery := esbuilder.NewBoolQuery()boolQuery.Filter(esbuilder.NewRangeQuery("doc_id").Gte(1))dslQuery.SetQuery(boolQuery)dslQuery.SetFrom(0)dslQuery.SetSize(1000)dslQuery.SetOrder(esbuilder.NewSortQuery("doc_id", "asc"))dsl := dslQuery.BuildJson()search := esapi.SearchRequest{Index: []string{"new_tag_202411"},Body:  strings.NewReader(dsl),}resp, err := search.Do(context.Background(), client)if err != nil {fmt.Println("search err:", err.Error())return}err = json.NewDecoder(resp.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}fmt.Println(docs.Hits.Hits[len(docs.Hits.Hits)-1].Sort)dslQuery.SetSearchAfter(docs.Hits.Hits[len(docs.Hits.Hits)-1].Sort)for {fmt.Println(dslQuery.BuildJson())search := esapi.SearchRequest{Index: []string{"new_tag_202411"},Body:  strings.NewReader(dslQuery.BuildJson()),}resp, err = search.Do(context.Background(), client)if err != nil {fmt.Println("search err:", err.Error())return}err = json.NewDecoder(resp.Body).Decode(&docs)if err != nil {fmt.Println("decode err:", err.Error())return}if len(docs.Hits.Hits) == 0 {fmt.Println("no more data")break}fmt.Println("检索数据数量:", len(docs.Hits.Hits), "doc_id:", docs.Hits.Hits[len(docs.Hits.Hits)-1].Source["doc_id"])dslQuery.SetSearchAfter(docs.Hits.Hits[len(docs.Hits.Hits)-1].Sort)}
}

 

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

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

相关文章

网易企业邮箱登陆:保障数据安全

网易企业邮箱是一款为企业提供安全可靠的电子邮件服务的工具。通过网易企业邮箱,企业可以实现员工之间的高效沟通和信息共享,同时保障数据的安全性。 企业邮箱的安全性是企业信息保护的重要组成部分。网易企业邮箱采用了多层加密技术,确保邮件…

3.银河麒麟V10 离线安装Nginx

1. 下载nginx离线安装包 前往官网下载离线压缩包 2. 下载3个依赖 openssl依赖,前往 官网下载 pcre2依赖下载,前往Git下载 zlib依赖下载,前往Git下载 下载完成后完整的包如下: 如果网速下载不到请使用网盘下载 通过网盘分享的文件…

Hive其十,优化和数据倾斜

目录 Hive优化 1、开启本地模式 2、explain分析SQL语句 3、修改Fetch操作 4、开启hive的严格模式【提高了安全性】 5、JVM重用 6、分区、分桶以及压缩 7、合理设置map和reduce的数量 合理设置map数量: 设置合理的reducer的个数 8、设置并行执行 9、CBO优…

uniapp通过v-if进行判断时,会出现闪屏?【已解决】

1.问题:按钮切换时,通过v-if来判断,会出现闪烁情况,影响用户体验 2.v-if 闪烁问题可能的原因 ‌条件切换频繁‌:如果 v-if 指令的条件在短时间内频繁切换,会导致元素不断被销毁和重新创建,从而…

ida的使用

一.ida的基本设置 在IDA的安装根目录下有许多文件夹,各个文件夹存储不同的内容 1.目录结构 cfg:包含各种配置文件,基本IDA配置文件ida.cfg,GUI配置文件idagui.cfg,文本模式用户界面配置文件idatui.cfg, idc:包含…

Faster R-CNN

文章目录 摘要Abstract1. 引言2. 框架2.1 RPN2.1.1 网络结构2.1.2 损失函数2.1.3 训练细节 2.2 训练过程 3. 创新点和不足3.1 创新点3.2 不足 参考总结 摘要 Faster R-CNN是针对Fast R-CNN缺点改进的目标检测模型。为了解决候选区域生成耗时长的问题,Faster R-CNN提…

嵌入式AI STM32部署卷积神经网络的魔法棒

基于STM32部署卷积神经网络控制设备方案-AI项目-STM32部署卷积神经网络方案-红外信号复制方案-轨迹识别 项目包含下述内容 硬件部分、PCB制板、BOM表文件等等 (Hardware)外壳、3D打印文件 (3D_print)软件程序、用于电子法棒的软件程序 AI Keil等等(Software)QT上位机动作识别…

GCP Cloud Observability 是什么,有什么使用场景

GCP Cloud Observability 是 Google Cloud Platform (GCP) 提供的一组工具和服务,用于监控、日志记录、追踪和调试应用程序和基础设施的健康和性能。通过收集和分析遥测数据(如指标、日志和追踪信息),Cloud Observability 有助于理…

UE4_用户控件_2_按钮的动态效果

效果展示: 操作步骤: 1、新建一个触发Actor,更名为BP_EventTrigger。 这个蓝图类可以拖拽到场景中好多次,生成好多实例。但是我希望每次触发创建的用户控件都是不同的。添加Capsule Collision。 修改胶囊体半高和半径都为156 BP_…

Bert各种变体——RoBERTA/ALBERT/DistillBert

RoBERTa 会重复一个语句10次,然后每次都mask不同的15%token。丢弃了NSP任务,论文指出NSP任务有时甚至会损害性能。使用了BPE ALBERT 1. 跨层参数共享 可以共享多头注意力层的参数,或者前馈网络层的参数,或者全部共享。 实验结果…

ADC(三):注入组的使用

有关ADC的基础知识请参考标准库入门教程 ADC(三):注入组的使用 1、规则组软件触发注入组自动注入2、规则组外部触发注入组自动注入3、规则组软件触发注入组外部触发(TIM2_CC1)4、规则组软件触发注入组外部触发&#xf…

代码随想录算法【Day4】

Day4 1.链表的题目,要在草稿纸上模拟清晰后就简单了 2.双指针更加灵活的应用。 3.环形链表多练习。 24. 两两交换链表中的节点 class Solution { public:ListNode* swapPairs(ListNode* head) {ListNode* _dummyHead new ListNode(0); //虚拟头结点_dummyHead…

(南京观海微电子)——GH7009开机黑屏案例分析

一、 现象描述: 不良现象: LVDS模组,开机大概2秒后就黑屏。 二、问题分析 等主机进入Kernel 后做以下测试: 1、手动reset LCM 后 可以显示正常; 总结: 1)uboot 部分HS 太窄,仅有4个clk宽度&am…

PaddleOCR文字识别模型的FineTune

一、paddleOCR paddle框架为百度开发的深度学习框架,其中对于文字检测、识别具有较为便利的开发条件。同时PaddleOCR文字识别工具较为轻量化,并可按照任务需求进行model的finetune,满足实际的业务需求。 源码来源:githubOCR 在gi…

Spark生态圈

Spark 主要用于替代Hadoop中的 MapReduce 计算模型。存储依然可以使用 HDFS,但是中间结果可以存放在内存中;调度可以使用 Spark 内置的,也可以使用更成熟的调度系统 YARN 等。 Spark有完善的生态圈: Spark Core:实现了…

影刀进阶指令 | Kimi (对标ChatGPT)

文章目录 影刀进阶指令 | Kimi (对标ChatGPT)一. 需求二. 流程三. 实现3.1 流程概览3.2 流程步骤讲解1\. 确定问题2\. 填写问题并发送3\. 检测答案是否出完 四. 运维 影刀进阶指令 | Kimi (对标ChatGPT) 简单讲讲RPA调用kimi实现…

Spring Security3.0.2版本

前言: 通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往…

--spring.profiles.active=prod

rootproduct-qualification:~# ps -ef | grep java root 5110 1 3 16:57 ? 00:00:54 java -jar productQualification.jar --spring.profiles.activeprod root 6476 5797 0 17:26 pts/0 00:00:00 grep --colorauto java好的,你使用 ps …

力扣矩阵-算法模版总结

lc-73.矩阵置零-(时隔14天)-12.27 思路:(23min22s) 1.直接遍历遇0将行列设0肯定不行,会影响后续判断,题目又要求原地算法,那么进一步考虑是否可以将元素为0,其行列需要设为0的位置给存储下来,最后再遍历根据…

Markov test笔记

补充知识 来源于数学之美第五章: 到了 19 世纪,概率论的发展从相对静止的随机变量的研究发展到随机变量的时间序列 ( s 1 , s 2 , s 3 , … ) (s_1, s_2, s_3, \dots) (s1​,s2​,s3​,…),即随机过程(动态的)。这在…