文章目录

  • 1. 数据聚合
    • 1.1 聚合的种类
    • 1.2 DSL实现聚合
      • 1.2.1 Bucket聚合语法
      • 1.2.2 聚合结果排序
      • 1.2.3 限定聚合范围
      • 1.2.4 Metric聚合语法
      • 1.2.5 小结
    • 1.3 RestAPI实现聚合
      • 1.3.1 API语法
      • 1.3.2 示例代码
      • 1.3.3 在lUserService中定义方法,实现对品牌、城市、星级的聚合

本节案例承接上节案例

1. 数据聚合

聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如:

  • 什么品牌的手机最受欢迎?
  • 这些手机的平均价格、最高价格、最低价格?
  • 这些手机每月的销售情况如何?

实现这些统计功能的比数据库的sql要方便的多,而且查询速度非常快,可以实现近实时搜索效果。


1.1 聚合的种类

小结:


1.2 DSL实现聚合

现在,我们要统计所有数据中的酒店品牌有几种,其实就是按照品牌对数据分组。此时可以根据酒店品牌的名称做聚合,也就是Bucket聚合。


1.2.1 Bucket聚合语法

语法如下:

GET /hotel/_search
{"size": 0,  // 设置size为0,结果中不包含文档,只包含聚合结果"aggs": { // 定义聚合"brandAgg": { //给聚合起个名字"terms": { // 聚合的类型,按照品牌值聚合,所以选择term"field": "brand", // 参与聚合的字段"size": 20 // 希望获取的聚合结果数量}}}
}

结果如图:


1.2.2 聚合结果排序

默认情况下,Bucket聚合会统计Bucket内的文档数量,记为_count,并且按照_count降序排序。

我们可以指定order属性,自定义聚合的排序方式:

