尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

数据质量管理平台:需求文档拆解、规则落地与告警SLA

数据质量管理平台:需求文档拆解、规则落地与告警SLA 简介这是一份面向数据治理从业者、数据平台产品经理与项目开发人员的数据质量管理平台需求文档以PDF形式系统梳理了从项目立项到功能落地的完整建设思路。文档先在项目介绍部分界定数据质量的含义明确准确性、完整性、一致性、时效性、有效性与可追溯性六大要素并结合数字化转型背景阐述建设目标随后在业务方案中给出模块化系统架构与整体要求强调灵活适配多业务场景与定制化规则。功能设计部分重点展开模板管理与规则管理覆盖内置模板、模板创建、查询、修改、审批以及规则的创建、查询、修改、导出与审批并延伸至任务管理等环节同时提及数据源管理、元数据管理、异常检测、性能监控与用户权限控制等配套能力。资源包为单个PDF文件约1.81MB目录层级清晰便于按章节检索。目前已有443人学习适合用于需求调研、方案撰写与投标参考。1. 一份《数据质量管理平台需求文档.pdf》落到手里先别数规则条数《数据质量管理平台需求文档.pdf》发到项目群里通常三十到八十页。第 3 页写着核心指标准确率不低于 99.9%第 17 页写着数据及时性要求 T1 早 8 点前就绪附录 A 贴了上百条校验规则第 40 页开始是字段清单。评审会开到第三轮业务方和技术方还在争同一个问题订单表里同一个用户同一秒下了两单到底算不算重复数据。这种扯皮的根源不在规则写得不细而在需求文档缺了前置的一层——数据分级和指标口径。没有分级所有表都按核心表处理几万条规则同时跑平台上线第一周就被误报淹掉没有口径准确率三个字的分子分母谁说了算都定不下来规则写完也没法验收。所以拿到文档的第一件事是把附录和正文拆开正文做分级和口径附录做规则映射需求条目和规则 ID 之间建一张追溯表。这套拆法适合数据平台工程师、数仓开发和数据治理岗也适合被拉来评审的业务方代表。后面按需求拆解、规则落地、告警 SLA、验收追溯四段推进每一段都给可直接抄的配置和 SQL。2. 数据质量管理平台需求文档的六个质量维度拆成可测指标2.1 把数据要准确翻译成可执行断言的映射表需求文档里的形容词几乎不能直接实现。及时完整一致这些词在评审会上人人在点头落到调度系统里没人知道阈值填几。常见的做法是先把它们归到六个维度上完整性、准确性、一致性、唯一性、有效性、及时性。归完之后每个维度再选一到两种可测的断言形式需求才算能进开发排期。维度文档常见原文可测定义计算口径典型阈值完整性用户资料不能缺关键字段非空率非空行数 / 总行数≥ 99.5%准确性金额要准与上游源表金额差异行占比差异行数 / 总行数≤ 0.1%一致性主数据要统一维表关联未命中率未命中行数 / 事实表行数≤ 0.5%唯一性主键不能重复主键重复组数重复主键组数 / 总组数 0有效性状态值要在枚举内越界值行占比越界行数 / 总行数≤ 0.05%及时性数据要早点到分区就绪时间就绪时间 - 业务日期 00:00≤ 8 小时这张表是需求文档评审的锚点。业务方说准确率 99.9%就让他在这张表上指一下是哪个维度、哪个字段、哪个时间窗口指不出来说明需求还没成型。2.2 指标口径表里必须写清的五件事同一个订单准确率数仓团队算出来 99.7%业务口径算出来 98.2%两边都没错差在时间窗口和过滤条件上。口径表要解决的就是这件事每一条指标至少写清五个要素缺一个就会出现两套数字。时间窗口按业务日期分区还是按事件发生时间滑动 7 天两者在跨天补数时结果完全不同过滤条件是否剔除测试账号、内部订单、退款冲正记录剔除清单要落到具体的枚举值主键定义唯一性校验以哪个字段组合为准复合主键的字段顺序要不要敏感分母选择总行数是全表行数、当期分区行数还是关联后的有效行数容忍度阈值是绝对值还是百分比超过阈值是阻断还是只告警口径表用一张配置表存下来和规则元数据放同一个库评审改动留痕。常见做法是给每条口径配一个版本号规则执行结果里带上版本号回溯历史时能还原当时的定义。CREATE TABLE dq_metric_def ( metric_id VARCHAR(64) NOT NULL COMMENT 指标编码如 order_amount_acc, metric_name VARCHAR(128) NOT NULL COMMENT 指标中文名, quality_dim VARCHAR(32) NOT NULL COMMENT 质量维度, table_name VARCHAR(128) NOT NULL COMMENT 目标表, dt_column VARCHAR(64) NOT NULL COMMENT 分区字段一般为 dt, time_window INT NOT NULL DEFAULT 1 COMMENT 窗口天数1 表示当天, filter_expr VARCHAR(512) DEFAULT COMMENT 过滤条件 SQL 片段, primary_keys VARCHAR(256) NOT NULL COMMENT 主键字段逗号分隔, threshold DECIMAL(10,6) NOT NULL COMMENT 阈值, threshold_type VARCHAR(16) NOT NULL DEFAULT ratio COMMENT ratio 或 abs, version INT NOT NULL DEFAULT 1 COMMENT 口径版本号, PRIMARY KEY (metric_id, version) );建表时把metric_id和version组成联合主键口径调整时不覆盖旧行新增一行版本号加一。校验结果表里同时落metric_id和version半年后追查某天的异常告警能确认当时用的是哪版口径。filter_expr只放 WHERE 片段不要放整条 SQL避免规则文本里出现分号造成注入和拼接歧义。2.3 需求文档评审阶段要问出口的七个问题评审会不是读文档是拿问题逼出可实现的约束。下面七个问题按经验能覆盖大部分后期返工点每个问题都要当场拿到明确答复拿不到就记成待定项别写进排期。这条规则的失败是阻断下游任务还是仅记录阈值是业务方拍的数字还是根据最近 30 天历史数据算出的基线规则的校验对象是当天分区、近 7 天滚动还是全量快照校验失败后由谁处理处理时限是多久超时升级给谁上游表结构变更时规则是自动失效还是报错阻塞同一条规则在多个下游复用时阈值是否允许按下游覆盖规则的准确率本身怎么验证会不会出现规则错了还天天告警的情况第 7 个问题最容易被跳过。规则本身也会出错比如把合法的负数金额当成异常。常见做法是给新上线的规则先跑一到两周的观察模式只记录不告警用真实数据反算阈值确认误报率低于 5% 再切成生效状态。3. 把需求文档里的规则落成可调度的校验 SQL3.1 四类断言模板覆盖八成规则需求文档附录里那两百条规则逐条写 SQL 是最费人力也最容易失控的做法。归类之后会发现绝大多数能归到四类断言单字段约束、枚举范围、跨表参照、跨表对账。为每类写一个模板规则只填参数新增一条规则的成本从写半小时 SQL 降到填一行配置。断言类型适用场景模板骨架关键参数单字段约束非空、唯一、格式匹配对目标列做聚合统计列名、正则枚举范围状态码、渠道码越界值不在白名单内计数白名单集合跨表参照事实表关联维表维表关联未命中计数关联键跨表对账双跑比对、上下游核对按主键全外连接求差主键、比对列、容差对账类规则要特别处理容差。金额字段做等值比较几乎必然失败浮点误差和上游四舍五入都会造成假差异。模板里加一个abs(a.amt - b.amt) 0.01的容差条件比事后解释误报省事得多。-- 跨表对账模板按主键全外连接找出金额差异超容差的行 SELECT COUNT(1) AS total_cnt, SUM(CASE WHEN COALESCE(a.amt, 0) COALESCE(b.amt, 0) THEN 1 ELSE 0 END) AS bad_cnt FROM ( SELECT order_id, SUM(pay_amt) AS amt FROM dwd_order_pay WHERE dt :biz_date GROUP BY order_id ) a FULL OUTER JOIN ( SELECT order_id, SUM(settle_amt) AS amt FROM dwd_order_settle WHERE dt :biz_date GROUP BY order_id ) b ON a.order_id b.order_id WHERE ABS(COALESCE(a.amt, 0) - COALESCE(b.amt, 0)) 0.01 OR a.order_id IS NULL OR b.order_id IS NULL;这条 SQL 一次性给出总行数和差异行数两个值外层total_cnt是本侧和对方去重后的主键并集。FULL OUTER JOIN保证只在上游存在和只在下游存在的记录都能被抓出来COALESCE处理 NULL 参与比较时返回 NULL 导致条件失效的问题。容差 0.01 按业务金额最小单位定如果是分成比例这类小数容差要跟着放大到 1e-6 量级。3.2 规则元数据表让规则可配置而不是写死在脚本里规则写进脚本的后果是每改一次阈值就走一次发版流程。把规则抽成配置表调度程序只做读取、渲染、执行、落库四步阈值调整在后台改一行数据即可生效。CREATE TABLE dq_rule_meta ( rule_id VARCHAR(64) NOT NULL COMMENT 规则唯一编码, metric_id VARCHAR(64) NOT NULL COMMENT 关联的口径定义, table_name VARCHAR(128) NOT NULL COMMENT 校验目标表, dt_column VARCHAR(64) NOT NULL DEFAULT dt, rule_type VARCHAR(32) NOT NULL COMMENT not_null/enum/ref/recon, target_col VARCHAR(256) DEFAULT COMMENT 目标列多列逗号分隔, rule_expr VARCHAR(1024) DEFAULT COMMENT 枚举集合或参照表表达式, window_days INT NOT NULL DEFAULT 1 COMMENT 校验窗口天数, threshold DECIMAL(10,6) NOT NULL COMMENT 触发阈值, rule_level VARCHAR(16) NOT NULL DEFAULT warn COMMENT block/warn/info, silence_days INT NOT NULL DEFAULT 3 COMMENT 同规则连续告警静默天数, enabled TINYINT NOT NULL DEFAULT 1, owner VARCHAR(64) NOT NULL COMMENT 责任人, PRIMARY KEY (rule_id) );rule_level决定告警走的通道block直接卡住下游调度warn发企业微信或邮件info只写进日报。silence_days是误报治理的关键参数同一条规则在静默期内重复失败只累加计数不再重复推送默认给 3 天核心链路可以给 1 天。window_days控制扫描范围超过 7 天的窗口在亿级表上会明显拖慢调度需要配合分区裁剪使用。3.3 用 Python 读规则配置并执行校验调度层不承担业务逻辑只做模板渲染和结果落库。下面这段代码可以直接挂到 Airflow 或 Azkaban 的任务里按rule_type分组拉取规则逐条执行后把总行数、异常行数、异常比例和阈值一起写入结果表。import logging from datetime import datetime, timedelta from sqlalchemy import create_engine, text logging.basicConfig(levellogging.INFO) engine create_engine( mysqlpymysql://dq_user:pwddq-host:3306/dq, pool_pre_pingTrue, pool_recycle1800, ) # 四类断言的 SQL 模板{col} {tbl} {dt} {expr} 由规则配置填充 TEMPLATES { not_null: ( SELECT COUNT(1) AS total_cnt, SUM(CASE WHEN {col} IS NULL OR TRIM(CAST({col} AS STRING)) THEN 1 ELSE 0 END) AS bad_cnt FROM {tbl} WHERE {dt} BETWEEN :d_start AND :d_end ), enum: ( SELECT COUNT(1) AS total_cnt, SUM(CASE WHEN {col} NOT IN ({expr}) THEN 1 ELSE 0 END) AS bad_cnt FROM {tbl} WHERE {dt} BETWEEN :d_start AND :d_end ), } INSERT_RESULT text( INSERT INTO dq_check_result (rule_id, biz_date, total_cnt, bad_cnt, bad_ratio, threshold, passed, checked_at) VALUES (:rule_id, :biz_date, :total, :bad, :ratio, :threshold, :passed, NOW()) ) def render(rule, biz_date): 按规则类型渲染 SQL窗口天数决定起止分区 d_end biz_date d_start biz_date - timedelta(daysrule[window_days] - 1) sql TEMPLATES[rule[rule_type]].format( colrule[target_col], tblrule[table_name], dtrule[dt_column], exprrule[rule_expr], ) return sql, {d_start: d_start, d_end: d_end} def run(rule, biz_date): sql, params render(rule, biz_date) with engine.connect() as conn: total, bad conn.execute(text(sql), params).fetchone() ratio 0.0 if not total else round(bad / total, 6) passed ratio float(rule[threshold]) conn.execute(INSERT_RESULT, { rule_id: rule[rule_id], biz_date: biz_date, total: total, bad: bad, ratio: ratio, threshold: rule[threshold], passed: 1 if passed else 0, }) conn.commit() logging.info(rule%s total%s bad%s ratio%s passed%s, rule[rule_id], total, bad, ratio, passed) return passedrender里把窗口天数换算成起止分区BETWEEN两端都闭避免补数窗口漏掉边界那天。pool_pre_ping和pool_recycle是长跑调度的必要设置否则任务跑几小时后连接被服务端断开会抛异常。bad_ratio保留六位小数再入库百分比展示交给前端避免下游做二次除法时精度丢失。判断通过与否统一用ratio threshold比值型阈值走这条路径绝对值型阈值需要在渲染阶段把total_cnt换成bad_cnt比较配置里用threshold_type区分。3.4 校验任务上线后最常见的三个坑NULL 语义是第一坑。col X在col为 NULL 时返回 NULL计数条件不成立异常行被静默放过。所有涉及比较的表达式外面套一层COALESCE或者显式用IS NULL OR写法。时间窗口边界是第二坑。滚动 7 天窗口在月初跑时如果上游某天分区缺失BETWEEN会把缺失那天当作零行处理分母变小比例虚高。规则里加一条前置判断分区不存在直接标记为数据未就绪不参与质量分计算。全表扫描是第三坑。SELECT COUNT(1)在 Hive 上也会拉全表分区裁剪失效时一条规则能跑几十分钟。确认dt_column出现在 WHERE 条件里并且和分区字段完全一致用EXPLAIN看执行计划里的Partition Count是否符合预期。4. 数据质量管理平台的告警分级与 SLA 落地4.1 阻断级、严重级、观察级的分级依据告警不分级的结果是所有人都把告警当背景噪音。分级不能按重要程度这种主观词来分要有可判断的客观依据通常看两个维度这条规则的下游影响面以及历史上这条规则的稳定性。级别判定依据通知方式响应时限是否阻塞调度阻断 block核心表主键唯一性或对账差异电话 群30 分钟是严重 warn核心表非空率、枚举越界超标群 邮件2 小时否观察 info非核心表、新上线规则日报汇总次日否新规则一律先进观察级。用一到两周真实数据跑出bad_ratio的分布取 P95 作为阈值的下界再往上留 20% 余量定成正式阈值比凭经验拍的阈值误报率低得多。阈值定完后把rule_level从info改成对应级别改动的记录留在规则表里。4.2 质量分和 SLA 达成率的 SQL 实现单个规则通过与否只是点管理层要看的是面。质量分通常按规则级别加权阻断级权重最高算出当天每个表、每个主题域的分值SLA 达成率则是按时间统计达标天数占总天数的比例。-- 按天、按表计算加权质量分阻断级权重 5严重级 3观察级 1 WITH weighted AS ( SELECT r.biz_date, m.table_name, SUM(CASE WHEN r.passed 0 THEN CASE r.rule_level WHEN block THEN 5 WHEN warn THEN 3 ELSE 1 END ELSE 0 END) AS fail_weight, SUM(CASE r.rule_level WHEN block THEN 5 WHEN warn THEN 3 ELSE 1 END) AS total_weight FROM dq_check_result r JOIN dq_rule_meta m ON m.rule_id r.rule_id WHERE r.biz_date DATE_SUB(:biz_date, INTERVAL 29 DAY) GROUP BY r.biz_date, m.table_name ) SELECT biz_date, table_name, ROUND(1 - fail_weight / NULLIF(total_weight, 0), 4) AS quality_score FROM weighted ORDER BY biz_date DESC, quality_score ASC;NULLIF(total_weight, 0)防止某天规则全部停用导致除零。30 天窗口是常见选择既能看出趋势又不至于让历史问题长期压低当前分值。质量分低于 0.95 的表在日报里标红低于 0.9 触发一次专项排查。SLA 达成率在质量分基础上再加一层时间判断把分区就绪时间作为独立指标和分值并排展示避免数据准确但迟到这种情况被质量分掩盖。4.3 误报治理静默期、白名单和去重窗口误报治理做不好平台三个月后就没人看告警了。三个手段按性价比排序静默期最省事白名单最精准去重窗口最治本。def should_notify(rule, history, biz_date): 三级过滤静默期 - 白名单 - 去重窗口 # 1. 静默期同规则连续失败天数未达阈值不重复推送 fail_days sum(1 for h in history if h[passed] 0) if fail_days rule[silence_days]: return False, within_silence_window # 2. 白名单命中豁免清单的行不参与判定 if is_whitelisted(rule[rule_id], biz_date, rule.get(whitelist)): return False, whitelisted # 3. 去重窗口同一规则 6 小时内只推一次 last last_notify_time(rule[rule_id]) if last and (datetime.now() - last).total_seconds() 6 * 3600: return False, duplicated_in_6h return True, notifysilence_days配成 3 意味着持续失败到第四天才第一次推送短时抖动完全被吸收。白名单按rule_id加业务日期维度维护比如大促当天某些渠道码临时扩充提前把枚举白名单挂上去避免当天刷几百条告警。去重窗口 6 小时是经验值阻断级告警建议缩短到 1 小时甚至不启用去重因为阻断级每一条都需要人跟进。5. 用需求追溯矩阵验证平台是否真的按文档落地5.1 需求条目到规则 ID 的追溯矩阵验收阶段最怕的情况是需求文档里某条要求从头到尾没人实现也没人发现。追溯矩阵解决这个问题把文档里每条可验收的需求编号和规则 ID、口径 ID、责任人对应起来缺哪一列一眼能看出来。需求编号文档原文摘要口径 ID规则 ID责任人状态DQ-001订单主键不可重复order_pk_uniqR_ORDER_PK_01张三已上线DQ-014支付金额与结算金额一致order_amount_accR_RECON_PAY_02李四已上线DQ-027用户资料关键字段完整user_profile_compR_USER_NN_05王五观察期DQ-033维表关联未命中率低于 0.5%dim_ref_rateR_REF_DIM_03张三待开发矩阵里的状态只有四种待开发、观察期、已上线、已下线。审批时只允许在相邻状态之间流转下线必须写原因。每季度拿这张矩阵和文档正文对一遍文档改版后新增的需求条目如果两周内没有对应的规则 ID直接进风险清单。5.2 用对账 SQL 验证质量分本身是否可信规则跑得再勤质量分算错一样白搭。验证方法不复杂手工抽一批样本用独立脚本重算和平台落库的分值比对差异超过容差说明计算链路有问题。抽样要覆盖通过和失败两种规则只看失败的会漏掉假阴性。-- 平台分值 vs 手工重算分值差异超过 0.01 的规则进入复核清单 SELECT p.rule_id, p.biz_date, p.bad_ratio AS platform_ratio, ROUND(h.bad_cnt / NULLIF(h.total_cnt, 0), 6) AS manual_ratio, ABS(p.bad_ratio - ROUND(h.bad_cnt / NULLIF(h.total_cnt, 0), 6)) AS diff FROM dq_check_result p JOIN dq_manual_sample h ON h.rule_id p.rule_id AND h.biz_date p.biz_date WHERE ABS(p.bad_ratio - ROUND(h.bad_cnt / NULLIF(h.total_cnt, 0), 6)) 0.01 ORDER BY diff DESC;抽样脚本要和调度脚本用不同的 SQL 写法实现比如调度用COUNT(1) CASE WHEN抽样用SUM加子查询写法不同但结果必须一致。两条路径算出同样结果才能排除模板渲染阶段的列名错位或过滤条件丢失。复核清单超过总数的 3% 时先停下来查模板不要继续加规则。矩阵和抽样之外还有一个容易被忽略的检查点规则覆盖率。把文档里所有字段清单导出来和dq_rule_meta里的target_col做反连接找出没有任何规则覆盖的字段。核心表的关键字段覆盖不到 80% 时平台看上去在跑实际上核心问题依然靠人肉发现。覆盖率的统计 SQL 和上面这条对账 SQL 可以放进同一个巡检任务每天凌晨跑完增量校验后自动输出一份缺口清单按表名和字段数排序优先补前二十个字段的规则。本文还有配套的精品资源点击获取
返回列表