前两天因为es索引和DB数据数量对应不上了,需要写一个任务,校验两边的数据进行多删少补。就是将多余的索引删除,缺少的索引进行添加。
然后觉得也没啥,也没开多线程,直接一个线程循环查,跑任务就ok。第一次遇到问题是通过from/size方式查询es是有默认最大条数限制的,是10000;然后本人通过{- index.max_result_window:最大限制条数}直接改了限制的条数,其实这也已经足够了。可是因为索引数量是几千万条,到后面我发现性能会有下降,然后就引出了本次所说的scroll查询。
大家都知道from/size会查询你所需要的数据前面所有数据然后剔除调无用的数据,然后我这有六个分片,可以想象一下后面性能会怎么样。然后看了一下scroll-scan查询的资料,发现并不需要读取大量数据再剔除不需要的,而是记录一下游标的位置,今儿快速的进行下次的读取。好了,话不多说,直接上代码
public Map<String,Object> findGoodsIdsByScroll(Integer pageNo, Integer pageSize,String scrollId) {
Map<String,Object> result=Maps.newHashMap();
String index = BASE_INDEX_NEW;
String type = GOODS_TYPE;
NativeSearchQueryBuilder nsb = new NativeSearchQueryBuilder();
if (pageNo != null && pageSize != null) {
if (pageNo < 0) {
pageNo = 0;
}
Pageable pageable = new PageRequest(pageNo, pageSize);
nsb.withPageable(pageable);
}
nsb.withIndices(index);// 索引 (库)
nsb.withTypes(type);// 索引下的类型 (表)
nsb.withFields("_id");// 查询字段
SearchQuery searchQuery = nsb.build();
long scollTimeInMillis = 2*60*1000; // scrollId过期时间
if(StringUtils.isEmpty(scrollId)){
scrollId = template.scan(searchQuery, scollTimeInMillis, false);
}
SearchResponse response =template.getClient().prepareSearchScroll(scrollId).setScroll(TimeValue.timeValueMillis(scollTimeInMillis)).execute().actionGet();
scrollId=response.getScrollId();
result.put("scrollId", scrollId);
List<String> ids=new ArrayList<String>(200);
for (SearchHit hit : response.getHits()) {
try{
String id=hit.getId();
ids.add(id);
}catch(Exception e){
e.printStackTrace();
System.out.println(response);
}
}
result.put("ids", ids);
if(CollectionUtils.isEmpty(ids)){
template.clearScroll(scrollId); //无查询结果清除
}
return result;
}
大概说下,先通过scan查询获取一个base64的长字符串,即scrollId,然后通过scrollId去查询索引数据即可。然后运行发现性能有着明显的提升。