代表性面试主题

数据工程面试:如何让 BI、Notebook 与 API 共用指标语义层?

数据困难
Offer.cc 编辑团队发布 更新

题干

指标定义已经受治理。你会如何把它编译并发布给 BI、Notebook 和 API,处理参数校验、权限、缓存、版本兼容与失败回滚?

题干与适用场景

公司发现“活跃客户”“收入”和“留存率”在不同报表中的 SQL 不一致。请设计一个语义层,让 BI、Notebook、API 和后续自动化代理共享指标定义。需要支持维度、时间粒度、过滤器、权限、历史版本和近实时数据,并说明如何避免把语义层变成另一个不可测试的报表平台。

面试官考察点

强回答会先区分实体、维度、度量、聚合和指标语义,再处理 join 粒度、重复计数、时区和迟到数据。面试官期待候选人把指标当作版本化产品契约:定义、所有者、来源、适用粒度、质量状态和变更兼容性都可审计,而不是只提供一个 SQL 模板目录。

回答前需要澄清的问题

  1. 指标的事实粒度是什么?订单、订单行和事件混用会导致收入重复聚合。
  2. 使用者需要哪些维度与时间粒度?并非所有组合都可安全计算,需声明支持矩阵。
  3. 数据新鲜度与一致性目标是什么?实时指标、日批指标和回补数据的可见状态不同。
  4. 谁能发布定义、谁能读取敏感维度?指标权限不能绕过底层行列级安全。
  5. 需要回溯历史口径还是只看当前口径?答案决定版本路由、快照和重算成本。

推荐方案与推导

建立不可变的指标定义实体:名称、描述、measure 表达式、默认聚合、维度、时间语义、过滤器、数据源、负责人、版本、状态和质量 SLO。查询请求只引用指标 ID、维度和时间窗口,编译器负责生成 SQL 或下推到预聚合表。

在编译前做语义检查:验证 join 路径是否唯一、聚合是否与粒度匹配、过滤器是否允许下推、用户是否拥有列权限。对 count distinct、比率和窗口指标记录分母、去重键和空值策略,禁止让不同工具各自猜测。

yaml
metric: active_customers
version: 3
owner: growth-data
source: mart_customer_daily
measure: count_distinct(customer_id)
dimensions: [plan, region]
time_grain: [day, week, month]
freshness_slo: 2h
status: published

采用双轨发布:新版本先在影子查询中与旧版本对比,再向少量工作区开放;发现差异超过阈值时自动阻断升级。缓存键必须包含 metric version、维度、过滤器和数据水位,否则版本切换会读到旧结果。对高成本查询设置预算、超时和预聚合回退。

替代方案与取舍

把逻辑放在每个 BI 工具里上线快,但定义会分叉;只建一个物理数据集简单,却无法表达多种粒度和权限。集中语义层提供一致性和可复用 API,代价是需要编译器、版本治理、权限映射和故障排查能力。小团队可先从少量核心指标和一个消费端开始,等契约稳定后再开放多工具接入。

失败场景、边界与反例

  • 把“收入”定义成简单 sum(amount),忽略退款、税、币种和订单重复 join。
  • 允许指标定义直接读取任意原始表,绕过质量门禁与列级权限。
  • 修改同一指标的含义却不升版本,历史仪表板悄悄改变结果。
  • 用缓存命中率证明正确性,忽略数据水位、迟到事件和回补期间的可见状态。
  • 为了支持所有维度组合生成笛卡尔积查询,导致成本和延迟不可控;应公开不支持的组合并提供替代聚合。

测试与验证清单

为每个指标保存黄金查询和小型固定数据集,验证聚合、分母、时区、空值、重复 join、迟到事件和版本差异。做 schema、权限、编译器和缓存契约测试;用生产样本进行结果对比和成本回归。发布门禁至少检查定义完整、来源新鲜、质量 SLO 达标、权限映射存在和新旧版本差异在阈值内。

追问与延伸

如何处理指标定义的破坏性变化?

发布新版本并保留旧版本路由,标记弃用时间,通知所有依赖者,等待迁移后再删除。若业务要求同名指标保持稳定,禁止复用版本号;历史报告必须能指定旧版本重算。

语义层如何支持近实时与批处理?

让定义声明来源和数据水位,查询结果携带 freshness 和 completeness 状态。近实时源可以提供临时结果,批处理完成后再校准;两者必须使用相同指标语义和去重规则。

如何限制自然语言或自动化代理误用指标?

只暴露已发布指标、支持的维度和权限范围,返回可解释的查询计划与定义版本。拒绝无法证明粒度、权限或新鲜度的请求,不让模型自由拼接原始表 SQL。

公开来源

同类题目