深入 Kibana 05 - Discover:交互式检索的执行模型
打开 Discover 不等于只发出一次搜索请求。字段侧边栏、顶部直方图和文档表格各自需要不同的数据,它们围绕同一查询状态触发 field caps、聚合与文档检索。Discover 的核心因此更接近多请求编排器,而不是“搜索框加表格”。
Discover 的请求拓扑
1 | |
上面这条链路描述的是经典 KQL / Data View 路径。当前 Discover 还支持 ES|QL:切到 ES|QL 后,查询可以直接针对索引运行,不再依赖 Data View,字段侧边栏和文档表格的生成路径也会随之改变。
字段侧边栏:field_caps API
Discover 左侧的字段列表不是直接读 Data View 的字段配置,而是通过 field_caps API 实时查询索引的字段能力集,再与 Data View 的元数据合并渲染。
field_caps 返回的每个字段包含:
1 | |
aggregatable: true 的字段在侧边栏会显示"可视化"快捷按钮;searchable: true 的字段可以在 KQL 里按 field:value 过滤。两者都是 false 的字段在侧边栏仍然列出(通常来自 _ignored 之类的元字段)但标为不可用。
字段侧边栏里的文档频率和 top values(点击字段展开后显示)来自另一类内嵌聚合请求:对该字段发一个 terms 聚合,取 top N 个值及其计数。这个请求是懒触发的,点击字段展开时才发。
直方图:date_histogram 聚合的参数逻辑
顶部柱状图是一次 date_histogram 聚合,核心参数:
1 | |
时间粒度(fixed_interval)由 Discover 根据时间范围动态选择:时间范围越大,粒度越粗(天/小时),时间范围越小,粒度越细(分/秒)。这个计算是客户端逻辑,使目标桶数大约保持在屏幕像素数的合理范围内。
size: 0 是关键:直方图请求只要聚合结果,不需要任何文档,这个请求和文档请求 [3] 是并发发出的,互不阻塞。
自 Kibana 8.x 起,直方图的时间粒度可在 Discover 的图表设置里手动固定;若不手动设置,仍走自动档。
文档表格:search_after 翻页
文档表格的翻页采用 search_after 机制,而不是传统的 from + size。
传统 from + size:
1 | |
问题:ES 需要在内存中排序并丢弃前 10000 条,深度翻页时内存开销随 from 线性增长,默认有 index.max_result_window: 10000 限制。
search_after 机制:
1 | |
search_after 不需要在内存中保留跳过的文档,每次翻页是 O(1) 内存开销(相对于 from)。Discover 文档表格的"加载更多"按钮就是在这个游标上追加。
sort 数组里额外带上 _id 的原因:时间戳相同的文档必须有确定的排序,否则分页边界不稳定,会出现重复或跳过。
列选择与 Discover session
Discover 的列选择(文档表格里显示哪些字段)直接影响请求 [3] 的 fields 参数。7.12 起,Discover 默认使用 fields API;当时仍可通过 Advanced Settings 回退到 _source。Kibana 9.0 移除了 discover:searchFieldsFromSource,这条回退路径随之消失。fields API 能按 mapping 返回 runtime fields、field aliases 和规范化后的字段值。
点击“Save”保存当前 Discover 视图,当前 UI 称其为 Discover session。底层仍写入一个 type: search 的 Saved Object,它的 attributes 里包含:
1 | |
这个 Saved Object 的 references 数组里有一条指向所用 Data View 的引用。其他组件(Dashboard Embeddable、Visualize 基于 Saved Search 建图)通过 references 找到这个依赖,确保 Data View 存在时才渲染。
上下文文档(Surrounding Documents)
Discover 文档表格每行有一个展开按钮,还有一个"查看上下文文档"链接。点击后,Kibana 额外发两条请求:
1 | |
两条请求的 query 里包含当前 Discover 的全部 filters,只放开时间范围约束,用相邻时间范围替代。结果就是"在当前过滤条件下,这条日志前后各 5 条"。
实验:用 Inspect 面板捕获三类请求
以下步骤在 Kibana 7.x/8.x Discover 界面均可执行:
-
打开 Discover,选择一个日志类 Data View(含
@timestamp字段),设置时间范围为最近 1 小时。 -
点击 Discover 右上角 Inspect 按钮,展开 Requests 标签,观察页面加载时发出了几条请求——应该能看到至少两条:直方图请求(名称通常含 “Chart”/“Histogram”)和文档请求(名称通常含 “Documents”)。
-
展开直方图请求的 Request 面板,验证:
size: 0(不返回文档)aggs.histogram.date_histogram存在,field为 Data View 的时间字段query.bool.filter包含时间范围
-
展开文档请求的 Request 面板,验证:
size等于页面大小(默认 500)sort含时间字段降序 +_id作为决定性排序键fields数组只包含侧边栏选中的列_source: false
-
缩小时间范围到最近 5 分钟,重新观察直方图请求,确认
fixed_interval变细(秒级)。 -
在侧边栏点击一个 keyword 字段展开 top values,打开 Inspect 观察是否新增了一条
terms聚合请求。
模式提炼
1 | |
工程迁移表
| Discover 概念 | 工程类比 |
|---|---|
| field_caps API → 字段侧边栏 | GraphQL introspection → schema explorer |
| date_histogram size:0 → 直方图 | SQL SELECT date_trunc, COUNT(*) GROUP BY 独立查询 |
| 父 Search Source 继承 | React Context / 依赖注入:全局 filter 下沉到子查询 |
| search_after 翻页 | keyset pagination(cursor-based)vs offset pagination |
columns → fields 参数 |
GraphQL field selection,只请求需要的列 |
Discover session → search Saved Object |
查询书签 / 视图配置持久化 |
| Surrounding Documents | 日志系统"上下文行"功能(Loki LogQL context) |
| Grafana Explore | 与 Discover 同构的日志探索 UI,查询模型不同(Loki/Tempo/Prom) |
常见误解
误解一:“Discover 每次刷新只发一条 ES 请求”。打开 Discover 至少触发三类请求,其中 field_caps 和直方图在很多场景下并发发出,文档请求紧随其后。用 Inspect 面板或浏览器 DevTools Network 标签可以看到全部请求。
误解二:“Discover 的分页是 from+size,翻到一万条后会报错”。Discover 默认用 search_after,不受 index.max_result_window 限制。from+size 限制只影响显式写 from 参数的请求(包括某些旧版 Kibana 的聚合和自定义脚本)。
误解三:“字段侧边栏显示的 top values 是实时的全量统计”。侧边栏的 top values 是对当前时间范围内的 terms 聚合,受时间范围限制,不是对整个索引的全量统计;点击字段展开时才触发,不是预加载。
误解四:“保存 Discover 视图只保存了搜索条件”。Discover session 还保存列配置、排序以及 Search Source(含 KQL query 和 filter pills)。Dashboard 嵌入这类 panel 时会加载整个 search Saved Object,包括列和过滤器;“Saved Search”是历史 UI 名称和常见内部称呼。
练习
-
在 Discover 的 Inspect 面板里找到直方图请求和文档请求,确认两者共享相同的
query.bool.filter内容(除时间范围桶参数外),验证父子 Search Source 继承关系在 network 层的体现。 -
把 Discover 列配置改为只显示
status、method两列,再打开 Inspect 查看文档请求的fields参数——验证确实只请求了这两个字段,而不是_source: true。保存为 Discover session,用GET api/saved_objects/_find?type=search找到刚保存的对象,读它的columns和searchSourceJSON。 -
思考题:search_after 翻页要求排序键在分页边界上是稳定且唯一的(因此加
_id)。在自己的业务系统里,如果要对一张没有自增主键的宽表实现无限滚动翻页,应该用哪个字段或字段组合作为游标?如果时间戳精度不够(同毫秒多条),有什么兜底策略?
系列导航
参考资料
- Kibana 官方文档 Discover:https://www.elastic.co/guide/en/kibana/current/discover.html
- ES field_caps API:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-field-caps.html
- ES search_after 文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/paginate-search-results.html#search-after
- ES date_histogram aggregation:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html
- Kibana Saved Objects API:https://www.elastic.co/guide/en/kibana/current/saved-objects-api.html
- Discover 7.12 默认使用 fields API:https://www.elastic.co/jp/blog/discover-uses-fields-api-in-7-12
- Kibana breaking changes:https://www.elastic.co/docs/release-notes/kibana/breaking-changes
- 保存 Discover session:https://www.elastic.co/docs/explore-analyze/discover/save-open-search
- Kibana 源码 Discover plugin:https://github.com/elastic/kibana/tree/main/src/platform/plugins/shared/discover
