🧑 博主简介:CSDN博客专家 ,历代文学网 (PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索"历代文学 ")总架构师,
15年
工作经验,精通Java编程
,高并发设计
,Springboot和微服务
,熟悉Linux
,ESXI虚拟化
以及云原生Docker和K8s
,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作 请加本人wx(注明来自csdn ):foreast_sea
【Elasticsearch】聚合分析:度量聚合
引言
在当今数据爆炸的时代,如何从海量的数据中提取有价值的信息成为了众多开发者和数据分析师面临的重要挑战。Elasticsearch 作为一款强大的分布式搜索引擎,不仅具备高效的搜索功能,还提供了丰富的聚合分析能力,其中度量聚合是其核心功能之一。
想象一下,你正在处理一个电商平台的销售数据,数据量庞大且复杂。你可能需要了解某个时间段内的总销售额,以便评估业务的整体表现;或者想知道各类商品的平均售价,从而制定更合理的价格策略;亦或是找出销量最高和最低的商品,为库存管理提供依据。这些看似复杂的数据分析需求,在 Elasticsearch 的度量聚合功能面前都能迎刃而解。
度量聚合能够对数据进行各种计算,像 sum(求和) 、avg(平均值) 、max(最大值) 、min(最小值) 、count(计数) 等。通过这些计算方式,我们可以快速地从数据中获取关键的统计信息,帮助我们做出更明智的决策。而且,度量聚合并非孤立存在,它常常与桶聚合相结合。桶聚合就像是一个个"桶",将数据按照不同的维度进行分组,而度量聚合则在这些分组的"桶"内对数据进行具体的统计计算,从而为我们提供更详细、更有针对性的分析结果。
在接下来的文章中,我们将深入探讨 Elasticsearch 度量聚合的各种计算方式,通过实际的 Java API 案例展示如何在不同场景下运用这些功能。同时,我们还会详细介绍相关的 Maven 依赖,帮助大家搭建起开发环境,让大家能够轻松地将 Elasticsearch 度量聚合应用到自己的项目中,挖掘数据背后的价值。
一、Elasticsearch 度量聚合基础概念
1.1 什么是度量聚合
度量聚合是 Elasticsearch 聚合分析中的一种类型,它主要用于对文档中的数值字段进行统计计算。与其他类型的聚合(如桶聚合用于分组数据)不同,度量聚合的重点在于对数据进行数值上的操作,以获取诸如总和、平均值、最大值等统计信息。
例如,在一个包含员工薪资信息的索引中,我们可以使用度量聚合来计算所有员工的总薪资、平均薪资等。通过这些计算结果,我们可以快速了解薪资的整体情况,为人力资源决策提供数据支持。
1.2 常见的度量聚合函数
1.2.1 sum(求和)
sum
函数用于计算指定字段的所有文档值的总和。比如,在电商销售数据中,我们可以使用 sum
函数计算某个时间段内所有订单的总金额。假设我们有一个名为 orders
的索引,其中每个文档代表一个订单,包含 amount
字段表示订单金额。通过 sum
聚合,我们可以轻松得到所有订单的总销售额。
1.2.2 avg(平均值)
avg
函数用于计算指定字段的平均值。继续以上述电商销售数据为例,使用 avg
函数可以计算出每个订单的平均金额。这对于了解客户的平均消费能力非常有帮助,商家可以根据这个平均值来制定营销策略,比如推出适合平均消费层次的套餐。
1.2.3 max(最大值)
max
函数用于找出指定字段中的最大值。在员工薪资数据中,使用 max
函数可以找到薪资最高的员工的薪资值。这对于了解公司的薪资上限,以及与市场上同行业最高薪资进行对比具有重要意义。
1.2.4 min(最小值)
min
函数与 max
函数相反,它用于找出指定字段中的最小值。在库存管理中,我们可以使用 min
函数找到某种商品的最小库存数量,以便及时补货,避免缺货情况的发生。
1.2.5 count(计数)
count
函数用于统计文档的数量。在一个博客文章索引中,使用 count
函数可以统计文章的总数。这对于了解博客的内容规模,以及评估博客的活跃度等方面都有一定的参考价值。
二、Maven 依赖介绍
2.1 Elasticsearch 客户端依赖
要在 Java 项目中使用 Elasticsearch 的度量聚合功能,首先需要引入 Elasticsearch 客户端依赖。目前,Elasticsearch 官方推荐使用 Elasticsearch Java High Level REST Client。
在 pom.xml
文件中添加以下依赖:
xml
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.4</version>
</dependency>
这个依赖提供了与 Elasticsearch 进行交互的高级 REST 客户端接口。它基于 Elasticsearch 的 REST API,通过简单易用的 Java 代码来操作 Elasticsearch。例如,我们可以使用这个客户端来发送请求、执行查询和聚合操作等。
2.2 Elasticsearch 核心依赖
除了客户端依赖,还需要引入 Elasticsearch 的核心依赖:
xml
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.17.4</version>
</dependency>
这个核心依赖包含了 Elasticsearch 的基本功能和核心类库。它是整个 Elasticsearch 运行的基础,提供了数据存储、索引构建、搜索算法等核心功能。在我们进行度量聚合操作时,底层的计算和数据处理都依赖于这个核心库。
2.3 其他相关依赖
根据项目的具体需求,可能还需要引入一些其他的依赖。例如,如果需要处理 JSON 数据,可能需要引入 Jackson 相关的依赖:
xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency>
Jackson 是一个非常流行的 JSON 处理库,它可以帮助我们将 Java 对象转换为 JSON 格式,以及将 JSON 数据解析为 Java 对象。在与 Elasticsearch 进行交互时,很多数据都是以 JSON 格式传输的,因此 Jackson 库可以方便我们对数据进行处理。
另外,如果项目中使用了日志框架,比如 Log4j,还需要引入相应的依赖:
xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
日志框架可以帮助我们记录程序运行过程中的重要信息,包括 Elasticsearch 操作的日志。通过分析这些日志,我们可以及时发现问题,优化程序性能。
三、Java API 实现度量聚合案例
3.1 简单度量聚合案例
3.1.1 求和案例
假设我们有一个名为 products
的索引,每个文档代表一个产品,包含 price
字段表示产品价格。我们要计算所有产品的总价格。
java
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.metrics.Sum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
public class SumAggregationExample {
public static void main(String[] args) throws Exception {
// 创建 RestHighLevelClient
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
// 创建搜索请求
SearchRequest searchRequest = new SearchRequest("products");
// 创建搜索源构建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(AggregationBuilders.sum("total_price").field("price"));
searchRequest.source(searchSourceBuilder);
// 执行搜索请求
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 获取聚合结果
Sum totalPrice = searchResponse.getAggregations().get("total_price");
System.out.println("所有产品的总价格: " + totalPrice.getValue());
// 关闭客户端
client.close();
}
}
在这个案例中,我们首先创建了一个 RestHighLevelClient
实例,用于与 Elasticsearch 进行通信。然后,我们创建了一个 SearchRequest
对象,指定要搜索的索引为 products
。接着,使用 SearchSourceBuilder
构建搜索请求的源,通过 aggregation
方法添加了一个 sum
聚合,指定聚合名称为 total_price
,要计算的字段为 price
。执行搜索请求后,从响应中获取聚合结果,并打印出所有产品的总价格。
3.1.2 平均值案例
计算所有产品的平均价格:
java
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.metrics.Avg;
import org.elasticsearch.search.builder.SearchSourceBuilder;
public class AvgAggregationExample {
public static void main(String[] args) throws Exception {
// 创建 RestHighLevelClient
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
// 创建搜索请求
SearchRequest searchRequest = new SearchRequest("products");
// 创建搜索源构建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.aggregation(AggregationBuilders.avg("average_price").field("price"));
searchRequest.source(searchSourceBuilder);
// 执行搜索请求
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 获取聚合结果
Avg averagePrice = searchResponse.getAggregations().get("average_price");
System.out.println("所有产品的平均价格: " + averagePrice.getValue());
// 关闭客户端
client.close();
}
}
此案例与求和案例类似,只是将 sum
聚合替换为 avg
聚合,通过 AggregationBuilders.avg
方法指定聚合名称和要计算平均值的字段,最终获取并打印出所有产品的平均价格。
3.2 在桶聚合基础上使用度量聚合
3.2.1 按类别分组并计算每个类别的总销售额
假设我们的 products
索引中还包含 category
字段表示产品类别。我们要按类别分组,并计算每个类别的总销售额。
java
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.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
public class CategorySumAggregationExample {
public static void main(String[] args) throws Exception {
// 创建 RestHighLevelClient
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http")));
// 创建搜索请求
SearchRequest searchRequest = new SearchRequest("products");
// 创建搜索源构建器
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("category_buckets").field("category");
termsAggregationBuilder.subAggregation(AggregationBuilders.sum("total_sales_per_category").field("price"));
searchSourceBuilder.aggregation(termsAggregationBuilder);
searchRequest.source(searchSourceBuilder);
// 执行搜索请求
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 获取桶聚合结果
ParsedTerms categoryBuckets = searchResponse.getAggregations().get("category_buckets");
for (Terms.Bucket bucket : categoryBuckets.getBuckets()) {
String category = bucket.getKeyAsString();
Sum totalSales = bucket.getAggregations().get("total_sales_per_category");
System.out.println("类别: " + category + ", 总销售额: " + totalSales.getValue());
}
// 关闭客户端
client.close();
}
}
在这个案例中,我们首先使用 AggregationBuilders.terms
方法创建了一个桶聚合,将数据按 category
字段分组,聚合名称为 category_buckets
。然后,在这个桶聚合的基础上,通过 subAggregation
方法添加了一个 sum
聚合,计算每个类别中的总销售额,聚合名称为 total_sales_per_category
。执行搜索请求后,我们遍历桶聚合的结果,获取每个类别的名称和对应的总销售额,并进行打印。
四、总结
通过本文的介绍,我们深入了解了 Elasticsearch 的度量聚合功能,包括常见的度量聚合函数如 sum
、avg
、max
、min
和 count
等,以及如何在 Java 项目中使用最新的 Java API 实现这些度量聚合操作。同时,我们详细介绍了相关的 Maven 依赖,帮助大家搭建起开发环境。
度量聚合在数据分析中具有重要的作用,它能够帮助我们快速获取数据的统计信息,为决策提供有力支持。而将度量聚合与桶聚合相结合,更是能够让我们对数据进行更细致、更深入的分析。希望大家在实际项目中能够灵活运用 Elasticsearch 的度量聚合功能,挖掘出数据背后的潜在价值。
参考资料文献
- Elasticsearch 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html
- Elasticsearch Java High Level REST Client 官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html
- 《Elasticsearch 实战》,作者:Radu Gheorge,出版社:人民邮电出版社