GET /hotel/_search
{"size": 0, "aggs": {"brandAgg": {"terms": {"field": "brand","order": {"_count": "asc" // 按照_count升序排列},"size": 20}}}
}

运行结果:


1.2.3 限定聚合范围

默认情况下,Bucket聚合是对索引库的所有文档做聚合,但真实场景下,用户会输入搜索条件,因此聚合必须是对搜索结果聚合。那么聚合必须添加限定条件。

我们可以限定要聚合的文档范围,只要添加query条件即可:

GET /hotel/_search
{"query": {"range": {"price": {"lte": 200 // 只对200元及以下的文档聚合}}}, "size": 0, "aggs": {"brandAgg": {"terms": {"field": "brand","size": 20}}}
}

这次,聚合得到的品牌明显变少了:


1.2.4 Metric聚合语法

上面,我们对酒店按照品牌分组,形成了一个个桶。现在我们需要对桶内的酒店做运算,获取每个品牌的用户评分的minmaxavg等值。

这就要用到Metric聚合了,例如stats聚合:就可以获取minmaxavg等结果。

语法如下:

GET /hotel/_search
{"size": 0, "aggs": {"brandAgg": { "terms": { "field": "brand", "size": 20},"aggs": { // 是brands聚合的子聚合,也就是分组后对每组分别计算"scoreAgg": { // 聚合名称"stats": { // 聚合类型,这里stats可以计算min、max、avg等"field": "score" // 聚合字段,这里是score}}}}}
}

这次的score_stats聚合是在brandAgg的聚合内部嵌套的子聚合。因为我们需要在每个桶分别计算。

运行结果:

另外,我们还可以给聚合结果做个排序,例如按照每个桶的酒店平均分做排序:


1.2.5 小结


1.3 RestAPI实现聚合


1.3.1 API语法

聚合条件与query条件同级别,因此需要使用request.source()来指定聚合条件。

聚合条件的语法:

聚合的结果也与查询结果不同,API也比较特殊。不过同样是JSON逐层解析:


1.3.2 示例代码

HotelAggregationTest.java

package cn.itcast.hotel;import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;
import java.util.List;@SpringBootTest
class HotelAggregationTest {private RestHighLevelClient client;@Testvoid testAgg() throws IOException {// 1.准备请求SearchRequest request = new SearchRequest("hotel");// 2.请求参数// 2.1.sizerequest.source().size(0);// 2.2.聚合request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(20));// 3.发出请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果Aggregations aggregations = response.getAggregations();// 4.1.根据聚合名称,获取聚合结果Terms brandAgg = aggregations.get("brandAgg");// 4.2.获取bucketsList<? extends Terms.Bucket> buckets = brandAgg.getBuckets();// 4.3.遍历for (Terms.Bucket bucket : buckets) {String brandName = bucket.getKeyAsString();System.out.println("brandName = " + brandName);long docCount = bucket.getDocCount();System.out.println("docCount = " + docCount);}}@BeforeEachvoid setUp() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.135.130:9200")));}@AfterEachvoid tearDown() throws IOException {client.close();}
}

运行结果:


1.3.3 在lUserService中定义方法,实现对品牌、城市、星级的聚合

返回值类型就是页面要展示的最终结果:

结果是一个Map结构:

  • key是字符串,城市、星级、品牌、价格
  • value是集合,例如多个城市的名称

业务实现:

cn.itcast.hotel.web包的HotelController中添加一个方法,遵循下面的要求:

  • 请求方式:POST
  • 请求路径:/hotel/filters
  • 请求参数:RequestParams,与搜索文档的参数一致
  • 返回值类型:Map<String, List<String>>

代码:

    @PostMapping("/filters")public Map<String, List<String>> getFilters(@RequestBody RequestParams params){return hotelService.getFilters(params);}

这里调用了IHotelService中的getFilters方法,尚未实现。

cn.itcast.hotel.service.IHotelService中定义新方法:

Map<String, List<String>> getFilters(RequestParams params);

cn.itcast.hotel.service.impl.HotelService中实现该方法:

    @Overridepublic Map<String, List<String>> getFilters(RequestParams params) {try {// 1.准备RequestSearchRequest request = new SearchRequest("hotel");// 2.准备DSL// 2.1.querybuildBasicQuery(params, request);// 2.2.设置sizerequest.source().size(0);// 2.3.聚合buildAggregation(request);// 3.发出请求SearchResponse response = client.search(request, RequestOptions.DEFAULT);// 4.解析结果Map<String, List<String>> result = new HashMap<>();Aggregations aggregations = response.getAggregations();// 4.1.根据品牌名称,获取品牌结果List<String> brandList = getAggByName(aggregations, "brandAgg");result.put("品牌", brandList);// 4.2.根据品牌名称,获取品牌结果List<String> cityList = getAggByName(aggregations, "cityAgg");result.put("城市", cityList);// 4.3.根据品牌名称,获取品牌结果List<String> starList = getAggByName(aggregations, "starAgg");result.put("星级", starList);return result;} catch (IOException e) {throw new RuntimeException(e);}}private void buildAggregation(SearchRequest request) {request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(100));request.source().aggregation(AggregationBuilders.terms("cityAgg").field("city").size(100));request.source().aggregation(AggregationBuilders.terms("starAgg").field("starName").size(100));}private List<String> getAggByName(Aggregations aggregations, String aggName) {// 4.1.根据聚合名称获取聚合结果Terms brandTerms = aggregations.get(aggName);// 4.2.获取bucketsList<? extends Terms.Bucket> buckets = brandTerms.getBuckets();// 4.3.遍历List<String> brandList = new ArrayList<>();for (Terms.Bucket bucket : buckets) {// 4.4.获取keyString key = bucket.getKeyAsString();brandList.add(key);}return brandList;}

运行结果(需要重启项目):

{"品牌":["7天酒店","如家","皇冠假日","速8","万怡","华美达","和颐","万豪","喜来登","希尔顿","汉庭","凯悦","维也纳","豪生","君悦","万丽","丽笙"],"星级":["二钻","五钻","四钻","五星级","三钻","四星级"],"城市":["上海","北京","深圳"]
}


Elasticsearch 分布式搜索引擎 -- 数据聚合(聚合的种类、DSL实现聚合、RestAPI实现聚合)相关推荐

  1. Elasticsearch——分布式搜索引擎01(索引库、文档、RestAPI、RestClient、拼音分词器、IK分词器)

    Elasticsearch--分布式搜索引擎01(索引库.文档.RestAPI.RestClient.拼音分词器.IK分词器) 一.初识 elesticsearch 1.1 简介 1.2 倒排索引(重 ...

  2. Elasticsearch 分布式搜索引擎 -- 数据同步:数据同步思路分析 实现elasticsearch与数据库数据同步

    文章目录 1. 数据同步思路分析 1.1 同步调用 1.2 异步通知 1.3 监听binlog 1.4 小结 2. 实现数据同步 2.1 导入hotel-admin 2.2 声明交换机.队列 1)引入 ...

  3. ElasticSearch分布式搜索引擎从入门到实战应用(入门篇-基本命令操作)

    ElasticSearch分布式搜索引擎从入门到实战应用(入门篇) 1.入门须知 2.ElasticSearch概述 2.1.ES简介 2.2.应用场景 3.ES和Solr的对比 3.1.ES作用 3 ...

  4. 爬梯:ElasticSearch分布式搜索引擎

    学习资料:狂神说 ElactisSearch 7.6.2 ElasticSearch 分布式搜索引擎 1. 概述 1.1 ELK ELK是ElasticSearch.Logstash.Kibana三大 ...

  5. ElasticSearch分布式搜索引擎——从入门到精通

    ES分布式搜索引擎 注意: 在没有创建库的时候搜索,ES会创建一个库并自动创建该字段并且设置为String类型也就是text 什么是elasticsearch? 一个开源的分布式搜索引擎,可以用来实现 ...

  6. elasticsearch分布式搜索引擎详细使用总结

    文章目录 一.初识elasticsearch 1.1.ES了解 1.1.1.elasticsearch的作用 1.1.2.ELK技术栈 1.1.3.elasticsearch和lucene 1.1.4 ...

  7. ElasticSearch分布式搜索引擎-03

    1.数据聚合 聚合可以让我们极其方便的实现对数据的统计.分析.运算.查询速度非常快,可以实现近实时搜索效果 1.1.聚合的种类 聚合常见的有三类: 桶(Bucket)聚合:用来对文档做分组 TermA ...

  8. 大数据(二)Elasticsearch 分布式搜索引擎(存索引、索引搜索)

    一.Elasticsearch 存索引, Hbase 里存原数据 例如:一条告警上报过来,会同时存Hbase, ES里,Hbase存原数据,ES里只存索引(包含告警ID, 告警级别,告警状态,告警时间 ...

  9. 项目1在线交流平台-6.Elasticsearch分布式搜索引擎-3.ES结合Kafka应用-开发社区搜索功能

    文章目录 功能需求 一.Service层处理操作ES服务器的数据 二.Controller层处理帖子添加和评论事件请求 1.添加帖子时-触发事件-发布消息 2. 添加评论时-触发发帖事件-发布消息 三 ...

  10. Elasticsearch 分布式搜索引擎 -- 自动补全(拼音分词器、自定义分词器、自动补全查询、实现搜索框自动补全)

    文章目录 1. 自动补全 1.1 拼音分词器 1.2.1 自定义分词器 1.2.2 小结 1.2 自动补全 1.3 实现酒店搜索框自动补全 1.3.1 修改酒店映射结构 1.3.2 修改HotelDo ...

最新文章

  1. php中getdistance函数_php计算两个经纬度地点之间的距离
  2. [LeetCode] Maximum Subarray 最大子数组
  3. injectionForXcode代码注入步骤
  4. 用户空间增加、缩减内存
  5. OpenYurt 如何 “0 侵入” 攻破云边融合难点
  6. Windows 7 完美安装 Visual C++ 6.0
  7. java的传值调用什么_Java的传值调用
  8. 网络编程的4种IO模型
  9. 第二节:Css重写样式
  10. php 将前端网页输出成unicdoe编码
  11. 日记 [2008年03月23日]不编译内核给iptables增加模块
  12. logisim输出变成红色的e_新款E刚出就被骂最丑,却销量可观,梅赛德斯:都是小事儿,上AMG...
  13. 使用 Repeater方式和完全静态页面使用AJAX读取和提交数据
  14. bootstrap 树
  15. 用计算机弹出古诗,电脑屏保不断变化的诗句
  16. 当你一个人走过你们曾经走过的大街小巷,你会有何感受?
  17. 处理 JS中 undefined 的7个技巧
  18. 十年之前..., 十年之后...
  19. ue4 无限地图_基于UE4的开放世界地图架构
  20. nsf5隐写算法 matlab,基于纹理复杂度的JPEG图像自适应隐写

热门文章

  1. ps图层新建 ,合并可见图层 ,盖印图层
  2. 第1章思维导图图片版
  3. 支付宝推出信用租房 醉翁之意不在酒?
  4. 洛克菲勒留给儿子的38封信
  5. MapReduce:Combiner与Shuffle阶段之Reducer输入
  6. 解决is exceeding the 65535 bytes limit问题
  7. 对话微软大中华区CEO梁念坚:WP7为云而生
  8. todo已完成任务_总结一下TODO的用法
  9. 六个免费的虚拟主机管理系统
  10. PHPer 为什么会被 Javaer 鄙视?