javaAPI实现elasticsearch5.5.2的聚合分析
前言:
在前面的几篇文章讲到了elasticsearch的搜索,但是elasticsearch还有强大的聚合分析功能,通过聚合,我们会得到一个数据的概览,这样对大数据提取统计指标时就变得游刃有余。聚合允许我们向数据提出一些复杂的问题。虽然功能完全不同于搜索,但它们使用相同的数据结构,执行速度很快并且就像搜索一样几乎是实时的。
一、聚合(Aggregations)的介绍
elasticsearch的聚合(Aggregations)类似于数据库sql中的分组 group by,count、sum等函数,除此之外他还有更多强大的数据统计分析接口。
聚合有两个核心概念:
1.桶(bucket):对数据进行分组。比如一个对象User他有一个属性是city,有如下数据:1.张三 上海 ;2.李四 北京; 3.王五 北京,我们就可以基于city划分buckets,一个是北京bucket,一个是上海bucket,按照某个字段进行bucket划分,那个字段的值相同的那些数据,就会被划分到一个bucket中,相当于sql中的group by分组。
2.指标(metric):对一个数据分组执行的统计。当我们有了一堆bucket之后,就可以对每个bucket中的数据进行聚合分词了,比如说计算一个bucket内所有数据的数量、平均值、最大值等的,metric就是对一个bucket执行的某种聚合分析的操作,相当于数据库中的avg,sum函数
二、Bucket aggregations 聚合分组的使用
官方参考资料:
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_bucket_aggregations.html
我会在第一个例子中将完整的代码写出来,其他的例子仿照第一个进行
1. Terms Aggregation
terms按照某个字段进行分组,下面的代码中也涉及了排序问题,详细代码看注释
/**TermAggs 包含了Order
* termAggs统计每个颜色的个数
* @Title: countByColor
* @Description: TODO(统计每个颜色的销量)
* @param @throws UnknownHostException
* @return void
* @autor lpl
* @date 2017年11月6日
* @throws
*/
@Test
public void countByColor() throws UnknownHostException{
//进行聚合查询,terms按照某个字段中进行分组
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders
.terms("popular_colors") //aggs的名称,自定义,取数据的时候与其一致即可
.field("color") //需要分组的字段
//.order(Terms.Order.term(true)) //true表示按照term分组的asc排序
.order(Terms.Order.count(true)); //true表asc按照doc_count排序,false表示desc排序
//查询数据进行聚合分析
SearchResponse response = EsClient.client().prepareSearch("tvs").setTypes("sales")
.addAggregation(termsAggregationBuilder)
.setSize(0)
.execute()
.actionGet();
//获取聚合
Terms terms = response.getAggregations().get("popular_colors");
//遍历处理数据
for (Terms.Bucket entry : terms.getBuckets()) {
Map<String,Object> map = new HashMap<String,Object>();
String key = (String) entry.getKey(); // Term
long docCount = entry.getDocCount(); // Doc count
//将结果放到Map中
map.put("color",key);
map.put("docCount",docCount);
System.out.println(map);
}
}
在Terms Aggregation涉及到一个Order分组问题,在上面的代码上我已经做了简单的注释,但是还存在一种排序方式,就是我们按照某一个统计出来字段进行排序,比如:按照height字段的平均值进行排序,fasle代表了desc排序
AggregationBuilders
.terms("genders")
.field("gender")
.order(Terms.Order.aggregation("avg_height", false))
.subAggregation(
AggregationBuilders.avg("avg_height").field("height")
)
2. Histogram Aggregation 按照区间进行分组
按照区间分组有Histogram Aggregation 和 Date Histogram Aggregation,我们以两个简单的需求进行编写具体的代码
2.1Histogram Aggregation:以2000位区间单位统计电视的销量
/**
* 以2000位区间单位统计电视的销量
* @Title: HistogramTest
* @param @throws UnknownHostException
* @return void
* @autor lpl
* @date 2017年11月6日
* @throws
*/
@Test
public void HistogramTest() throws UnknownHostException{
//histogram:类似于terms,也是进行bucket分组操作,interval:2000,
//划分范围,0~2000,2000~4000,4000~6000,6000~8000,8000~10000
HistogramAggregationBuilder histogramAggregationBuilder = AggregationBuilders
.histogram("his_price")
.field("price")
.interval(2000);
//查询数据进行聚合分析
SearchResponse response = EsClient.client()
.prepareSearch("tvs").setTypes("sales")
.addAggregation(histogramAggregationBuilder)
.setSize(0)
.execute()
.actionGet();
Histogram agg = response.getAggregations().get("his_price");
// For each entry
for (Histogram.Bucket entry : agg.getBuckets()) {
Map<String,Object> map = new HashMap<String,Object>();
Number key = (Number) entry.getKey(); // 区间key
long docCount = entry.getDocCount(); // Doc count
//数据封装
map.put("key",key);
map.put("doc_count",docCount);
System.out.println(map);
}
}
2.2Date Histogram Aggregation:统计每个月份的电视销量,这个需求中还涉及了一些其他知识点,在代码注释中有体现
/**
* 统计每个月份的电视销量
* @Title: dateHistogramTest
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @throws UnknownHostException
* @return void
* @autor lpl
* @date 2017年11月6日
* @throws
*/
@Test
public void dateHistogramTest() throws UnknownHostException{
//Date histogram的用法与histogram差不多,只不过区间上支持了日期的表达式。
DateHistogramAggregationBuilder dateHistogramInterval = AggregationBuilders
.dateHistogram("date_hist") //聚合的名称,可以随意去取,下边取数据一致即可
.field("sold_date") //需要进行分组的字段
.dateHistogramInterval(DateHistogramInterval.MONTH) //设置时间区间
.minDocCount(0) //设置最小的 doc_count,
.format("yyyy-MM-dd") //将返回的时间结果进行格式化
.missing("2016-05-01"); //缺省字段:当遇到没有值的字段,就会按照该字段的值来计算
//查询数据进行聚合分析
SearchResponse response = EsClient.client()
.prepareSearch("tvs").setTypes("sales")
.addAggregation(dateHistogramInterval)
.setSize(0)
.execute()
.actionGet();
//获得我们设置的聚合
Histogram agg = response.getAggregations().get("date_hist");
//循环数据输出
for (Histogram.Bucket entry : agg.getBuckets()) {
Map<String,Object> map = new HashMap<String,Object>();
//处理
DateTime key = (DateTime) entry.getKey(); // Key
String keyAsString = entry.getKeyAsString(); // Key as String
long docCount = entry.getDocCount(); // Doc count
//封装
map.put("date",keyAsString);
map.put("doc_count",docCount);
System.out.println(map);
}
}
3.Range Aggregation按照范围进行分组
这个功能介绍中,我会减少代码量,只把关键代码贴出来,代码中会有注释
3.1.数字范围:
AggregationBuilder rangAgg = AggregationBuilders
.range("rang_price")
.field("price")
.addUnboundedTo(1000) //从负无穷到1000
.addRange(1001, 1500) //从1001-1500
.addRange(1501, 2000) //从1501-2000
.addUnboundedFrom(2001);//2000到正无穷
// 获得我们设置的聚合
Range agg = response.getAggregations().get("rang_price");
// 循环数据输出
for (Range.Bucket entry : agg.getBuckets()) {
Map<String, Object> map = new HashMap<String, Object>();
// 处理
String key = entry.getKeyAsString(); // Range as key
Number from = (Number) entry.getFrom(); // Bucket from
Number to = (Number) entry.getTo(); // Bucket to
long docCount = entry.getDocCount(); // Doc count
// 封装
map.put("key", key);
map.put("doc_count", docCount);
System.out.println(map);
}
3.2.Date Range Aggregation日期范围
AggregationBuilder aggregation =
AggregationBuilders
.dateRange("agg")
.field("dateOfBirth") //field名称
.format("yyyy") //日期格式
.addUnboundedTo("1950") // from -infinity to 1950 (excluded)
.addRange("1950", "1960") // from 1950 to 1960 (excluded)
.addUnboundedFrom("1960"); // from 1960 to +infinity
for (Range.Bucket entry : agg.getBuckets()) {
String key = entry.getKeyAsString(); // Date range as key
DateTime fromAsDate = (DateTime) entry.getFrom(); // Date bucket from as a Date
DateTime toAsDate = (DateTime) entry.getTo(); // Date bucket to as a Date
long docCount = entry.getDocCount(); // Doc count
}
3.3 IP Range Aggregation ip范围分组
IpRangeAggregationBuilder aggregation1 =
AggregationBuilders
.ipRange("agg")
.field("ip")
.addUnboundedTo("192.168.1.0") // 从负无穷到192.168.1.0
.addRange("192.168.1.0", "192.168.2.0") // 从 192.168.1.0 到 192.168.2.0 (excluded)
.addUnboundedFrom("192.168.2.0"); // 从 192.168.2.0 到 +infinity
for (Range.Bucket entry : aggregation1.getBuckets()) {
String key = entry.getKeyAsString(); // Ip 范围 as key
String fromAsString = entry.getFromAsString(); // Ip bucket from as a String
String toAsString = entry.getToAsString(); // Ip bucket to as a String
long docCount = entry.getDocCount(); // Doc count
}
4. Filters Aggregation 过滤分组:根据过滤条件进行分组
AggregationBuilder aggregation =
AggregationBuilders
.filters("agg",
new FiltersAggregator.KeyedFilter("men", QueryBuilders.termQuery("gender", "male")),
new FiltersAggregator.KeyedFilter("women", QueryBuilders.termQuery("gender", "female")));
// For each entry
for (Filters.Bucket entry : agg.getBuckets()) {
String key = entry.getKeyAsString(); // bucket key
long docCount = entry.getDocCount(); // Doc count
logger.info("key [{}], doc_count [{}]", key, docCount);
}
key [men], doc_count [4982]
key [women], doc_count [5018]
三、Metrics aggregations 聚合分析的使用
官方参考文档:
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/_metrics_aggregations.html
3.1常用的:Avg,Max,Sum等等
我通过一个需求将metric的javaAPI进行说明,需求是:查询电视销售每个颜色的平均价格、最高价格、总价格并按照平均价格降序排序,对应的sql语句为:
select avg(price) avg_price,max(price) max_price,sum(price) sum_price from tvs.sales group by color order by avg_price
/**
* 查询电视销售每个颜色的平均价格、最高价格、总价格并按照平均价格降序排序
* @Title: metrics
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param @throws UnknownHostException
* @return void
* @autor lpl
* @date 2017年11月6日
* @throws
*/
@Test
public void metrics() throws UnknownHostException{
// 创建查询索引和type
SearchRequestBuilder srBuilder =EsClient.client()
.prepareSearch("tvs")
.setTypes("sales");
// colorAggs
// 如果需要进行排序的话,可以使用order(Order.aggregation("avg_price",true))
// "avg_price"对应下班的字聚合的名称,true表示升序排序。false表示倒叙排序
TermsAggregationBuilder colorsAgg = AggregationBuilders
.terms("colors")
.field("color")
.order(Order.aggregation("avg_price", true));
// 平均值
AvgAggregationBuilder avgAgg = AggregationBuilders.avg("avg_price").field("price");
// 最大值a
MaxAggregationBuilder maxAgg = AggregationBuilders.max("max_price").field("price");
// 总和
SumAggregationBuilder sumAgg = AggregationBuilders.sum("sum_price").field("price");
SearchResponse response = srBuilder.setSize(0)
.addAggregation(colorsAgg
.subAggregation(avgAgg)
.subAggregation(maxAgg)
.subAggregation(sumAgg))
.execute()
.actionGet();
Terms terms = response.getAggregations().get("colors");
//处理结果
for (Terms.Bucket entry : terms.getBuckets()) {
Map<String, Object> map = new HashMap<String, Object>();
// 获得按照颜色进行分组的桶
String keyAsString = entry.getKeyAsString();
// 获得每个分组的数量
long docCount = entry.getDocCount();
// 获得平均价格
Avg avg = entry.getAggregations().get("avg_price");
// 获得最大价格
Max max = entry.getAggregations().get("max_price");
// 获得价格总和
Sum sum = entry.getAggregations().get("sum_price");
map.put("key", keyAsString);
map.put("docCount", docCount);
map.put("avg", avg.getValue());
map.put("max", max.getValue());
map.put("sum", sum.getValue());
System.out.println(map);
}
}
3.2 Percentile Aggregation百分比聚合分析
PercentilesAggregationBuilder aggregation =
AggregationBuilders
.percentiles("agg")
.field("height")
.percentiles(1.0, 5.0, 10.0, 20.0, 30.0, 75.0, 95.0, 99.0);
// sr is here your SearchResponse object
Percentiles agg = response.getAggregations().get("agg");
// For each entry
for (Percentile entry : agg) {
double percent = entry.getPercent(); // Percent
double value = entry.getValue(); // Value
}
percent [1.0], value [0.814338896154595]
percent [5.0], value [0.8761912455821302]
percent [25.0], value [1.173346540141847]
percent [50.0], value [1.5432023318692198]
percent [75.0], value [1.923915462033674]
percent [95.0], value [2.2273644908535335]
percent [99.0], value [2.284989339108279]
上边就是我对elasticsearch的聚合分析的一些javaAPI使用的总结,当然我只写出了一部分,强大的elasticsearch还有很多的接口,大家可以通过上边我提供的连接进入elasticsearch的官网进行查询。在前面的文章中我也对elasticsearch的常用搜索、curd、高亮显示、搜索建议进行了记录,如果大家有兴趣可以去翻阅。文章中有哪些地方有误请大家及时指出,感激不尽,相互交流,共同进步!
更多推荐
所有评论(0)