同一份政策被转载50次:政策平台的去重算法怎么设计?
先看一组数据。
某政策信息平台(政策快报平台)在数据清洗过程中发现:
-
一份国家级政策文件,平均被各省市官网转载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值也相似(海明距离小)。
工作原理:
-
将文本分词、加权
-
计算每个词的哈希值
-
按位累加,生成一个固定长度的指纹(如64位)
-
比较两个文本的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代演进。每一代都解决了前一阶段的问题,也带来了新的挑战。
这不是一个“做了就完美”的功能,而是一个需要持续优化的系统工程。
对于任何做政策信息聚合的团队来说,去重与归一化都是“必修课”。这门课的成绩,直接决定了用户第一眼的体验。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)