采进来的数据怎么保证「能用」?采集数据校验与质量门禁

采集数据最大的风险不是「没采到」,而是「采到了但数据是坏的」——字段空了、类型错了、值域异常,下游分析直接崩。这篇记录我给采集数据加「校验与质量门禁」的实践:校验什么、什么时候校验、不合格怎么办,让坏数据在入口就被拦住。

为什么需要数据校验

搜索数据接口的返回是「活的」——可选字段、结构变化、谷歌布局调整,都会让采集数据出现「看起来成功、实际上有问题」的情况。没有校验,坏数据会一路流到下游:

  • 字段缺失 → 下游 KeyError
  • 类型错乱 → 分析结果荒谬
  • 值域异常(排名 0、负延迟)→ 逻辑 bug 的温床

校验的目标:在数据进入存储/下游之前,把不合格的拦下来。

校验什么:三个层次

以 SerpBase(serpbase.dev)的 /google/search 返回为例,校验分三层:

1. 信封层(响应级)

def validate_envelope(data):
    checks = [
        data.get("status") == 0,                 # 成功
        isinstance(data.get("request_id"), str), # 有追踪 id
        isinstance(data.get("elapsed_ms"), int), # 延迟是数字
        isinstance(data.get("credits_charged"), (int, float)),
    ]
    return all(checks), "envelope"

2. 记录层(结果级)

def validate_result(item):
    checks = [
        isinstance(item.get("rank"), int) and 1 <= item["rank"] <= 100,  # 排名值域
        bool(item.get("title")),               # 标题非空
        str(item.get("link", "")).startswith("http"),  # 链接合法
    ]
    return all(checks), "result"

3. 关系层(跨记录)

def validate_relations(items):
    ranks = [i["rank"] for i in items]
    # 排名应基本连续(允许有跳号但不应全乱)
    return len(set(ranks)) > len(items) * 0.5, "relations"

三层的重点不同:信封层管「请求成功没」,记录层管「每条数据对不对」,关系层管「整批数据合不合理」。

什么时候校验:三个入口

校验要有「门禁」意识,在三个位置把关:

1. 采集时(清洗后立刻校验)

def fetch_and_validate(keyword):
    data = fetch(keyword)          # 采集
    recs = clean(data)             # 清洗
    bad = [r for r in recs if not validate_result(r)]
    if bad:
        mark_recollect(keyword, bad)   # 标记重采,而不是硬写
    return recs

2. 入库前(存储层校验):数据库层加 CHECK 约束兜底:

CREATE TABLE snapshots (
  keyword text,
  rank integer CHECK (rank >= 1 AND rank <= 100),
  title text NOT NULL,
  url text NOT NULL,
  ...
);

3. 下游使用前(消费方校验):关键数据消费前再验一次,防止「中间被改坏」。

不合格怎么办:三种处置

校验失败的处理,按严重程度分级:

  1. 轻度(可修复):字段缺失但有默认值 → 补默认值后放行,记日志
  2. 中度(标记):单条数据异常 → 标记 quality=bad,不入主流,但保留原始
  3. 重度(拦截):信封层失败或整批异常 → 整批拦下,触发重采/告警,绝不入库
# 伪代码:分级处置
def gate(data):
    ok, level = validate_envelope(data)
    if not ok:
        reject_batch(data)      # 重度:整批拦截 + 告警
        return
    for rec in clean(data):
        ok, _ = validate_result(rec)
        if not ok:
            mark_bad(rec)       # 中度:标记不入主流
        else:
            store(rec)          # 放行

校验规则从哪来

校验规则别拍脑袋,三个来源:

  1. 接口文档:必选/可选字段、值域(如 page 从 1 起、zoom 1–21),文档写什么验什么
  2. 历史数据:看历史数据的真实分布,异常值(排名 0、负延迟)就是校验规则的来源
  3. 业务约束:你的业务对数据的假设(比如「排名必须 1–100」)

注意:校验规则要和接口文档一致——SerpBase 文档明确标注哪些字段 optional,校验时别把「可选字段缺失」当成「数据坏了」(这是最常见的误判)。

和监控/重采的配合

校验是「入口门禁」,配合之前的体系:

  • 质量监控(InfoQ 质量篇):校验结果计入质量指标(合格率、拒绝率)
  • 重采机制(定时任务/补偿):重度拦截的批次进重采队列
  • 告警:拒绝率突增 → 大概率「接口结构变了」或「校验规则过时」,告警调查

工程清单沉淀

  1. 校验三层:信封(请求级)、记录(数据级)、关系(批次级)
  2. 门禁三处:清洗后、入库前、消费前
  3. 处置分级:修复 / 标记 / 拦截重采
  4. 规则来源:接口文档 + 历史数据 + 业务约束
  5. 别把「可选字段缺失」误判为数据坏

数据校验是采集系统「最后一道门」——坏数据一旦入库,下游所有分析都不可信。把校验做成入口门禁,比在下游一遍遍纠错便宜得多。

接口字段的必选/可选定义和值域在 SerpBase 官方文档,写校验规则时先对照。你的采集数据有校验吗?评论区聊聊各自的门禁设计。

posted @ 2026-09-08 08:09  蜘蛛人  阅读(24)  评论(0)    收藏  举报