Elasticsearch滚动查询+线程池处理大批量数据

什么是滚动查询?

scroll 查询 可以用来对 Elasticsearch 有效地执行大批量的文档查询,而又不用付出深度分页那种代价。
scroll查询允许我们 先做查询初始化,然后再批量地拉取结果。 这有点儿像传统数据库中的 游标(cursor) 。

scroll查询会在第一次查询时,保存一个当时时间点的快照数据,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,这个快照数据保持不变。

深度分页的代价根源是结果集全局排序,如果去掉全局排序的特性的话查询结果的成本就会很低。scroll查询采用基于_doc进行排序的方式,性能较高。

每次发送scroll请求,我们还需要指定一个 scrollId,设置失效时间,每次搜索请求只要在这个失效时间内能完成就可以了。
更多滚动查询请参考:https://www.elastic.co/guide/cn/elasticsearch/guide/current/scroll.html

java API中的滚动查询

MatchQueryBuilder qb = QueryBuilders.matchQuery("message","去养猪了");

SearchResponse scrollResp = client.prepareSearch()
		.addSort(FieldSortBuilder.DOC_FIELD_NAME,SortOrder.ASC)
		.setScroll(new TimeValue(10))
		.setQuery(qb)
		.setSize(100).get();// 设置hits次数最多为100


// 将查询出来批量数据,按照hits次数遍历,直到hits为空
while(scrollResp.getHits().getHits().length !=0) {
	for (SearchHit hit : scrollResp.getHits().getHits()) {
		System.out.println(hit.toString());
		// Handle the hit...
	}
	
	scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(100)).execute().actionGet();
}; 

使用elasticsearchTemplate实现滚动查询

获取scrollId:

String scrollId = elasticsearchTemplate.scan(searchQuery, 6000, false);

滚动查询:

Page<Entity> pages = elasticsearchTemplate.scroll(scrollId, 6000, Entity.class);

滚动查询+线程池

注入elasticsearchTemplate:

@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
// 定义线程池,线程数为10个
private static ExecutorService executorService = Executors.newFixedThreadPool(10);

实现代码:

String scrollId = null;
try {
	// 滚动查询失效时间
	int SCROLL_TIMEOUT_INMILLIS = 12 * 60 * 60 * 1000;
	
	// 构建查询语句
	QueryBuilder orgQuery = QueryBuilders
			.boolQuery()
			.filter(QueryBuilders.termQuery("orgCode", orgCode));
	// es检索对象
	SearchQuery searchQuery = new NativeSearchQueryBuilder()
			.withIndices("你的索引index")
			.withTypes("你的类型type")
			.withQuery(orgQuery)
			.withPageable(new PageRequest(0, 100)) // 一次查询100条
			.build();
				
	// 获取初始滚动ID
	// 记录当前查询条件下所有数据的快照,之后的滚动查询都是从快照一批批的查
	scrollId = elasticsearchTemplate.scan(searchQuery, SCROLL_TIMEOUT_INMILLIS, false);
	while(true) {
		
		// 滚动查询
		Page<DemoEntity> pages = elasticsearchTemplate.scroll(scrollId, SCROLL_TIMEOUT_INMILLIS, DemoEntity.class);
		
		// 所有数据滚动完成,退出while
		if(!pages.hasContent()) {
			break;
		}
		
		for(DemoEntity document:pages.getContent()) {
			// 线程池
			executorService.execute(new clearMethod(document));
		}
	}
} catch (Exception e) {
	// exception
}finally {
	// 清除滚动id
	elasticsearchTemplate.clearScroll(scrollId);
	// 关闭线程池
	executorService.shutdown();
}

class clearMethod extends Thread {
	private DemoEntity document;
	
	public clearMethod(DemoEntity document) {
		this.document = document;
	}
	public void run() {
		// do something...
    }
}

结束

如对elasticsearch不是很了解,可以参考我前几篇博客。
因为工作要求,本篇描述的代码ES版本为2.4.0,可能有些过时了,但是思路大体上上正确的。
本篇所示的代码是伪代码,请不要直接copy,如有描述不清楚的地方,欢迎留言。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM中的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值