--- title: "排行榜、趋势图,Easysearch 一次查询全搞定" date: 2026-02-18 lastmod: 2026-02-18 description: "讲解 Easysearch 中 date_histogram 聚合的两种切分方式,通过趋势图和排行榜实例演示如何构建业务报表,涵盖 calendar_interval、fixed_interval 的选择策略和 ECharts 可视化实践" tags: ["时间序列", "数据可视化", "聚合查询"] summary: "在数据统计和可视化场景中,排行榜和趋势图是最常见的图表类型,它们分别用于展示分类排行和时间序列变化。Easysearch 的聚合功能,特别是 date_histogram,能够帮助我们通过一次查询就计算出这些统计结果,并用很少的数据处理工作就绘制出图表。 本文带你从原理到实践逐步掌握如何使用 Easysearch 的 date_histogram 聚合做排行榜和趋势图。 一、Easysearch 简要介绍 # Easysearch 是一款分布式搜索与分析引擎,在支持全文检索能力的基础上,还提供了强大的聚合分析能力,可以对匹配的数据进行统计性的提取。你可以利用聚合完成各种统计分析的任务,而不需要额外的数据库或中间计算层。 聚合分析通常用于构建: 趋势图(时间序列展示) 排行榜(分类排名) 报表统计 实时监控指标 二、date_histogram 聚合:时间统计的核心能力 # 在 Easysearch 中,date_histogram 是最常用、也是最容易产生价值的一类聚合。 它的作用只有一件事: 按照时间维度,把数据切成连续的时间段,并在每个时间段内做统计。 只要你的数据中存在时间字段(如日志时间、下单时间、事件发生时间),date_histogram 几乎都是构建趋势图、排行榜和监控看板的首选工具。 2.1 date_histogram 是如何工作的 # 从行为上看,date_histogram 的工作方式可以理解为三步: 读取每条数据的时间字段 按指定规则,将时间划分成一个个“时间桶” 每个时间桶内,统计文档数量或子聚合结果 最终返回的不是单条数据,而是一组按时间顺序排列的统计结果,非常适合直接用于图表展示。 2.2 两种时间切分方式:calendar_interval 与 fixed_interval # 在使用 date_histogram 时,最核心的选择其实只有一个: 时间是按照“日历概念”切,还是按照“固定时长”切? Easysearch 提供了两种方式,分别对应两个参数。 2.2.1 calendar_interval:按自然日历切分 # calendar_interval 使用的是日历语义,例如: { "date_histogram": { "field": "@timestamp", "calendar_interval": "day" } } 含义是:" --- 在数据统计和可视化场景中,**排行榜和趋势图**是最常见的图表类型,它们分别用于展示分类排行和时间序列变化。Easysearch 的聚合功能,特别是 `date_histogram`,能够帮助我们通过一次查询就计算出这些统计结果,并用很少的数据处理工作就绘制出图表。 本文带你从原理到实践逐步掌握如何使用 Easysearch 的 `date_histogram` 聚合做排行榜和趋势图。 --- ## 一、Easysearch 简要介绍 Easysearch 是一款分布式搜索与分析引擎,在支持全文检索能力的基础上,还提供了强大的聚合分析能力,可以对匹配的数据进行统计性的提取。你可以利用聚合完成各种统计分析的任务,而不需要额外的数据库或中间计算层。 聚合分析通常用于构建: - 趋势图(时间序列展示) - 排行榜(分类排名) - 报表统计 - 实时监控指标 --- ## 二、`date_histogram` 聚合:时间统计的核心能力 在 Easysearch 中,`date_histogram` 是最常用、也是最容易产生价值的一类聚合。 它的作用只有一件事: **按照时间维度,把数据切成连续的时间段,并在每个时间段内做统计。** 只要你的数据中存在时间字段(如日志时间、下单时间、事件发生时间),`date_histogram` 几乎都是构建趋势图、排行榜和监控看板的首选工具。 --- ### 2.1 `date_histogram` 是如何工作的 从行为上看,`date_histogram` 的工作方式可以理解为三步: 1. 读取每条数据的时间字段 2. 按指定规则,将时间划分成一个个“时间桶” 3. 每个时间桶内,统计文档数量或子聚合结果 最终返回的不是单条数据,而是**一组按时间顺序排列的统计结果**,非常适合直接用于图表展示。 --- ### 2.2 两种时间切分方式:`calendar_interval` 与 `fixed_interval` 在使用 `date_histogram` 时,最核心的选择其实只有一个: **时间是按照“日历概念”切,还是按照“固定时长”切?** Easysearch 提供了两种方式,分别对应两个参数。 --- #### 2.2.1 `calendar_interval`:按自然日历切分 `calendar_interval` 使用的是**日历语义**,例如: ```json { "date_histogram": { "field": "@timestamp", "calendar_interval": "day" } } ``` 含义是: - 一天,指的是自然日(00:00 ~ 24:00) - 一周,指的是自然周 - 一个月,长度会随月份变化 这种方式**更符合人的直觉**,非常适合业务报表和运营分析。 常见使用场景包括: - 每日 / 每周 / 每月趋势图 - 运营数据报表 - 按自然周期统计的排行榜 --- #### 2.2.2 `fixed_interval`:按固定时间长度切分 `fixed_interval` 使用的是**绝对时间长度**,不关心日历含义: ```json { "date_histogram": { "field": "@timestamp", "fixed_interval": "1h" } } ``` 这表示: - 每 1 小时切一个时间桶 - 无论是否跨天、跨月 - 每个时间桶长度始终一致 可以把它理解为: **“从某个时间点开始,每隔固定时间统计一次”** 常见的 `fixed_interval` 值包括: - `5m`:每 5 分钟 - `1h`:每 1 小时 - `30s`:每 30 秒 --- #### 2.2.3 两者的直观区别 用一句话概括区别: **calendar_interval 关心“这是哪一天” \*\***fixed_interval 关心“过了多久时间”\*\* 从实践角度看: | 场景 | 推荐方式 | | -------------------- | ----------------- | | 业务趋势、日报、周报 | calendar_interval | | 实时监控、指标统计 | fixed_interval | | 滚动窗口分析 | fixed_interval | | 运营分析 | calendar_interval | --- ### 2.3 一个容易被忽略但很重要的选择 在实际项目中,很多趋势图“看起来不对”,并不是数据问题,而是: - 该用 `calendar_interval` 的地方用了 `fixed_interval` - 或者反过来 例如: - 用 `fixed_interval: 24h` 画“每日订单趋势” - 在跨时区或夏令时场景下,图表可能出现错位 因此,在写 `date_histogram` 之前,**先明确业务语义**,再选择参数,往往比调优更重要。 --- ### 2.4 小结 `date_histogram` 看起来只是一个聚合参数,但它决定了: - 时间如何被理解 - 趋势图是否可信 - 排行榜统计口径是否一致 记住一个简单原则即可: **自然周期 → calendar_interval \*\***固定频率 → fixed_interval\*\* 掌握这一点,`date_histogram` 的大部分使用问题,就已经解决了一半。 --- ## 三、使用 `date_histogram` 做趋势图 趋势图通常用于展示某个指标随时间的变化,例如每天的访问量、每日订单数量等。 ### 1. 场景:统计每日访问量趋势 假设我们有一个日志索引 `logs`,其中包含时间字段 `@timestamp`(UTC 格式),我们希望统计过去一段时间内每天访问次数。 --- ### ① 聚合查询 ```json GET logs/_search { "size": 0, "aggs": { "daily_visits": { "date_histogram": { "field": "@timestamp", "calendar_interval": "day", "format": "yyyy-MM-dd" } } } } ``` 这条聚合表示: - 按天进行分桶 - 每个桶表示某一天范围 - 每个桶返回该天的数据数量(文档数) --- ### ② 返回结果结构示例 ```json { "aggregations": { "daily_visits": { "buckets": [ { "key_as_string": "2026-01-01", "key": 1738252800000, "doc_count": 1590 }, { "key_as_string": "2026-01-02", "key": 1738339200000, "doc_count": 1842 }, { "key_as_string": "2026-01-03", "key": 1738339200000, "doc_count": 2156 }, { "key_as_string": "2026-01-04", "key": 1738339200000, "doc_count": 2367 } ] } } } ``` 说明: - `key_as_string` 是时间段标签 - `doc_count` 是该段内匹配的数据量 --- ### ③ ECharts 折线图的可视化示例 如果使用 ECharts 可视化上述趋势图: ```js // 假设 response 即上面聚合结果 const buckets = response.aggregations.daily_visits.buckets; // 1. 提取坐标数据 const xAxisData = buckets.map((b) => b.key_as_string); const seriesData = buckets.map((b) => b.doc_count); // 2. 配置 ECharts const option = { title: { text: "每日访问趋势" }, tooltip: { trigger: "axis" }, xAxis: { type: "category", data: xAxisData, }, yAxis: { type: "value" }, series: [ { name: "访问量", type: "line", data: seriesData, smooth: true, }, ], }; chart.setOption(option); ``` ![](/img/knowledge-base/usage/easysearch-leaderboard-and-trend-charts/image-1.png) 这个折线图可以直观地帮助你看到每天访问量的波动趋势。 --- ## 四、用 `date_histogram` 做排行榜 你也可以结合分组聚合,在时间维度和其他字段上构建更复杂的排行榜。 ### 1. 场景:每周热门产品排行 现在假设有订单索引 `orders`,其中包含: - `order_time` 时间字段 - `product_id` 产品字段 我们想统计过去一段时间内**每周销量排行榜**。 --- ### ① 聚合查询结构 ```json GET orders/_search { "size": 0, "aggs": { "weekly": { "date_histogram": { "field": "order_time", "calendar_interval": "week", "format": "yyyy-MM-dd" }, "aggs": { "top_products": { "terms": { "field": "product_id.keyword", "size": 10 } } } } } } ``` 这条查询做了: - 按周分桶 - 每周内部按产品分组并统计数量 --- ### ② 返回结果结构示例(简化) ```json { "aggregations": { "weekly": { "buckets": [ { "key_as_string": "2026-01-03", "top_products": { "buckets": [ { "key": "P1", "doc_count": 140 }, { "key": "P2", "doc_count": 98 }, { "key": "P3", "doc_count": 226 } ] } } ] } } } ``` 每周的桶里,有一个大的 `top_products` 子聚合,用来展示产品排行榜。 ![](/img/knowledge-base/usage/easysearch-leaderboard-and-trend-charts/image-2.png) --- ### ③ 排行榜可视化实践 结合 ECharts,你可以为每个时间点生成一个排行榜视图,常见做法: - 柱状图展示某个时间段内 Top N 排行 - 多维折线图(产品销量随时间变化趋势) 以下示例展示单周内的柱状图: ```js // 选取某一桶 const bucket = response.aggregations.weekly.buckets[0]; const productBuckets = bucket.top_products.buckets; // ECharts 数据转换 const xAxisData = productBuckets.map((p) => p.key); const seriesData = productBuckets.map((p) => p.doc_count); const option = { title: { text: `周销量排行榜(${bucket.key_as_string})` }, tooltip: {}, xAxis: { type: "category", data: xAxisData, }, yAxis: { type: "value" }, series: [ { name: "销量", type: "bar", data: seriesData, }, ], }; chart.setOption(option); ``` --- ## 五、更多进阶用法 ### 1. 结合子聚合计算指标 你可以在 `date_histogram` 内进一步加入指标聚合,例如计算每段的总销售额: ```json "aggs": { "daily_sales": { "date_histogram": { "field": "order_time", "calendar_interval": "day", "format": "yyyy-MM-dd" }, "aggs": { "total_amount": { "sum": { "field": "amount" } } } } } ``` 在每一天分桶内,会输出 `total_amount.value` 总销售额数据,可以在趋势图中画折线显示金额。 --- ## 六、使用建议与注意事项 ### 1. 合理选择时间粒度 粒度太细(如按分钟)可能会产生大量桶,影响性能;而粒度太粗则可能失去趋势细节。根据数据密度与展示需求调整 `calendar_interval`。 ### 2. 时间格式输出 通过 `format` 参数可以设置时间字符串格式,便于图表展示。 ### 3. 时区问题 默认情况下,时间按 UTC 存储并计算。如果要显示本地时间,需要在聚合中设置 `time_zone` 参数。 --- ## 七、总结 通过 `date_histogram` 聚合,Easysearch 能够轻松实现: - **趋势图**(如每日/每周数据变化) - **排行榜**(时间分段内分组排行) 而且所有统计都可以通过一条请求完成。这不仅减少了后端计算与数据搬运工作,还能显著提升报表与看板的实时性。 一句话总结:**排行榜 + 趋势图,用 Easysearch 一次查询就能搞定。**