import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
@Autowired
protected ElasticsearchTemplate elasticsearchTemplate;
A:搜索构造器
1、构建一个搜索请求,参数是将搜索的索引:
SearchRequest searchRequest = new SearchRequest(your-indexe);
1.1:用法是将过滤条件生成器、聚合条件生成器添加在里面。
B:过滤条件构造器
2、需要有过滤条件创建匹配条件生成器:
BoolQueryBuilder bool = QueryBuilders.boolQuery();
条件可以添加多个可根据业务添加。
2.2:对某个字段的过滤,比如对字段name是张三的用户进行过滤代码
bool.must(QueryBuilders.termQuery("your-name-field", "张三"));
2.3:对某个字段进行前缀匹配的过滤(用于页面搜索功能),比如对字段name是张三的用户进行前缀匹配过滤代码
bool.filter(QueryBuilders.prefixQuery("your-name-field", "张"));
2.4:如果有时间范围搜索的要求:
bool.must(QueryBuilders.rangeQuery("your-time-field").gte(StartTime).lte(EndTime));
3:匹配过滤器创建成功后,需要将比配过滤器添加到搜索元构造器中
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
3.1:放入搜索元构造器代码:
sourceBuilder.query(bool);
C:聚合条件
3:聚合思路:聚合是根据过滤条件(B)过滤后的数据进行聚合,聚合可以是多层聚合,多层聚合取值时多个循环的去一层一层的取值,一级聚合下的子集聚合也可多个。
4:字段聚合的使用代码:
TermsAggregationBuilder nameAggregation = AggregationBuilders
.terms("随意取名字")
.field("your-field")
.size(Integer.MAX_VALUE);
4.1:terms的参数是随意取的,后面取值时需要用来取,就好比sql中的AS操作,field参数是自己需要聚合的字段,size最好加上,因为如果数据量比较大不添加这个ES的API就会给一个默认值10,但是你的数据有11条就会产生少统计的误差。
5: sum聚合的使用代码:
SumAggregationBuilder sumAggregation = AggregationBuilders
.sum("随意取名字,这儿取 sum_field做示例")
.field("your-field");
5.1:对聚合的结果排序代码(2种方式):
第一种:
resourceIdAggregation.order(BucketOrder.aggregation(sum_field, false));
第二种:需要将bucketSort放入聚合桶中
List<FieldSortBuilder> sorts = new ArrayList<>();
sorts.add(new FieldSortBuilder(Constant.visitFlow.FLOW_NUMBER_SUM).order(SortOrder.DESC));
5.2:对聚合的结果进行分页代码:
BucketSortPipelineAggregationBuilder bucketSort = new BucketSortPipelineAggregationBuilder(Constant.visitFlow.SUM_SORT, sorts)
.from(webContext.pagination().getPageNumber() * webContext.pagination().getPageSize())
.size(webContext.pagination().getPageSize());
注意:需要将bucketSort 添加到聚合桶中;
注意:分页需要一个重要参数是总条数此代码的思路是将第一层聚合的数量就可当做总条数。
CardinalityAggregationBuilder cardinalityAggregation = AggregationBuilders.cardinality(“随意取值”).field(第一层聚合的字段);
6:需要将聚合串联起来,演示代码:
①:nameAggregation是第一层聚合,sumAggregation 是第二层
nameAggregation.subAggregation(sumAggregation );
②:bucketSort 作为分页也可当做一个聚合
nameAggregation.subAggregation(bucketSort );
添加总条数的聚合
nameAggregation.aggregation(cardinalityAggregation);
③添加TOP_ONE操作(后续解释)
nameAggregation.subAggregation(
AggregationBuilders.topHits(“TOP_ONE”)
.size(1));
7:将聚合条件添加至搜索元构造器中
sourceBuilder.aggregation(targetAggregation);
D:获取结果集
searchRequest.source(sourceBuilder);
E:获取结果集封装的util
1、此代码是封装的一个查询方法代码可封装在项目util中:
public static SearchResponse queryForSearchResponse(ElasticsearchOperations elasticsearchTemplate, String indexName,
SearchSourceBuilder searchSource) {
// 执行查询,并获取查询结果
SearchRequest searchRequest = new SearchRequest();
searchRequest.source(searchSource);
searchRequest.indices(indexName);
SearchResponse response = null;
if (elasticsearchTemplate instanceof ElasticsearchRestTemplate) {
ElasticsearchRestTemplate restTemplate = (ElasticsearchRestTemplate)elasticsearchTemplate;
try {
response = restTemplate.getClient().search(searchRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
throw ApplicationException.build();
}
} else if (elasticsearchTemplate instanceof ElasticsearchTemplate) {
ElasticsearchTemplate template = (ElasticsearchTemplate)elasticsearchTemplate;
SearchRequestBuilder searchBuilder = template.getClient().prepareSearch(indexName);
searchBuilder.setSource(searchSource);
response = searchBuilder.execute().actionGet();
执行查询代码:
SearchResponse searchResponse = ElasticsearchUtils.queryForSearchResponse(elasticsearchTemplate,“your-indexe” , sourceBuilder); }
return response;
}
F:处理查询结果
1、根据“E”封装的方法
SearchResponse searchResponse = ElasticsearchUtils.queryForSearchResponse(elasticsearchTemplate, “你的索引”, sourceBuilder);
2、拿到分页总条数:
Cardinality cardinality = searchResponse.getAggregations().get(“自己所定义的名字”);
long total = cardinality.getValue();
total就是聚合的总条数
3、处理聚合结果:
Terms idTerms = searchResponse.getAggregations().get(“是自己定义的第一层聚合名字”);
for (Terms.Bucket idBucket : idTerms.getBuckets()) {
String id = dBucket.getKeyAsString();
//如果有第二层聚合
Terms userIDTerms = portBucket.getAggregations().get(“第二层聚合定义的名字”);
for (Terms.Bucket userIDBucket : userIDTerms.getBuckets()) {
String userId = (String) userIDBucket.getKey();
//业务逻辑操作(后面还有下一层聚合依次循环)注意:如果uerId这层有多个聚合比如有sum的聚合是和userId 是同层的就不需要循环Sum downloadBytesSum = userIDBucket .getAggregations().get(Constant.visitFlow.DOWNLOAD_BYTES_SUM);
long umValue = (long) downloadBytesSum.getValue();
}
}
4、取聚合以外的值:场景User对象有字段name、age、sex字段,有两层聚合通过sex聚合后再通过age聚合,但是再上述F中只能拿到age和sex的值如:String id = idBucket.getKeyAsString();但是你想拿到name,如果再去查询数据库当数据量大的时候就会影响效率,可以通过上述C.6.③的操作拿到数据。
在你定义的聚合层级:
TopHits topHits = bucket.getAggregations().get(Constant.visitFlow.TOP_ONE);
SearchHit[] hits = topHits.getHits().getHits();
if (hits.length > 0) {
// 在topHits中获取ame字段的值
name = (String) hits[0].getSourceAsMap().get(“name”);
}
注意:
nameAggregation.subAggregation(
AggregationBuilders.topHits(“TOP_ONE”)
.size(1));
这里size的值可根据自己的业务需求来定,如果值需要拿所有聚合中的随意一个就可以了那就1就可以了取值的时候hits[0]就行,如果是去所有但是数量不知道,就填Int的最大值
Integer.MAX_VALUE就行。