Skip to main content
 首页 » 编程设计

Elasticsearch聚合教程

2022年07月19日118duanxz

Elasticsearch聚合教程

虽然Elasticsearch不是关系型数据库,但也可以对查询结果进行聚合,尤其需要对文档进行分组统计分析是非常有用。
本文主要介绍Elasticsearch的聚合特性。首先介绍聚合主要概念,如分组和度量。然后描述一些主要聚合类型,最后展示如何通过Java API进行实现。

1 分组和度量

Elasticsearch中聚合主要基于两个概念:分组(buckets)和度量(buckets)。

分组是匹配条件的文档集合,执行Elasticsearch时检查每个文档属于那个分组。例如对age字段进行聚合,那么age=30的文档属于一组,而age=40的文档属于另一组。分组可以进行嵌套,意味着我们可以对30和40年龄的文档集合进行子分组,如分为男性和女性。

通常情况下,度量是分析分组文档集合的一些算术操作。通过度量可以计算每个分组的文档数量、特定字段值求和等。因此,可以计算住在北京的30岁员工的平均工作。

因此可以认为聚合是分组和度量的组合,它们可以单独应用,一起使用、甚至嵌套使用,如前面描述示例中的嵌套分组。相比于SQL语言,分组可以理解为group by子句,而度量类似于COUNT(field), SUM(field), AVG(field) 等。

2 聚合类型

Elasticsearch实现了不同类型的聚合。一些是关系型数据库中已经存在,一些类型聚合关系型数据库没有。首先先看几个主流算术运算类型集合,与关系型数据库几乎一致:

  • min: 返回分组文档的最小值.
  • max: 返回分组文档的最大值.
  • sum: 对特定字段进行求和.
  • avg: 技术特定字段平均值.

这些聚合的值可以从特定字段抽取,也可以从字段和脚本中抽取,如对计算值增加一些比例。
另外一类聚合关注分析文档而不是计算文档,主要包括:

  • filter: 对聚合文档进行过滤。因此可以搜索结果中的部分文档进行聚合,过滤聚合在嵌套聚合中非常有用。
  • range: 进行特定范围进行分组。如我们可以对员工进行年龄范围机型分组: 0-18, 18-25, 25-30, 30-40 等.
  • terms: 按照词条进行分组。词条是直接从定义字段中抽取,或脚本动态计算获取。
  • missing: 对没有特定字段或其值null的文件进行聚合。

聚合也可以区分文档结构:

  • children: 应用于父子文档的聚合。
  • nested:实现嵌套文档聚合。

除此之外,还有地址位置和日期时间聚合等。

3 Java API实现聚合

在实际应用中有些聚合很常用,因此需要定义工具类,使得代码可以重用。下面定义QueryAggs类:

public final class QueryAggs { 
  
  private QueryAggs() { 
    throw new ConstructorNotInvokableException(); 
  } 
  
  public static SumAggregationBuilder concededHome() { 
    return AggregationBuilders.sum("goals_conceded_home").field("guestGoals"); 
  } 
  
  public static MaxAggregationBuilder maxHostGoals() { 
    return AggregationBuilders.max("goals").field("hostGoals"); 
  } 
  
  public static TermsAggregationBuilder season() { 
    return AggregationBuilders.terms("group_by_season").field("season"); 
  } 
  
  public static TermsAggregationBuilder score() { 
    return AggregationBuilders.terms("scores") 
      .script("doc['hostGoals'].value.toString() + ':' + doc['guestGoals'].value.toString()"); 
  } 
  
} 

我们看到聚合主要通过org.elasticsearch.search.aggregations.AggregationBuilders工具类进行构造,其提供工厂方法初始化特定类型的聚合:sum, avg, script 或 terms等。这些聚合继承自org.elasticsearch.search.aggregations.ValuesSourceAggregationBuilder,该类是所有基于字段聚合类的父类。其他聚合继承自抽象构建器:AggregationBuilder 或 AbstractRangeBuilder。

前节我们提到聚合可以嵌套。代码上通过AggregationBuilder类的subAggregation(AbstractAggregationBuilder aggregation)方法实现。该方法内置了子聚合列表,源码如下:

    public AB subAggregation(AggregationBuilder aggregation) { 
        if (aggregation == null) { 
            throw new IllegalArgumentException("[aggregation] must not be null: [" + name + "]"); 
        } 
        factoriesBuilder.addAggregator(aggregation); 
        return (AB) this; 
    } 

可以在执行响应上通过org.elasticsearch.search.aggregations.bucket.terms.InternalTerms抽象类的getBuckets()方法获取所有分组,也可以调用类的public Terms.Bucket getBucketByKey(String term)方法直接访问特定分组。

4 总结

聚合即分组和度量的组合。elasticsearch提供不同类型的聚合,如算术操作聚合、分析类型聚合、嵌套聚合等,Java Api也有相应实现进行支持。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/102740813
阅读延展