资讯详情

资讯详情

数据质量管理平台需求文档与SQL校验:六维规则到闭环验收

简介这份《数据质量管理平台需求文档》面向数据治理产品经理、数据架构师及企业信息化建设人员用于梳理数据质量平台从立项到功能落地的完整需求。文档围绕数据质量六要素——准确性、完整性、一致性、时效性、有效性与可追溯性展开依次阐述项目背景与目标、模块化系统架构与整体要求并细化模板管理中的内置模板、创建、查询、修改与审批流程以及规则管理、任务管理等设计要点同时对数据源管理、元数据管理、异常检测、性能监控和权限控制提出要求可作为需求评审、方案编写与选型的参考底稿。资源为1个PDF文件压缩包约1.81MB内容以目录化章节组织便于按模块快速定位。目前已有443人学习浏览适合需要搭建数据质量体系或撰写同类需求文档的读者对照使用。1. 数据质量管理平台需求文档到底该定什么需求评审会上最常出现的场景业务方在文档里写「数据要准、要全、要及时」研发追问「准到几个九、哪个字段、几分钟内到」然后会议就卡住了。数据质量管理平台需求文档的真正价值不是描述这个平台有哪些菜单和看板而是把「数据好」这句形容词拆成可判定、可执行、可验收的条目。它必须回答三个问题规则从哪里来、规则用什么跑、跑出不合格之后谁在多久内处理。这三件事没写清后面无论用多贵的调度和存储平台都只是个报表工具。适合读这份文档的人包括数据开发、数据治理、测试以及握着指标口径的业务负责人——尤其是最后这一类因为准确性规则的定义权往往在他们手里而不是在数仓团队手里。判断一份需求文档能不能落地最简单的标准是把文档交给一个不熟悉业务的数据开发他能不能在不追问的情况下写出一条校验 SQL。2. 把需求文档拆成六维数据质量规则表2.1 六个维度的判定口径和最容易混的地方数据质量维度是需求文档的骨架但写得最乱的也是它。常见做法是固定六个完整性、唯一性、准确性、一致性、及时性、有效性。每个维度的判定必须落到一个可计算的表达式上否则就是形容词。维度判定问题典型表达式常见误用完整性该有的值有没有col IS NULL OR TRIM(col)的空值率把「默认值 -1」当成有值唯一性主键/业务键是否重复GROUP BY key HAVING COUNT(*)1用自增主键查重永远通过准确性值与真实世界是否一致值域、正则、与主数据比对没有真值来源就声称「准确率 99%」一致性同一事实在不同表是否相同跨表 JOIN 差异率把跨系统一致性当跨表一致性及时性数据在 SLA 内是否就绪分区就绪时间 vs 承诺时间只看任务成功不看数据到达有效性值是否符合业务规范枚举码表、格式、区间与完整性混为一谈准确性和有效性是最容易写虚的两项。准确性依赖外部真值如果需求文档给不出真值来源就应该把它降级成「与上游系统对账一致」而不是硬凑一个准确率。有效性则要有明确的码表或格式定义例如手机号^1[3-9]\d{9}$、订单状态属于{10,20,30,40}。2.2 需求条目到规则元数据的字段映射需求文档里一句话最终要变成一条结构化记录。字段不齐的规则在执行层一定会出问题——最常见的是漏了「责任人」和「例外清单」导致告警发出来没人认领或者把内部测试账号当成脏数据反复报警。文档里的写法规则元数据字段是否必填「订单表用户 ID 不能为空」table/column/dimension必填「空值率不超过 0.5%」threshold/compare_op必填「每天 T1 校验」schedule/biz_date_offset必填「P1 级问题 30 分钟内响应」severity/sla_minutes/owner必填「测试账号除外」exception_list选填「超过 1000 万行抽样」sample_rate/max_scan_rows选填把这套映射写进文档附录评审时逐条对照能省掉后面大量的返工。经验上一份规则条数在 200 条左右的平台需求元数据字段缺项超过三成执行层就必然要打补丁。2.3 用 pdfplumber 把规则表抽成 JSON 配置需求文档以 PDF 交付时规则表往往是最难处理的部分——跨页表头、合并单元格、全角空格。常见做法是先抽出表格再人工核对而不是指望一次全自动。下面这段脚本把 PDF 中的规则表提取成待确认的 JSON 列表import json import re import pdfplumber # 需要抽表的页码范围1-based跨页表格要连续写 PAGES list(range(6, 15)) COLUMNS [rule_id, domain, table, column, dimension, expression, threshold, severity, owner] def clean(cell): if cell is None: return # 去掉换行、全角空格和多余空白PDF 里这几种字符混用很常见 return re.sub(r[\s\u3000], , str(cell)).strip() rules [] with pdfplumber.open(数据质量管理平台需求文档.pdf) as pdf: for pno in PAGES: page pdf.pages[pno - 1] # 默认按线框识别无框线表格可改用 {vertical_strategy: text} table page.extract_table({ vertical_strategy: lines, horizontal_strategy: lines, snap_tolerance: 3, }) if not table: continue for row in table: cells [clean(c) for c in row] if len(cells) ! len(COLUMNS): continue # 跳过重复表头 if cells[0] in (规则编号, rule_id): continue rules.append(dict(zip(COLUMNS, cells))) with open(dq_rules_draft.json, w, encodingutf-8) as f: json.dump(rules, f, ensure_asciiFalse, indent2) print(f抽出 {len(rules)} 条待确认规则)逻辑说明PAGES按 PDF 实际页码填写表头所在页和跨页续页都要包含extract_table的策略参数决定识别方式有线框的表格用lines靠空白对齐的表格改成textsnap_tolerance控制线框容差设得过大相邻两列会被合并设得过小则同一行被拆成多行。参数说明clean()里同时处理半角空白和全角空格\u3000这是 PDF 抽表最典型的坑TRIM不掉的「空值」多半是它列数校验len(cells) ! len(COLUMNS)用来丢弃合并单元格导致的错行宁可漏抽也不要错抽抽出的结果命名为_draft强制走一遍人工确认因为规则表达式一旦抽错后续校验结果会静默失真。3. 数据质量管理平台校验执行层的 SQL 编写3.1 单表字段级校验的 SQL 模板执行层的第一原则是校验 SQL 必须与业务查询共用同一套表不要再复制一份数据。完整性校验的模板如下返回的是一行统计结果而不是明细这样即使表很大也不会把结果集撑爆。-- 完整性按业务日期分区统计空值率 SELECT ${bizdate} AS biz_date, dwd_order AS tbl_name, user_id AS col_name, COUNT(*) AS total_cnt, SUM(CASE WHEN user_id IS NULL OR TRIM(user_id) THEN 1 ELSE 0 END) AS null_cnt, ROUND(SUM(CASE WHEN user_id IS NULL OR TRIM(user_id) THEN 1 ELSE 0 END) / COUNT(*), 6) AS null_rate FROM dwd_order WHERE dt ${bizdate};逻辑说明整条语句只扫一个分区${bizdate}由调度系统注入null_rate保留 6 位小数避免小样本下 0.0001 被判成 0。参数说明若表没有dt分区必须补一个时间范围条件否则全表扫描会拖垮集群当单分区行数超过max_scan_rows时加TABLESAMPLE (10 PERCENT)并同步把阈值判定改成「抽样空值率」同时在告警文案里标明是抽样结果。唯一性校验要返回重复键样本否则问题无法定位-- 唯一性找出重复的业务主键LIMIT 防止明细过多 SELECT order_id, COUNT(*) AS dup_cnt FROM dwd_order WHERE dt BETWEEN ${start_date} AND ${end_date} GROUP BY order_id HAVING COUNT(*) 1 ORDER BY dup_cnt DESC LIMIT 100;这里用业务主键order_id而不是自增 ID。窗口建议取 7 天而非单日因为重复数据常常跨分区产生只看当天会漏掉。3.2 跨表一致性校验与口径对齐一致性规则最难的不是 SQL而是对齐两边的口径一边统计的是支付成功金额另一边统计的是下单金额差异率天然存在规则上线第一天就会误报。写规则前必须确认四件事——过滤条件、时间口径、币种/单位、是否含退款。-- 一致性订单表与支付表的金额差异率 SELECT COUNT(*) AS join_cnt, SUM(CASE WHEN ABS(o.pay_amt - p.pay_amt) 0.01 THEN 1 ELSE 0 END) AS diff_cnt, ROUND(SUM(CASE WHEN ABS(o.pay_amt - p.pay_amt) 0.01 THEN 1 ELSE 0 END) / COUNT(*), 6) AS diff_rate FROM dwd_order o JOIN dwd_pay p ON o.order_id p.order_id AND p.dt ${bizdate} WHERE o.dt ${bizdate};参数说明0.01是浮点容忍度若两列都是DECIMAL(18,2)可直接用比较使用JOIN而非LEFT JOIN时join_cnt会小于订单总数只能反映「两边都存在的记录」如果要看支付缺失必须再单独加一条左连接统计p.order_id IS NULL的规则。这两条规则经常被合并成一条写结果既测不出缺失也测不出金额差。3.3 调度、增量与采样参数怎么设全量校验在数据量上到千万级之后基本不可持续主流做法是走增量水位线只校验新变更的数据-- 增量水位线取上一次成功校验之后的最大更新时间 SELECT COALESCE(MAX(update_time), 1970-01-01 00:00:00) AS watermark FROM dwd_order WHERE dt ${bizdate};参数作用建议取值concurrency同时执行的规则数集群队列的 1/3留出业务任务余量retry_times单条规则失败重试2 次且重试前先判断上游任务状态timeout_minutes单条规则超时P1 规则 10 分钟P2 规则 30 分钟sample_rate大表抽样比例单分区超 5000 万行时取 10%biz_date_offset校验 TN 数据核心链路 T1外部接入 T2超时值和重试次数要跟上游任务的就绪时间绑定上游还在跑就触发校验得到的空值率是假的这类误报占线上告警的一半以上。4. 质量分、告警收敛与问题闭环的设计4.1 DQI 加权计算与阈值基线质量分的作用是给管理层一个可比较的数字但它极容易被误用成考核指标所以计算方式必须写进需求文档并公开。常见做法是规则通过率按维度加权再对维度加权# 数据质量指数规则通过率 - 维度得分 - 总分 RULE_WEIGHTS {P1: 3, P2: 2, P3: 1} # 按严重级别加权 DIM_WEIGHTS { completeness: 0.30, accuracy: 0.30, consistency: 0.20, timeliness: 0.10, uniqueness: 0.10, } def dimension_score(rules): rules: [{dimension, severity, pass_rate}] weight_sum sum(RULE_WEIGHTS[r[severity]] for r in rules) if weight_sum 0: return None # 该维度无规则返回空而不是 0 return sum(RULE_WEIGHTS[r[severity]] * r[pass_rate] for r in rules) / weight_sum def dqi(rule_results): scores {} for dim in DIM_WEIGHTS: subset [r for r in rule_results if r[dimension] dim] s dimension_score(subset) if s is not None: scores[dim] s total_w sum(DIM_WEIGHTS[d] for d in scores) return round(sum(DIM_WEIGHTS[d] * s for d, s in scores.items()) / total_w * 100, 2)逻辑说明没有规则的维度返回None并在总分中剔除而不是记 0 分——否则每上线一个新维度历史分数会凭空下跌业务方会立刻不信任这个指标。阈值基线建议取上线前 30 天历史数据的分位数例如 P1 规则以历史 P5 分位作为告警线而不是拍一个 99%。4.2 告警抑制、聚合与升级策略同一个字段的规则在批量补数期间可能连续失败上百次不做收敛的告警系统会被直接静音等于没有。策略参数需要在文档里写死策略触发条件参数建议抑制同一rule_id重复失败30 分钟内只发一次聚合同一业务域多条规则同时失败按domain合并成一条消息升级连续 3 个业务日期未修复通知上级与值班群静默补数窗口或发布窗口维护静默白名单按任务实例 ID 而非表名静默白名单要按任务实例 ID 匹配按表名静默会把真实问题一起屏蔽掉这是运维阶段最常见的自伤操作。4.3 问题工单落库与根因归因告警必须落到一张可查询的工单表否则闭环无从谈起。最小可用的表结构如下CREATE TABLE dq_issue ( issue_id BIGINT COMMENT 工单ID, rule_id STRING COMMENT 规则ID, biz_date STRING COMMENT 业务日期, severity STRING COMMENT P1/P2/P3, metric_value DOUBLE COMMENT 触发时的指标值, threshold DOUBLE COMMENT 阈值, status STRING COMMENT OPEN/PROCESSING/FIXED/IGNORED, root_cause STRING COMMENT 上游变更/代码缺陷/业务异常/规则误配, owner STRING COMMENT 责任人, created_at TIMESTAMP COMMENT 创建时间, fixed_at TIMESTAMP COMMENT 修复时间 );根因分类建议固定成四五个枚举值别让责任人自由填写。字段root_cause稳定之后可以按周统计「规则误配」占比如果这个比例超过两成说明需求文档里的规则定义质量有问题应该回头改文档而不是改阈值。5. 验收条款变成可回放检查项的具体做法需求文档里最没约束力的句子是「数据准确率不低于 99%」。它没法验证因为它没定义分母。改写方式是补齐三个要素统计口径、样本范围、验证手段。例如改成「以财务系统 T1 对账文件为真值取 2024 年 1 月至 3 月共 90 个自然日的订单金额合计日粒度差异绝对值不超过 0.1%差异天数不超过 2 天」。这样一句话就能直接写成脚本。真值样本建议在平台上线前就固化下来也就是一份「黄金数据集」人工核对过的、包含已知脏数据的少量记录。它的作用不是覆盖全量而是确保规则引擎本身没算错——很多上线事故不是数据脏而是校验 SQL 写错了。回放脚本的骨架如下import json import pandas as pd # 黄金数据集label 为人工判定结果1 表示合格0 表示不合格 golden pd.read_csv(golden_dataset.csv) with open(dq_rules_draft.json, encodingutf-8) as f: rules json.load(f) hit, miss, false_alarm 0, 0, 0 for r in rules: if r[rule_id] not in golden[rule_id].values: continue expected int(golden.loc[golden[rule_id] r[rule_id], label].iloc[0]) actual int(r[exec_result]) # 回放得到的实际判定 if expected 1 and actual 1: hit 1 elif expected 0 and actual 1: miss 1 # 漏报最危险 elif expected 1 and actual 0: false_alarm 1 # 误报影响信任 precision hit / (hit false_alarm) if hit false_alarm else 0 recall hit / (hit miss) if hit miss else 0 print(fprecision{precision:.3f} recall{recall:.3f})逻辑说明漏报意味着真实脏数据被判为合格直接进业务报表所以验收时优先看recall误报会消耗责任人耐心precision低于 0.9 就说明阈值或口径需要重新标定。参数上黄金数据集每条规则至少覆盖 30 条样本且必须包含边界值——空字符串、全角空格、超出区间的负数、时间戳跨天。回放时把校验 SQL 里的${bizdate}替换成历史分区跑完对比判定结果差异条目逐条定位到 SQL 的哪一段。一个容易忽略的验收点是及时性规则本身的可观测性校验任务自己是否在承诺时间内跑完需要单独埋一个监控否则数据质量平台会以「校验任务没跑」的方式失灵而这件事没有任何告警会告诉你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →