上一篇(第 06 篇)展示了 Visualize 手动配置聚合的模型:每一个 bucket aggregation 和 metric aggregation 都需要用户逐个展开下拉框选择。Lens 想回答的问题是:当用户把一个字段拖到画布上时,系统能不能根据字段类型直接给出一个合理的聚合方案,而不是等用户自己配?

字段类型到聚合的映射

Lens 拿到一个字段后,它首先读取该字段在 Data View 里登记的类型。映射规则如下:

1
2
3
4
5
6
7
字段类型 → 默认聚合

keyword / ip / boolean → terms(top N 分组)
date → date_histogram(时间分桶)
number(metric 位置) → avg
number(bucket 位置) → histogram / range
geo_point → geotile_grid(地图场景)

这不是硬编码的枚举,而是 Lens 内部的 operation catalog。每种 operation 声明它接受哪些字段类型(allowedInputTypes),Kibana 8.x 的 x-pack/plugins/lens/public/indexpattern_datasource/operations/ 目录下每个 operation 都是独立模块,自描述自己的约束。拖字段时,Lens 的 datasource 层过滤出与该字段类型兼容的 operation 列表,取优先级最高的一个作为默认值。

这解释了一个常见现象:把同一个字段拖到 X 轴和 Y 轴,Lens 会选不同的聚合——X 轴(dimension)更倾向于 bucket 语义,Y 轴更倾向于 metric 语义,即使字段类型相同。

Suggestion 引擎

字段映射只解决了"聚合选什么",图表类型的推断由 suggestion 引擎负责。

1
2
3
4
5
6
7
8
用户拖入字段序列 → suggestion 引擎 → 候选图表列表(按置信度排序)

规则示例:
1 个 date + 1 个 number → line chart(首选)/ bar chart / area
1 个 keyword + 1 个 number → bar chart(横向或纵向)
1 个 keyword + 2 个 number → stacked bar / grouped bar
2 个 number → scatter plot / metric
geo_point → maps(如果 Maps 插件已安装)

suggestion 引擎在 x-pack/plugins/lens/public/chart_info_badges/ 和各个图表类型的 getSuggestions 方法里实现。每种图表类型(如 xy_visualizationpie_visualizationmetric_visualization)各自定义:接受哪种字段维度组合、输出置信度分数。引擎汇总所有图表类型的打分,按分数降序排列,显示为 Lens 右侧面板的"Suggestions"列表。

当用户调整字段组合时,suggestion 列表实时刷新。这意味着 Lens 不是预先规定"两个字段只能画折线图",而是每次都重新评估所有图表类型对当前维度组合的兼容性。

Layer 模型

1
2
3
4
5
6
7
8
Lens 画布
└── Layer 0(主层)
├── X 轴 dimension → 字段 A(date → date_histogram)
├── Y 轴 dimension → 字段 B(number → avg)
└── breakdown → 字段 C(keyword → terms)
└── Layer 1(附加层,可选)
├── 类型:reference line / annotation
└── 独立的 data source 或表达式

一个 Lens 画布可以有多个 layer。常见用法是在 time series 上叠加一条阈值参考线(reference line layer),或者叠加事件注解(annotation layer)。不同 layer 可以共享同一个 data source,也可以各自绑定不同的 index pattern。每个 layer 的聚合结果独立计算,最终在渲染层合并到同一张图上。

Formula:computed metric

Lens 的 formula 功能允许在 Y 轴输入表达式而不是单选一个聚合函数:

1
2
3
4
5
6
formula 示例:

count() / overall_sum(count()) → 各桶占总量比例
moving_average(sum(bytes), window=7) → 7 期移动平均
differences(sum(bytes)) → 相邻桶差值
sum(bytes) / max(bytes) → 归一化后的值

formula 表达式被 Lens 的表达式引擎解析成一个 pipeline,在 ES 的 aggregation 层(bucket_script、moving_avg 等)执行,不在 Kibana 侧做二次计算。这意味着 formula 的计算精度和性能取决于 ES 管道聚合的能力,而不是 JavaScript。

为什么 Lens 取代了 Visualize

Visualize(传统面板编辑器)与 Lens 的根本差异在于配置入口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Visualize 工作流:
选图表类型 → 手动配置 bucket agg → 手动配置 metric agg → 预览

Lens 工作流:
拖字段 → 系统推断聚合 → suggestion 引擎推荐图表类型 → 调整

Visualize 劣势:
- 配置顺序固定;改图表类型通常需要重新配置聚合
- 不同图表类型的编辑界面各自独立,学习成本高
- 无法跨图表类型复用配置状态

Lens 优势:
- 字段维度和聚合逻辑解耦;换图表类型时维度配置保留
- formula 支持管道聚合的表达式化
- layer 模型支持在同一画布叠加多种数据层
- 与 Dashboard 的 Embeddable 框架深度集成(inline editing)

Kibana 8.x 官方文档明确标注 Lens 为推荐的可视化编辑器。Visualize 仍然保留(主要是历史 Dashboard 的兼容),但新功能只在 Lens 里迭代。

Lens Saved Object 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
Saved Object type: lens

attributes
├── title 图表名称
├── description
├── visualizationType "lnsXY" / "lnsPie" / "lnsMetric" ...
├── state
│ ├── datasourceStates
│ │ └── formBased(或 textBased)
│ │ └── layers: { layerId → { columnOrder, columns } }
│ └── visualization
│ └── 各图表类型自有的配置(X/Y 轴绑定、颜色、图例等)
└── references → 引用的 index-pattern(Data View)

columns 里每一列就是一个 operation 配置,包含字段名、聚合类型、参数(如 terms 的 size)。Lens 的 “Inspect” 面板会展示最终发给 ES 的聚合 JSON,这是验证推断结果是否符合预期的直接手段。

实验:观察推断差异

在 Lens 编辑器里,依次拖以下三种字段到 X 轴维度,记录每次 Lens 自动选择的聚合类型,然后用 Inspect(图表右上角 → Inspect → Requests)查看实际发给 ES 的聚合 JSON:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
实验序列:

1. 拖一个 keyword 字段到 X 轴
预期:terms aggregation,size=5(默认)

2. 拖一个 date 字段到 X 轴
预期:date_histogram,interval 由 Lens 自动计算(auto)

3. 拖一个 number 字段到 X 轴
预期:histogram aggregation,interval 由字段值域推断

4. 再拖一个 number 字段到 Y 轴
预期:avg aggregation(若字段在 Y 轴位置)

对比在 Visualize 里需要点多少步配置才能达到同样结果

Inspect 面板里的 Request 标签页会展示完整的 ES 请求 body,其中 aggs 节点就是 Lens 推断并生成的聚合定义。这与 Visualize 需要手动配置后才能在 Inspect 里看到的 aggs 直接对应。

将实验结果映射到内部对象

1
2
3
4
5
6
7
用户操作               → Lens 内部对象               → ES 请求

拖 keyword 到 X 轴 → TermsIndexPatternColumn → { terms: { field, size } }
拖 date 到 X 轴 → DateHistogramIndexPatternColumn → { date_histogram: { field, calendar_interval } }
拖 number 到 Y 轴 → AvgIndexPatternColumn → { avg: { field } }
输入 formula 表达式 → FormulaIndexPatternColumn → { bucket_script: { ... } }
添加 reference line → 独立 Layer(非聚合) → 单独 ES 请求或客户端常量

每种 Column 类型都在 Lens 的 operation 模块里有对应的 toEsAggsFn 方法,负责把 column 配置序列化成 ES aggregation 参数。

模式提炼

1
2
3
4
5
6
7
8
9
10
11
12
模式:字段类型驱动的聚合推断 + suggestion 引擎的图表推荐

核心机制:
1. operation catalog 声明兼容类型,拖入时过滤并排序候选
2. suggestion 引擎由各图表类型自述兼容性并打分,汇总后排序
3. layer 模型把"多套数据叠加"从特殊功能变成组合基元
4. formula 把管道聚合的组合能力暴露为文本表达式

