基于第二章搭建的项目,下面 我们实现es的批量插入
参考此文章,请先参考第二章进行搭建
1、海量数据的搜索(千万级别以上的数据)而且要求搜索响应要快
2、根据搜索条件返回的结果,有相等,类似,并且要求结果越接近的优先展示
牛逼吹多了!我们进入正文
同步数据到es 可以使用spring-boot-starter-data-elasticsearch 封装好的方法
saveAll(Iterable<S> entities)
看底层源码 就知道也是调用了
elasticsearchOperations 的void bulkIndex(List<IndexQuery> queries);方法
当然灵活点可以自己写
这里我是自己写,每次插入的数量设置为15w
public class ElasticsearchUtil { /** * 批量插入的数据长度大小 */ private final int PAGE_SIZE = 150000; @Autowired private ElasticsearchTemplate elasticsearchTemplate; /** * 批量插入数据 * @return */ public int bulkIndex(String indexName,String indexType,List<BaseEsEntity> dataList){ int counter = 0; checkData(indexName,indexType,dataList); //判断索引是否存在 if (!elasticsearchTemplate.indexExists(indexName)) { elasticsearchTemplate.createIndex(indexName); } List<IndexQuery> indexQueries = convertData(dataList,indexName,indexType); elasticsearchTemplate.bulkIndex(indexQueries); log.info("bulkIndex counter : " + indexQueries.size()); counter = indexQueries.size(); indexQueries.clear(); dataList.clear(); elasticsearchTemplate.refresh(indexName); return counter; } private void checkData(String indexName,String indexType,List<BaseEsEntity> dataList){ if(StringUtils.isBlank(indexName) || StringUtils.isBlank(indexType)){ throw new RuntimeException("indexName or indexType can not be null"); } if(CollectionUtils.isEmpty(dataList)){ throw new RuntimeException(String.format("保存的数据不能为空,data size 长度{%d}", dataList.size())); } if(dataList.size() > PAGE_SIZE){ throw new RuntimeException(String.format("data size 必须小于{%d},当前长度{%d}", PAGE_SIZE, dataList.size())); } } private List<IndexQuery> convertData(List<BaseEsEntity> dataList,String indexName,String indexType){ List<IndexQuery> queries = new ArrayList<>(); for (BaseEsEntity esEntity : dataList) { IndexQuery indexQuery = new IndexQuery(); indexQuery.setId(esEntity.getId()); indexQuery.setSource(JSONObject.toJSONString(esEntity)); indexQuery.setIndexName(indexName); indexQuery.setType(indexType); queries.add(indexQuery); } return queries; } }
一下是聚合统计的代码展示
构建查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); if (StringUtils.isNotBlank(request.getName())) { boolQueryBuilder.should(QueryBuilders.matchQuery(ElasticsearchDateKey.brandName, request.getName())); boolQueryBuilder.should(QueryBuilders.wildcardQuery(ElasticsearchDateKey.brandName+".keyword","*"+request.getName()+"*")); boolQueryBuilder.minimumShouldMatch("50%"); } boolQueryBuilder.filter(QueryBuilders.termQuery(ElasticsearchDateKey.brandType,9));
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); //查询条件 nativeSearchQueryBuilder.withQuery(boolQueryBuilder); //分页 nativeSearchQueryBuilder.withPageable(pageable); //2.2指定索引库和文档类型 nativeSearchQueryBuilder.withIndices(TRADEMARK_US_INDEX_NAME).withTypes(TRADEMARK_US_INDEX_TYPE); int termsAggregationSize = request.getPageSize() * 10 > 10000 ? 10000 : request.getPageSize() * 10; TermsAggregationBuilder field = AggregationBuilders.terms(ElasticsearchDateKey.typeCount).field( ElasticsearchDateKey.brandType).size(termsAggregationSize); TermsAggregationBuilder applicationStatus = AggregationBuilders.terms(ElasticsearchDateKey.applicationStatus).field( ElasticsearchDateKey.applicationStatusKeyword).size(termsAggregationSize); nativeSearchQueryBuilder.addAggregation(field); nativeSearchQueryBuilder.addAggregation(applicationStatus); //2.4构建查询对象 NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build(); Page<TrademarkUsPagelistEO> byTitle = trademarkUs.search(nativeSearchQuery);
执行代码 的debug结果
dsl查询结果
结果相符。
这里提一些个问题: 代码通配符查询
QueryBuilders.wildcardQuery(ElasticsearchDateKey.brandName+".keyword","*"+request.getName()+"*")
这里增加了keyword 是不让 "*Ac*" 这样进行分词
问题二:分页查询 出现-Result window is too large, from + size must be less than or equal to 的错误 因为es默认的查询分页深度就是1w。正常情况下 几乎没人从第一条数据查看到1w条,不正常的时候就是想看最后结果,杠精。遇到这样的产品提需求,请谁先k他一顿,并且问他是怎么做到产品的
解决办法:
PUT 索引库/_settings
{
"index":{
"max_result_window":1000000 #这个数值根据自身服务器资源 或者需求的要求编写
}
}