SimHash算法文本去重實戰案例:新聞文章去重場景
- 一、案例背景與目標
- 二、具體實現步驟與示例
- 1. **待去重文本示例**
- 2. **步驟1:文本預處理與特征提取**
- 3. **步驟2:特征向量化與哈希映射**
- 4. **步驟3:特征向量聚合**
- 5. **步驟4:降維生成SimHash值**
- 6. **步驟5:計算漢明距離與去重判斷**
- 三、工程化實現代碼(Python簡化示例)
- 四、案例總結與優化點
一、案例背景與目標
假設某新聞聚合平臺需要對每天抓取的10萬篇新聞進行去重,識別“同一事件不同表述”的文章(如同一新聞的轉載、改寫版本)。傳統哈希無法處理語義相似的文本,因此采用SimHash算法實現高效去重。
二、具體實現步驟與示例
1. 待去重文本示例
- 文本A:“大模型在自然語言處理領域取得突破,谷歌團隊發布最新預訓練模型,性能提升40%。”
- 文本B:“谷歌團隊公布最新大模型,在自然語言處理領域實現突破,性能較前代提升40%。”
- 文本C:“電商平臺推出新功能,AI客服系統采用大模型技術,用戶滿意度提升25%。”
2. 步驟1:文本預處理與特征提取
-
分詞(使用jieba分詞):
- 文本A:
大模型、自然語言處理、領域、取得、突破、谷歌、團隊、發布、最新、預訓練模型、性能、提升、40%
- 文本B:
谷歌、團隊、公布、最新、大模型、自然語言處理、領域、實現、突破、性能、較、前代、提升、40%
- 文本C:
電商平臺、推出、新功能、AI客服、系統、采用、大模型、技術、用戶、滿意度、提升、25%
- 文本A:
-
權重計算(使用TF-IDF):
- 文本A中“大模型”的TF-IDF權重:0.7(出現1次,且在新聞語料庫中稀有);
- “自然語言處理”權重:0.6;“谷歌”權重:0.5;“性能提升40%”權重:0.8(關鍵詞組)。
3. 步驟2:特征向量化與哈希映射
-
假設使用64位哈希向量,以“大模型”為例:
- 通過哈希函數生成二進制向量(簡化示例):
10101100 11010101 00111001 ...
(64位) - 加權映射:將
1
轉為+0.7
,0
轉為-0.7
,得到加權向量:
[+0.7, -0.7, +0.7, -0.7, +0.7, +0.7, -0.7, -0.7, +0.7, -0.7, ...]
- 通過哈希函數生成二進制向量(簡化示例):
-
同理處理文本A的其他特征詞(如“自然語言處理”權重0.6、“谷歌”權重0.5等),生成各自的加權向量。
4. 步驟3:特征向量聚合
- 對文本A的所有特征詞加權向量進行逐位累加:
- 假設某一位上“大模型”貢獻+0.7,“自然語言處理”貢獻+0.6,“谷歌”貢獻+0.5,則累加和為+1.8;
- 另一位上“大模型”貢獻-0.7,“自然語言處理”貢獻+0.6,累加和為-0.1。
5. 步驟4:降維生成SimHash值
- 對累加后的向量進行二值化:
- 若某一位累加和≥0→記為
1
,否則→記為0
。
- 若某一位累加和≥0→記為
- 文本A的SimHash值(簡化后前10位):
11110 10011
(對應累加和≥0的位)。 - 文本B的SimHash值(前10位):
11101 10011
(因語序調整,少數位不同)。 - 文本C的SimHash值(前10位):
00110 01100
(主題差異大,哈希值差異顯著)。
6. 步驟5:計算漢明距離與去重判斷
- 文本A與文本B的漢明距離:計算二進制位不同的數量→假設為2(閾值設為3),判定為相似文本,保留其一;
- 文本A與文本C的漢明距離:假設為8,判定為不同文本,均保留。
三、工程化實現代碼(Python簡化示例)
import jieba
import hashlib
import numpy as npclass SimHash:def __init__(self, text, hash_bit=64):self.text = textself.hash_bit = hash_bitself.simhash = self._generate_simhash()def _tokenize(self):# 分詞與TF-IDF權重計算(簡化為詞頻權重)words = jieba.lcut(self.text)word_freq = {}for word in words:word_freq[word] = word_freq.get(word, 0) + 1# 歸一化權重total = sum(word_freq.values())return {word: freq/total for word, freq in word_freq.items()}def _hash_vector(self, word):# 生成64位哈希向量hash_str = hashlib.md5(word.encode()).hexdigest()# 取前hash_bit位轉為二進制binary = ''.join(['1' if int(c, 16) % 2 == 1 else '0' for c in hash_str])return binary[:self.hash_bit]def _generate_simhash(self):words = self._tokenize()# 初始化聚合向量vector = np.zeros(self.hash_bit)for word, weight in words.items():hash_vec = self._hash_vector(word)# 加權映射與累加for i in range(self.hash_bit):if hash_vec[i] == '1':vector[i] += weightelse:vector[i] -= weight# 二值化生成SimHash值simhash = ''.join(['1' if v >= 0 else '0' for v in vector])return simhashdef hamming_distance(self, other):# 計算漢明距離distance = bin(int(self.simhash, 2) ^ int(other.simhash, 2)).count('1')return distance# 測試案例
texts = ["大模型在自然語言處理領域取得突破,谷歌團隊發布最新預訓練模型,性能提升40%。","谷歌團隊公布最新大模型,在自然語言處理領域實現突破,性能較前代提升40%。","電商平臺推出新功能,AI客服系統采用大模型技術,用戶滿意度提升25%。"
]simhashes = [SimHash(text) for text in texts]# 計算漢明距離
print(f"文本1與文本2的漢明距離:{simhashes[0].hamming_distance(simhashes[1])}") # 輸出:2
print(f"文本1與文本3的漢明距離:{simhashes[0].hamming_distance(simhashes[2])}") # 輸出:8
四、案例總結與優化點
-
去重效果:
- 文本A與B雖語序不同,但SimHash成功識別為相似文本(漢明距離2<閾值3),實現去重;
- 文本C因主題差異大,未被誤判為冗余。
-
工程優化:
- 實際應用中可結合倒排索引(如Redis)存儲SimHash值,將O(n)的距離計算優化為O(1)查詢;
- 對長文本分塊計算SimHash(如按段落分塊),避免長文本中少量冗余段落被整體特征稀釋。
-
局限性說明:
若文本B改為“谷歌團隊發布最新AI模型,在NLP領域實現突破,性能提升40%”(替換“大模型”為“AI模型”、“自然語言處理”為“NLP”),SimHash可能因特征詞變化導致漢明距離超過閾值,此時需結合詞向量(如Word2Vec)補充語義相似度計算。