可迁移的设计原则:
- 把用户输入(字段)和系统决策(聚合、图表类型)分层
- "推荐 + 可覆盖"优于"必填 + 空白":给默认值,但允许手工改
- 把图表类型从中央注册表改成各自声明 getSuggestions,利于扩展

工程迁移表

Lens 概念 Grafana 对应 Tableau 对应 Power BI 对应
Operation catalog(字段 → 聚合) Query 字段配置(手动) "Show Me"自动推断聚合 自动汇总(SUM/COUNT 推断)
Suggestion 引擎 无内置(靠用户选面板类型) Show Me(基于维度/度量组合) Auto-visualization hint
Layer 模型 多 series + override 多 mark layer 叠加图层
Formula(管道聚合表达式) 计算字段(Transforms) 计算字段(LOD 表达式) DAX 计算列 / 度量
Lens Saved Object Panel JSON 工作簿 XML pbix 二进制
Inline editing(Dashboard 内直接编辑) Grafana 8+ 面板内编辑 Dashboard 内编辑 报表内编辑

常见误解

误解一:“Lens 只能画简单图,复杂聚合还是要用 Visualize”。formula 功能已经覆盖了移动平均、差值、百分比等管道聚合场景。Visualize 的手动配置能表达的聚合,Lens 通过 operation catalog 和 formula 基本都能覆盖,差异主要在旧版本或特定图表类型。

误解二:“Lens 的图表类型比 Visualize 少”。Kibana 8.x 中 Lens 已经包含折线、柱状、面积、饼图、环形图、热力图、散点、Metric、Gauge、Waffle 等主流类型。Visualize 中部分类型(如 TSVB、Vega)是独立编辑器,不归属于 Lens,但这不代表 Lens 图表类型少。

误解三:“拖字段后 Lens 就直接发请求”。Lens 有一个 debounce 机制,配置变更会短暂等待后再触发查询,避免在拖拽过程中发出大量中间状态的请求。

误解四:“Lens 公式和 Elasticsearch Painless 脚本是一回事”。Lens formula 被编译成 ES 的标准聚合(bucket_script、moving_avg 等),不涉及 Painless 脚本。Painless 是 ES 侧的脚本执行能力,用在 runtime fields 和 script query 里。

练习

  1. 在 Lens 编辑器中,分别把 keyword、date、number 三种类型的字段拖到 Y 轴(metric 位置),观察每次自动选中的 operation 名称,然后在 Inspect → Requests 里找到对应的 ES aggregation JSON,确认推断的聚合类型与字段类型的对应关系。

  2. 用 formula 实现"每个 bucket 的值占所有 bucket 总和的百分比":在 Y 轴输入 count() / overall_sum(count()) * 100,用 Inspect 查看生成的 ES bucket_script 结构,理解 overall_sum 如何映射为 pipeline aggregation。

  3. 建一个双 layer 图表:Layer 0 是正常的时序折线,Layer 1 是一条固定值的 reference line。观察 Inspect 里 Layer 0 和 Layer 1 各自发出了什么 ES 请求(或 Layer 1 是否发请求)。

系列导航

序号 主题 状态
00 导读:Kibana 的状态存在 Elasticsearch 里
01 Kibana 架构:浏览器、Node.js server 与 New Platform
02 Saved Object:Kibana 一切状态的统一模型
03 Data View(Index Pattern):查询之前的字段抽象
04 Search Source 与查询翻译:KQL、Lucene 与 Query DSL
05 Discover:一次查询的完整执行路径
06 Visualize:手动聚合配置的模型
07 Lens:拖拽背后的自动聚合推断 本篇
08 TSVB、Timelion 与 Vega:时序与自定义可视化 下一篇
09 Dashboard 与 Embeddable:面板的组合与依赖
10 Alerting 框架:Rule、Connector 与 Action
11 Reporting:从 Dashboard 到 PDF/PNG
12 Task Manager:分布式任务调度
13 Spaces 与安全:RBAC、Feature Controls
14 插件体系:New Platform 的 setup/start 生命周期
15 性能模型:bundle、bootstrap 与异步搜索会话
16 Kibana vs Grafana:两种可视化平台的设计取舍
17 演进:从纯前端到 New Platform 再到 Serverless

参考资料