前言
项目中经常会遇到一些比较复杂的查询,如何使用RestHighLevelClient来实现查询呢,本文将讲解Spring Boot采用RestHighLevelClient如何实现高级查询。
数据准备
我们准备相关的数据来展示相关的示例。
具体实现
分页组合查询
分页查询:采用from、size的方式进行分页和Mysql的limit分页原理是一样的,from代表是数据从那条开始,size代表是查询多少条数据。
Controller实现
@GetMapping("/pageSearch")
public Result pageSearch(String indexName,String key,String value) throws IOException
{
//设置多个文档
SearchRequest request =new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
//表示从什么位置开始,查询多少条数据
sourceBuilder.from(0).size(2);
//按照价格排序
sourceBuilder.sort("price",SortOrder.DESC);
request.source(sourceBuilder);
SearchResponse response =client.search(request, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : hits)
{
logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
}
return Result.success(searchHits);
}
输出结果
c.s.f.e.c.RestHightController - search Id:12,hit data:{"createDate":1655132070891,"id":"12","price":110.0,"skuNo":"sku0012","title":"java设计模式"}c.s.f.e.c.RestHightController - search Id:10,hit data:{"createDate":1655132070891,"id":"10","price":105.0,"skuNo":"sku0011","title":"Effive java"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO [] c.s.f.e.c.RestHightController - search Id:11,hit data:{"createDate":1655132070891,"id":"11","price":100.0,"skuNo":"sku0011","title":"java架构设计"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO [] c.s.f.e.c.RestHightController - search Id:2,hit data:{"createDate":1655132070891,"id":"2","price":99.0,"skuNo":"sku0002","title":"java从入门到精通"}
2022-06-14 21:41:55.994 [http-nio-9090-exec-1] INFO [] c.s.f.e.c.RestHightController - search Id:3,hit data:{"createDate":1655132070891,"id":"3","price":89.0,"skuNo":"sku0003","title":"java编程思想"}
说明:从输出结果可以看出,通过查询包含java的数据,分页显示5条数据,且按照价格进行排序。
分组查询
分组查询:采用TermAggregation针对某个字段进行分组查询。
Controller实现
@GetMapping("/aggSearch")
public Result aggSearch(String indexName,String key,String value) throws IOException
{
SearchRequest request =new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
//按照价格进行聚合
AggregationBuilder ageAgg = AggregationBuilders.terms("priceGroup").field("price").size(10);
sourceBuilder.aggregation(ageAgg);
request.source(sourceBuilder);
SearchResponse response =client.search(request, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : hits)
{
logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
}
Aggregations aggregations = response.getAggregations();
//数据为double类型,采用ParsedDoubleTerms
ParsedDoubleTerms parsedDoubleTerms = aggregations.get("priceGroup");
// 输出匹配的结果数据
List<? extends Terms.Bucket> buckets = parsedDoubleTerms.getBuckets();
for (Terms.Bucket bucket:buckets)
{
logger.info("key:{},count:{}",bucket.getKeyAsString(),bucket.getDocCount());
}
return Result.success(searchHits);
}
说明:针对price字段进行分组查询,如果是double类型的数据,需要采用ParsedDoubleTerms进行接收,否则会报类型转换错误。
输出结果
c.s.f.e.c.RestHightController - key:89.0,count:2
c.s.f.e.c.RestHightController - key:99.0,count:1
c.s.f.e.c.RestHightController - key:100.0,count:1
c.s.f.e.c.RestHightController - key:105.0,count:1
c.s.f.e.c.RestHightController - key:110.0,count:1
聚合查询
聚合查询通常包含:Max、Min、AVG、Sum等查询
Controller实现
/**
* 聚合查询
* @param indexName
* @param key
* @param value
* @return
* @throws IOException
*/
@GetMapping("/sumSearch")
public Result sumSearch(String indexName,String type,String key,String value) throws IOException
{
//设置多个文档
SearchRequest request =new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
AggregationBuilder ageAgg =null;
//按照条件进行聚合
if("max".equals(type))
{
ageAgg=AggregationBuilders.max("priceMax").field("price");
}
else if("min".equals(type))
{
ageAgg=AggregationBuilders.min("priceMin").field("price");
}
else if("avg".equals(type))
{
ageAgg=AggregationBuilders.avg("priceAvg").field("price");
}
else
{
ageAgg= AggregationBuilders.sum("priceSum").field("price");
}
sourceBuilder.aggregation(ageAgg);
request.source(sourceBuilder);
SearchResponse response =client.search(request, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : hits)
{
logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
}
Aggregations aggregations = response.getAggregations();
//价格之和
/**
max 使用ParsedMax处理
min 使用ParsedMin处理
avg 使用 ParsedAvg处理
sum 使用ParsedSum处理
*/
if("max".equals(type))
{
ParsedMax preMax = aggregations.get("priceMax");
logger.info("求最大为:"+preMax.value());
}
else if("min".equals(type))
{
ParsedMin preMin = aggregations.get("priceMin");
logger.info("求最小为:"+preMin.value());
}
else if("avg".equals(type))
{
ParsedAvg preAvg = aggregations.get("priceAvg");
logger.info("求平均值为:"+preAvg.value());
}
else
{
ParsedSum parsedSum = aggregations.get("priceSum");
logger.info("求和值为:"+parsedSum.value());
}
return Result.success(searchHits);
}
说明:
- Type:类型:通过传入不同的值,进行不同的聚合查询,
- ParsedSum :处理求和后的结果
- ParsedAvg :处理求平均值的结果
- ParsedMin :处理最小值的结果
- ParsedMax:处理最大值的结果
输出结果
例如求平均值:
2022-06-14 22:28:52.938 [http-nio-9090-exec-6] INFO [] c.s.f.e.c.RestHightController - 求平均值为:98.66666666666667
Top查询
Controller实现
@GetMapping("/topSearch")
public Result topSearch(String indexName,String key,String value) throws IOException
{
SearchRequest request =new SearchRequest(indexName);
SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
//按照价格排序获取前2条
AggregationBuilder aggregationBuilder = AggregationBuilders.topHits("price_top").sort(SortBuilders.fieldSort("price").order(SortOrder.DESC)).size(2);
sourceBuilder.aggregation(aggregationBuilder);
request.source(sourceBuilder);
SearchResponse response =client.search(request, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : hits)
{
logger.info("search Id:{},hit data:{}",hit.getId(),hit.getSourceAsString());
}
//输出结果
Aggregations aggregations = response.getAggregations();
TopHits topHits = aggregations.get("price_top");
SearchHits hitsRes = topHits.getHits();
for (SearchHit hit : hitsRes.getHits())
{
logger.info("id:{} ,Top data:{}",hit.getId(),hit.getSourceAsString());
}
return Result.success(searchHits);
}
说明:通过price进行排序获取前2条记录。
输出结果
c.s.f.e.c.RestHightController - id:12 ,Top data:{"createDate":1655132070891,"id":"12","price":110.0,"skuNo":"sku0012","title":"java设计模式"}
c.s.f.e.c.RestHightController - id:10 ,Top data:{"createDate":1655132070891,"id":"10","price":105.0,"skuNo":"sku0010","title":"Effive java"}
高亮显示
Controller实现
@GetMapping("/hightSearch")
public Result hightSearch(String indexName,String key,String value) throws IOException
{
SearchRequest request =new SearchRequest(indexName);
//构造查询条件
SearchSourceBuilder sourceBuilder =new SearchSourceBuilder().query(QueryBuilders.termQuery(key, value));
//设置高亮显示
HighlightBuilder highlightBuilder = new HighlightBuilder().preTags("<span style='color:red'>").postTags("</span>");
highlightBuilder.highlighterType("unified"); // 设置字段高光色类型。
highlightBuilder.field("title").field("remark"); //将字段高光色添加到高亮构建器。
//设置值
sourceBuilder.highlighter(highlightBuilder);
request.source(sourceBuilder);
SearchResponse response =client.search(request, RequestOptions.DEFAULT);
SearchHits hits = response.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit: searchHits)
{
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if(highlightFields.containsKey("remark"))
{
logger.info("remark高亮的结果:{}",highlightFields.get("remark").fragments()[0]);
}
if(highlightFields.containsKey("title"))
{
logger.info("title高亮的结果:{}",highlightFields.get("title").fragments()[0]);
}
}
return Result.success(searchHits);
}
说明:通过查询包含java的标题显示为红色。
输出结果
c.s.f.e.c.RestHightController - title高亮的结果:<span style='color:red'>java</span>架构设计
c.s.f.e.c.RestHightController - title高亮的结果:<span style='color:red'>java</span>从入门到精通
总结
本文重点讲解了Spring Boot集成Elasticsearch实现一些复杂的查询,如有疑问可以随时反馈。