在企业的工商库、招投标平台和舆情系统中,组织名称常常因为简称、错别字或括号备注产生大量变体。基于N-gram的组织名称相似度匹配,通过将名称转为字符片段集合并统计交集,能够在保证准确率的同时显著降低计算开销。

什么是N-gram切分
N-gram是将字符串按长度为N的滑动窗口切分成连续子串的方法。以组织名“星辰科技有限公司”为例,当N=2时生成如“星辰”“辰科”“科技”“技有”“有限”“限公”“公司”等二元组。这些片段构成了名称的特征指纹。
常见N值选择
- Bigram(N=2):中文组织名最常用,兼顾语义与性能
- Trigram(N=3):对长名称区分度更高,但集合更大
- Uni-gram(N=1):仅单字,过于稀疏,一般不单独使用
相似度打分方式
得到两个名称的N-gram集合A和B后,可用Jaccard或Dice系数衡量相似度。Dice公式如下:
Dice = 2 × |A∩B| / (|A| + |B|)
该值介于0到1之间,越接近1表示名称越可能指向同一组织。
代码示例:Python实现Bigram相似度
def get_bigrams(name):
# 去除空格并生成二元组
name = name.replace(' ', '')
return set(name[i:i+2] for i in range(len(name) - 1))
def dice_similarity(a, b):
# 计算两个组织名的bigram Dice相似度
ga, gb = get_bigrams(a), get_bigrams(b)
if not ga or not gb:
return 0.0
inter = len(ga & gb)
return 2 * inter / (len(ga) + len(gb))
# 测试示例
name1 = '星辰科技有限公司'
name2 = '星辰科技有限责任公司'
print(dice_similarity(name1, name2))
如何提升匹配效率
面对百万级组织名称,两两比对不可行。可构建以N-gram为键的倒排索引,每个键指向包含该片段的机构ID列表。查询时只对候选集求交,大幅缩减计算量。
| 策略 | 适用场景 | 优势 |
|---|---|---|
| 倒排索引 | 大规模名称库 | 避免全量扫描 |
| 分块过滤 | 区域或行业已知 | 缩小候选范围 |
| 阈值剪枝 | 实时接口 | 低延迟返回 |
倒排检索示例
from collections import defaultdict
def build_index(names):
# 构建bigram倒排索引
index = defaultdict(list)
for idx, nm in enumerate(names):
for g in get_bigrams(nm):
index[g].append(idx)
return index
def candidate_ids(index, query):
# 返回包含查询名任一bigram的候选ID
cands = set()
for g in get_bigrams(query):
cands.update(index.get(g, []))
return cands
names = ['星辰科技有限公司', '星河技术公司', '辰科有限']
index = build_index(names)
print(candidate_ids(index, '星辰科技有限责任公司'))
实践中的注意事项
在使用<code>N-gram</code>策略时,建议先统一全角半角与括号格式;对“公司”“集团”等高频词可做停用处理以防噪声。函数调用如get_bigrams()应作为普通方法使用,而非标签。结合业务阈值,通常Dice大于0.6即可视为疑似重复组织。