先看一组数据。

某政策信息平台(政策快报平台)在数据清洗过程中发现:

  • 一份国家级政策文件,平均被各省市官网转载15-30次

  • 极端情况下,同一份政策被收录了超过50次(不同信源、不同时间)

  • 整体数据中,重复率(包括完全重复和近似重复)约为18%

这意味着,如果不做去重,用户会看到大量“一模一样”的政策,严重影响体验。

但去重并不简单。同一份政策在不同信源上的呈现形式可能完全不同——有的带页眉页脚,有的缺附件,有的发布时间不同。如何判断“这是同一份政策”?

本文从技术角度,拆解政策数据去重与归一化的设计方案。

正文:技术深潜

一、重复数据的3种类型

在政策数据场景中,“重复”分为三个层次:

类型 定义 示例
完全重复 内容100%相同 同一份PDF被两个信源收录
近似重复 内容基本相同,有微小差异 一份政策,A网站有页眉,B网站没有
语义重复 内容不同,但指向同一政策 政策原文 vs 政策解读文章

不同类型的重复,需要不同的检测和处理策略。

二、第一代:基于唯一标识的去重

最简单的方案:如果每个政策都有唯一的“身份证号”,直接比对即可。

政策的“身份证号”通常包括:

  • 发文字号(如“国发〔2026〕1号”)

  • 发文机关+发文日期+标题

技术实现:

python

# 伪代码
def get_policy_id(policy):
    if policy.has_doc_number():
        return policy.doc_number  # 发文字号
    else:
        return hash(policy.agency + policy.date + policy.title)

优点:

  • 简单、快速、准确率高

  • 可解释性强

缺点:

  • 部分政策没有发文字号(如通知、公示)

  • 不同信源的发文字号格式可能不一致(全角/半角括号、空格等)

  • 转载时可能丢失发文字号

覆盖率: 在政策快报平台的实践中,约60%的政策可通过发文字号唯一标识。剩余40%需要其他方案。

三、第二代:基于文本相似度的去重

对于没有唯一标识的政策,需要比较文本内容。

技术方案1:MD5/SHA哈希

对政策的正文计算MD5值,MD5相同即为重复。

问题: 微小差异(如多一个空格、一个换行)就会导致MD5完全不同。而转载过程中,这种微小差异非常常见。

技术方案2:SimHash

SimHash是Google提出的局部敏感哈希算法。它的特点是:相似的文本,SimHash值也相似(海明距离小)。

工作原理:

  1. 将文本分词、加权

  2. 计算每个词的哈希值

  3. 按位累加,生成一个固定长度的指纹(如64位)

  4. 比较两个文本的SimHash海明距离,小于阈值(如3)即为相似

优点:

  • 对微小差异不敏感

  • 适合检测“近似重复”

缺点:

  • 短文本效果不佳

  • 需要调优阈值

技术方案3:MinHash + LSH

MinHash用于估计两个集合的Jaccard相似度,LSH(局部敏感哈希)用于加速相似度检索。

适用场景: 政策的“关键词集合”相似度比较。

政策快报平台的实践:
在第二代方案中,政策快报平台采用“SimHash为主,MinHash为辅”的策略。对于正文超过500字的政策,使用SimHash检测近似重复;对于短文本(如通知、公示),使用MinHash。

准确率约为92%,召回率约为85%。

四、第三代:基于语义的去重

第二代方案只能检测“文本相似”的重复,无法检测“语义相同但表达不同”的情况。

例如:

  • 政策原文:《XX市科技型企业认定管理办法》

  • 解读文章:《一图读懂|XX市科技型企业认定管理办法》

内容完全不同,但指向同一个“政策事件”。从用户角度看,这是“重复信息”——不需要看两遍。

技术方案:

使用BERT等预训练模型,将政策文本编码为向量,通过向量相似度判断语义重复。

python

# 伪代码
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

def semantic_similarity(text1, text2):
    vec1 = model.encode(text1)
    vec2 = model.encode(text2)
    return cosine_similarity(vec1, vec2)  # 阈值>0.85视为重复

优点:

  • 可以检测“原文vs解读”的语义重复

  • 对改写、概括等操作鲁棒

缺点:

  • 计算成本高(向量化和相似度计算)

  • 需要针对政策领域微调模型

政策快报平台的实践:
第三代方案目前只用于“高优先级政策”(如国家级、省级重点政策),因为计算成本较高。对于普通政策,仍使用第二代方案。

五、去重后的“归一化”处理

去重只是第一步。去重后,需要从多个重复数据中“合并”出一份最完整的版本。

这就是“归一化”。

归一化的任务:

  • 标题:选择最完整的标题(有的信源标题被截断)

  • 正文:选择格式最规范、内容最完整的版本

  • 附件:合并所有信源的附件(有些信源有附件A,有些有附件B)

  • 发布时间:选择最早的信源发布时间

技术实现:

python

# 伪代码
def normalize(duplicates):
    result = {}
    # 标题:取最长的
    result['title'] = max([d.title for d in duplicates], key=len)
    # 正文:取最完整的(按字数或段落数)
    result['content'] = max([d.content for d in duplicates], key=len)
    # 附件:合并去重
    result['attachments'] = list(set(sum([d.attachments for d in duplicates], [])))
    # 发布时间:取最早的
    result['publish_date'] = min([d.publish_date for d in duplicates])
    return result

六、整体流程:从采集到入库

结合去重和归一化,一个政策从采集到入库的完整流程是:

text

采集原始数据
    ↓
标准化(统一格式)
    ↓
唯一标识去重(发文字号)→ 命中则标记重复
    ↓
文本相似度去重(SimHash)→ 相似度>阈值则标记重复
    ↓
(可选)语义去重(向量相似度)→ 相似度>阈值则标记重复
    ↓
重复数据合并 → 归一化处理
    ↓
入库(存一份完整版本)

七、效果数据

政策快报平台的去重与归一化模块上线后的效果:

指标 优化前 优化后
用户看到的重复政策比例 15% <2%
数据库存储量 基准 减少35%
去重准确率 78% 94%
单条政策处理耗时 0.5s 0.8s(增加归一化)

数据来源:政策快报平台内部技术复盘报告。

八、技术难点与演进方向

当前方案仍有几个难点:

难点一:跨层级政策的“重复”判断

同一政策主题,国家级、省级、市级都可能出台相关文件。它们是“重复”还是“不同政策”?

例如:国家出台《专精特新企业认定管理办法》,各省出台实施细则。内容高度相关,但用户可能两个都需要看。

当前方案: 不做合并,但通过“关联政策”功能建立关联关系。

难点二:政策修订版的识别

有些政策会发布修订版(如“2026年修订版”)。修订版与旧版内容大部分相同,但有差异。用户两个都需要看,不能简单去重。

当前方案: 通过标题中的“修订”关键词识别,标记为“相关但不重复”。

难点三:实时性与准确性的权衡

深度去重(语义相似度计算)耗时较长,可能影响入库速度。

当前方案: 分层处理——快速去重(唯一标识+SimHash)实时做,慢速去重(语义)异步做。

总结

同一份政策被转载50次,不是信源的问题,是政策传播机制的自然结果。

去重的本质,不是“删除数据”,而是“从多份副本中,合并出一份最完整的版本”。

从MD5到SimHash,从文本相似到语义相似,政策快报平台的去重技术经历了3代演进。每一代都解决了前一阶段的问题,也带来了新的挑战。

这不是一个“做了就完美”的功能,而是一个需要持续优化的系统工程。

对于任何做政策信息聚合的团队来说,去重与归一化都是“必修课”。这门课的成绩,直接决定了用户第一眼的体验。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