SpringBoot整合Elasticsearch游标查询的示例代码(scroll)
作者:李锋镝的园子 发布时间:2022-02-11 02:02:13
游标查询(scroll)简介
scroll
查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
游标查询会取某个时间点的快照数据。 查询初始化之后索引上的任何变化会被它忽略。 它通过保存旧的数据文件来实现这个特性,结果就像保留初始化时的索引 视图 一样。
启用游标查询可以通过在查询的时候设置参数 scroll
的值为我们期望的游标查询的过期时间。 游标查询的过期时间会在每次做查询的时候刷新,所以这个时间只需要足够处理当前批的结果就可以了,而不是处理查询结果的所有文档的所需时间。 这个过期时间的参数很重要,因为保持这个游标查询窗口需要消耗资源,所以我们期望如果不再需要维护这种资源就该早点儿释放掉。 设置这个超时能够让 Elasticsearch 在稍后空闲的时候自动释放这部分资源。
GET /old_index/_search?scroll=1m
{
"query": { "match_all": {}},
"sort" : ["_doc"],
"size": 1000
}
scroll=1m:保持游标查询窗口一分钟。
返回结果示例:
{
"_scroll_id": "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs=",
"took": 10,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 2633253,
"max_score": 1.0,
"hits": [
{
"_index": "old_index",
"_type": "old_index_type",
"_id": "1",
"_score": 1.0,
"_source": {
...
}
}
]
}
}
这个查询的返回结果包括一个字段 _scroll_id
, 它是一个base64编码的长字符串 。 现在我们能传递字段 _scroll_id
到 _search/scroll
查询接口获取下一批结果:
GET /_search/scroll
{
"scroll": "1m",
"scroll_id" : "cXVlcnlUaGVuRmV0Y2g7NTsxMDk5NDpkUmpiR2FjOFNhNnlCM1ZDMWpWYnRROzEwOTk1OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MTA5OTM6ZFJqYkdhYzhTYTZ5QjNWQzFqVmJ0UTsxMTE5MDpBVUtwN2lxc1FLZV8yRGVjWlI2QUVBOzEwOTk2OmRSamJHYWM4U2E2eUIzVkMxalZidFE7MDs="
}
注意:需要再次设置游标查询过期时间为一分钟。
这个游标查询返回下一批结果。
另外尽管我们指定字段 size
的值为1000
,但是我们有可能取到超过这个值数量的文档。 当查询的时候, 字段 size
作用于单个分片,所以每个批次实际返回的文档数量最大为 size * number_of_primary_shards
。
注意:游标查询每次返回一个新字段 _scroll_id
。每次我们做下一次游标查询, 我们必须把前一次查询返回的字段_scroll_id
传递进去。 当没有更多的结果返回的时候,我们就处理完所有匹配的文档了。
整合
新增以下三个方法:
/**
* 游标查询
* @param params 查询入参
* @param indexName 索引名称
* @param type 索引类型
* @param defaultSort 默认排序
* @param keyMappings 字段映射
* @param keyMappingsMap 索引对应字段映射
* @param scrollTimeInMillis 游标开启的时间
* @return Page
*/
protected Page<Map> commonStartScroll(Map<String, String> params, String indexName, String type, String defaultSort,
Map<Key, FieldDefinition> keyMappings,
Map<String, Map<Key, FieldDefinition>> keyMappingsMap, long scrollTimeInMillis) {
SearchQuery searchQuery = buildSearchQuery(params, indexName, type, defaultSort, keyMappings, keyMappingsMap);
return elasticsearchTemplate.startScroll(scrollTimeInMillis, searchQuery, Map.class);
}
/**
* 游标查询
* @param scrollId 游标ID
* @param scrollTimeInMillis 游标开启的时间
* @return Page
*/
protected Page<Map> commonContinueScroll(String scrollId, long scrollTimeInMillis) {
return elasticsearchTemplate.continueScroll(scrollId, scrollTimeInMillis, Map.class);
}
/**
* 根据游标ID清除游标(提早释放资源,降低ES的负担)
* @param scrollId 游标ID
*/
protected void clearScroll(String scrollId) {
elasticsearchTemplate.clearScroll(scrollId);
}
StoreSearchService
中增加游标查询方法以及清除游标方法:
/**
* 游标查询
* @param params 查询条件
* @return page
*/
public Page<Map> scroll(Map<String, String> params) {
IndexConfig config = indexEntity.getConfigByDocCode(DOC_CODE);
// 如果请求参数包含游标ID,则说明执行翻页操作,否则认为开启新的游标查询
String scrollId = params.getOrDefault(SCROLL_ID, null);
if (StringUtils.isNotBlank(scrollId)) {
return commonContinueScroll(params.get(scrollId), config.getScrollTimeInMillis());
}
return commonStartScroll(params, config.getIndexName(), config.getType(), DEFAULT_SORT,
keyMappings, keyMappingsMap, config.getScrollTimeInMillis());
}
public void clearScroll(String scrollId) {
super.clearScroll(scrollId);
}
对外暴露接口:
@PostMapping("/scroll")
public ResponseResult scroll(@RequestBody Map<String, String> params) {
return ResponseResult.success(storeSearchService.scroll(params));
}
@GetMapping("/scroll/clear/{scrollId}")
public ResponseResult clearScroll(@PathVariable String scrollId) {
storeSearchService.clearScroll(scrollId);
return ResponseResult.success(null);
}
游标查询分为开启和继续两个步骤,接口/scroll
中根据_scrollId
判断为开启游标查询还是继续游标查询。
若条件允许的话,尽量将游标查询及时关闭,以释放ES集群的资源,降低负担。
源码
Git项目地址:https://github.com/lifengdi/search
原文链接:https://www.lifengdi.com/archives/article/2119
来源:https://www.cnblogs.com/lifengdi/p/13827262.html
猜你喜欢
- 现在很多的网站都提供有用户注册功能, 通常我们注册成功之后就会收到一封来自注册网站的邮件。邮件里面的内容可能包含了我们的注册的用户名和密码以
- 本文实例为大家分享了java实现简单的图书管理系统的具体代码,供大家参考,具体内容如下一、项目分布Book类: 定义了书的一些属性(书名,作
- Springmvc+hibernate成为现在很多人用的框架整合,最近自己也在学习摸索,由于我们在开发项目中很多项目都用到列表分页功能,在此
- 在spring boot中,简单几步,使用spring AOP实现一个 * :1、引入依赖:<dependency> &nbs
- 本文实例为大家分享了Unity实现攻击范围检测并绘制检测区域的具体代码,供大家参考,具体内容如下一、圆形检测using System.Col
- 一.关于使用Mybatisplus自带的selectById和insert方法时的一些问题1.selectById的问题(1).表的主键列名
- 介绍该系统有三个角色,分别是:普通用户、房屋中介、管理员。普通用户的功能:浏览房屋信息、预约看房、和中介聊天、申请成为中介等等。房屋中介的功
- 自定义starterSpringBoot中的starter是一种非常重要的机制,能够抛弃以前繁杂的配置,将其统一集成进 starter,应用
- 线程池中ThreadGroup的坑在Java中每一个线程都归属于某个线程组管理的一员,例如在主函数main()主工作流程中产生一个线程,则产
- 1、前言随着技术的发展,微信的一系列服务渗透进了我们的生活,但是我们应该怎样进行微信方面的开发呢。相信很多的小伙伴们都很渴望知道吧。这篇文章
- 1、使用场景 因为最近项目需要国际化,需要能够支持多种国际化语言,目前需要支持三种(法
- 规则1(无继承情况下):对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、
- selectMaps和selectList的区别selectList查询部分字段,会返回所有的,没查询的值为nullselectMaps 只
- 原理解析:利用RandomAccessFile在本地创建一个随机访问文件,文件大小和服务器要下载的文件大小相同。 根据线程的数量(假设有三个
- 概要应同学邀请,演示如何使用 PyQt5 内嵌浏览器浏览网页,并注入 Javascript 脚本实现自动化操作。下面测试的是一个廉价机票预订
- 1.Spring IOC容器可以管理bean的生命周期,Spring允许在bean生命周期内特定的时间点执行指定的任务。2.Spring I
- 一、SpringCache介绍Spring Cache 是一个优秀的缓存组件。自Spring 3.1起,提供了类似于@Transaction
- 在spring的注解 @RequestMapping 之下可以直接获取 HttpServletRequest 来获得诸如request he
- 前言前面的篇幅里有提到通过InitializingBean和Disposable等接口可以对bean的初始化和销毁做一些自定义操作,那么有一
- 前 言🍉 作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端☕专栏简介:深入、全面、系统的介绍消息中间件🌰 文章简介