[5.1]帮学弟解决了一个生产环境ES深分页SearchAfter Date类型字段排序的问题-这个坑你早晚会遇到

我们知道elasticsearch可以通过SearchAfter的方式解决深分页问题。SearchAfter原…

我们知道elasticsearch可以通过SearchAfter的方式解决深分页问题。SearchAfter原理就是通过维护一个实时游标来避免scroll的缺点,它可以用于实时请求和高并发场景。

目录

1、案发现场

2、初步推断

3、亮出杀手锏

3.1 SearchAfter调试过程

3.1.1 测试索引

3.1.2 测试方法

3.2 跟踪关键代码

3.2.1 重大发现

3.2.2 按图索骥

4、解决方案

方案一:将排序的字符串或Date类型转化为毫秒

方案二:直接从Hits返回数据中获取


1、案发现场

前两天有一个学弟,找我解决了一个关于ES深分页SearchAfter支持Date类型排序的问题。

报错信息如下:

ES源码SearhAfter不支持日期排序吗? 对这一点我表示怀疑。୧(๑•̀◡•́๑)૭

2、初步推断

我找学弟看了下ES定义的createTime类型,如下:

从异常异常信息提示看,应该是String类型无法转化Date类型导致的。

当时的第一反应是,把传入的字符串转化为Date类型,这样不就能支持了吗?

~~ 报错依然存在……

当有排序字段时,ES的SearchAfter会执行这么一段代码:

我们会发现,for循环中只有String、Text、Long、Integer、Short、Byte、Double、Float和Boolean这9种类型。

看来转Date这条路行不通,似乎一切显示这个错误出现的又是那么的理所当然~~😡😡😡

好吧,看看换个别的思路能不能发现什么线索。

3、亮出杀手锏

作为一名老司机,根据多年玩ES的经验,这个问题不简单。那就直接祭出杀手锏吧~~

撸Demo代码并调试跟踪 🌶🌶🌶。

具体 Elasticsearch CRUD 示例在下一篇文章会讲到。今天我们先来说下关键问题点以及解决方案。

3.1 SearchAfter调试过程

3.1.1 测试索引

3.1.2 测试方法

3.2 跟踪关键代码

看代码: SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);

说明:此处使用了ES 高级API。

3.2.1 重大发现

我发现DBug的内容中,除了返回createTime的字符串值(2022-05-02 12:55:09)之外,外层节点还有一个sort字段值数组 ~~ 一大喜讯 🎉🎉🎉。

返回内容竟然:把date字符串转化为了long类型的时间戳,好神奇。

如果这个时间戳能用起来,前面的那段ES源码 setSortValues方法不就可以用了吗?

此时,我们还得一探究竟:看看ES是在什么位置做了这么友好的转化?

这个sort字段目前就是我们要重点研究的对象了。

3.2.2 按图索骥

date 字段被转为毫秒当作排序依据。于是我继续跟踪源码。

关键代码位置: RestHighLevelClient.internalPerformRequest。

在此位置使用了Apache的HttpResponse对象,直接用工具类看看从服务端返回的内容是什么?EntityUtils.toString(response.getEntity())。

原来是在服务器端,就对这个sort字段进行了处理 :ES服务端会对排序字段进行转化:date 字段会被转为毫秒。

为什么说是服务端呢?

我们从管理端直接查询,看返回内容是否一样?

查询条件

查询结果

果真是从服务器端返回的数据。(待后续相关ES文章老王会深究服务端的具体实现~~暂且不表🤗🤗🤗)

那从上面的分析,解决方案就不言而喻了。

4、解决方案

方案一:将排序的字符串或Date类型转化为毫秒

给大家提供一个字符串转毫秒的工具类。(针对已经是字符串的代码)

方案二:直接从Hits返回数据中获取

SearchHit last = searchHits[searchHits.length – 1];

builder.searchAfter(last.getSortValues());

👏🏻👏🏻👏🏻 完毕!

如果有需要深入学习ES相关知识的朋友,可持续关注老王,后续精彩继续!

本文来自网络,不代表软粉网立场,转载请注明出处:https://www.rfff.net/p/1187.html

作者: HUI

发表评论

您的电子邮箱地址不会被公开。

返回顶部