1. 程式人生 > >Spark 在反作弊聚類場景的實踐

Spark 在反作弊聚類場景的實踐

作者:周奧特 孫先 陳磊

連結:https://zhuanlan.zhihu.com/p/23385044

來源:知乎

目前知乎站內的 spammer 為了快速取得收效,往往傾向於大批量地產生相似的 spam 內容,或者密集地產生特定的行為。針對這種大量,相似,和相對聚集的特點,我們最近開始嘗試使用聚類的方式去發現和挖掘 spammer。 anti-spam 現階段使用到聚類的場景主要有面向內容和行為的聚類。

聚類的目的在於把相似的內容和行為聚集在一起。常見的聚類方法有 k-means, 層次聚類。另外還有基於密度和圖的聚類分析方案。

聚類分析僅根據在資料中發現的描述物件及其關係的資訊,將資料物件分組。其目標是,組內的物件相互之間是相似的(相關的),而不同組之間的物件是不同的(不相關的)。組內的相似性(同質性)越大,組間差別越大,聚類就越好。

《資料探勘導論》

從上面的定義來看,相似度的度量是聚類的關鍵之一,常見的相似度演算法有 edit distance,conscine similarity, Jaccard 相似度,pearson 相關係數等。本次聚類我們使用了一些文字相似度的演算法,主要包括 jaccard 和 sim-hash.

Jaccard

Jaccard 相似度以兩個集合交集佔並集的比例作為兩個集合的相似度,e.g. 集合 A, B 的相似度 J(A, B) 可以表示成:


sim-hash

然而對於資料量比較大的場景下,jaccard 的表現差強人意, 於是我們將嘗試使用 sim-hash。 sim-hash 由 Charikar 在 2002 年提出,後續在 google 被得以應用,用於近似網頁的檢測。sim-hash 為輸入的文字生成一個 n 位的指紋,與傳統的 MD5, SHA-1 這類雜湊函式不同的是,對於近似的文字,sim-hash 生成的指紋也近似; 越近似的文字,其指紋不同的二進位制位數(記為 k)越少。對於兩個文字,比較其 sim-hash 相似度的步驟如下:

  1. 分詞,對文字進行分詞,為了減少停用詞和其他常見詞(e.g. 的,是,在..)帶來的影響,使用 tf-idf(Term Frequency-Inverse Document Frequency) 為每個詞增加權重,這裡 tf 指的是某個詞在該文字中出現的頻率,idf 則與一個詞的常見程度相關(即包含這個詞的文字數),越常見的詞,其 idf 值越低。tf-idf 權重就是 tf 與 idf 的乘積,在一段文字中,tf-idf 權重相對高的詞就成為了這段文字的關鍵詞。更詳細的解釋請參考 這篇文章。

  2. hash,計算每個詞的 hash 值,通過將文字轉換成數字來提高計算效率。

  3. 加權,將 hash 中的 1 乘以正數的權重,0 乘以負數的權重。

  4. 合併,將加權後的hash值按列相加,得到一個數字組成的序列。

  5. 降維,將步驟 4 得到的數字序列轉換成 0,1 串,大於 0 的數字轉換成 1,小於 0 的數字轉換成 0。

  6. 相似度比較,比較生成的 sim-hash 值的 hamming distance。hamming distance 即兩個 hash 值的漢明距離,相信大家都很熟悉了,更多的介紹可以參考連結(https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Hamming_distance)裡面的解釋。


simhash 生成過程示意圖

我們測試了兩種方法執行 100w 次的時間耗費,測試程式碼如下:


結果顯示:

jaccard 耗費時間: 21772  ms

sim-hash 耗費時間: 9981  ms

在文字較短的情況下,sim-hash 可以提升至少一半的檢測效率;檢測長文字的差距更為明顯。所以採用 sim-hash 可以有效的縮短相似度檢測的時間。

經過試驗,對於 64 位的 sim-hash 指紋,k=3 是判斷兩個文字是否相似比較合理的閾值,因為在 k=3 的時候, 召回率和準確率都能處在一個比較滿意的水平(75%左右)。為了提高召回和準確率,在實踐當中,我們使用 k=4 來保證召回,並在 sim-hash 的基礎上,對每一組再次進行一次 jaccard 相似度計算,提高其準確率。


不同閾值下的準確率和召回率曲線

目前站內每天 web 端產生近千萬的寫行為。拿私信舉例, 如果用單程序去比較每天 10w 條私信的相似度,每一條私信需要和其他 99999 條私信進行兩兩比較,根據實驗資料, 使用 sim-hash 一次遍歷需要近 1s, 將 10w 的資料全都檢測一遍則需要接近 27個小時。在這種場景下,如何有效,快速地對全量的資料進行聚類呢?

spark 是目前我們採用的方案。spark,是一個高效能分散式計算框架。spark 的計算是基於記憶體的,spark 支援將計算的中間結果和資料集儲存在記憶體,大大減少了磁碟 io,網路通訊的時間。與 map-reduce 模型相比,提供了更為豐富的運算元 (e.g. filter,flatMap等)。這些運算元被分成兩類,轉換(transformation)和執行 (action),所有的 transformation 操作具有延遲性,當一個 transformation 操作被呼叫時,計算不會立即觸發,只有 action 被呼叫時,計算才會被觸發。這一點也良好的保證了 spark 的容錯性,當一個 task 在某個節點掛掉時,在一個新的節點重新進行計算的成本不會很高。

內容聚類

  • 資料準備:

在使用 spark 之前,資料準備是由 HiveQL 結合 python 指令碼完成的,在資料量大的情況下,效率存在問題。而 spark 可以與 hive 進行無縫整合,因此資料處理的效率提升了不少。在 hive 上,HiveQL 實際上被轉換成一系列的 map-reduce 過程,在 hadoop 平臺上執行計算;而在 spark 上執行 hive 語句,HiveQL 會被轉化成一系列的 transformation 和 action。spark 會直接讀取 hive 的元資料,將元資料轉化成 spark RDD, 並在此基礎上進行計算。得益於 spark 豐富的運算元和基於記憶體的特點,加上原來由 python 指令碼完成的資料清洗工作也可以由 spark 的運算元來代替完成,spark sql 的執行效率要比原來採用 hiveQL 的執行效率高至少 10 倍有餘。

  • 聚類實現:

內容聚類的實現採用了圖分割的方式,即構建一個相似度圖 G=(V, E),以每個文件為頂點,文件之間的相似度作為相連邊的權重。以 sim-hash 為例,兩點之間相連邊的權重就是兩個 hash 值的 hamming distance。如下圖所示,假如我們以 k=3 作為閾值,取所有權重大於閾值的邊作為新的子圖(即圖中黑色的邊),並計運算元圖中的連通子圖即可得到(1,2,3)和(4,5,6,7)兩個cluster。

在實際使用中,我們本來使用 Graphx(spark 對於圖和圖的平行計算的 api,詳情見GraphX | Apache Spark) 提供的 connectedComponents 介面,但是後續發現在資料量比較大的情況下,反覆的迭代帶來了比較大的效能問題。於是利用文字相似度的傳播性(a與b相似,且 b與c相似,則a與c相似),我們使用 spark SQL 將問題轉化為 “尋找最小相似節點” 的問題。舉個例子,在下圖中,與1相似的最小節點是1,與2相似最小的節點為1,與3相似最小的節點也為1,這三個點最小相似節點均為1,所以他們屬於同一個 cluster。而 4,5,6,7 這四個節點,因為最小相似節點為 4,所以他們屬於另外一個獨立的 cluster。


cluster 分割示意圖

由於 Jaccard 相似度計算成本比較高,實踐中使用 sim-hash 來提升相似度計算的效率。使用 64 位雜湊值,將 k=4 作為閾值,將輸入的資料進行一個預先分組。由於這種條件下可以保證比較高的召回,而準確率相對來說比較低, 需要再針對每個分組使用 Jaccard 進行細分,進而提高準確度。這種方式減少了需要計算 Jaccard 相似度的數量,也彌補了 sim-hash 相似度在召回高時準確率不足的問題。另外,為了減少不必要的計算資源浪費,相連兩個節點的相似度只單向計算了一次。但是相似度的比較仍然是一個近似笛卡爾積的計算,為了提高這部分的計算效率,我們採用 spark 的廣播機制,在所有節點的記憶體快取一份變數,從而減少在計算過程中的通訊開銷。

目前針對私信,聚類可以在 1-3 min 之內完成,使用 spark 充分提高了資料處理的效率。

行為聚類

行為聚類的主要思路是將使用者的行為路徑以文字的方式表達出來,將行為聚類轉換成內容聚類,通過文字相似度聚類,將相似的行為聚集在一起。

  • 資料準備:

行為路徑的表達:以使用者的一個 post 行為為單位,取前後至少兩個請求,並計算每個行為之間的時間間隔,將使用者的行為序列表達成由“請求路徑|請求方法|與上一次請求的時間間隔|”構成的文字組合。

  • 聚類實現:

相對於內容聚類,行為聚類面對著更大的資料量, 在資料清洗過後大概每天有 30w+ 的關鍵業務寫行為。考慮到比較不同類別的寫行為之間的相似度沒有太大意義,因此針對每個業務單獨進行聚類,這樣一來將 30w * 30w 的計算規模減少到了 1w * 1w + 3w * 3w + .....。由於聚類的實現與內容聚類的邏輯大體一致,這裡就不再多做介紹。

總結:針對批量的 spammer 內容和行為,聚類是一種替代人工策略行之有效的方法。目前行為和內容聚類均以離線處理的方式上線,聚類是 antispam 使用 spark 的初步嘗試,後續會繼續優化提高其處理效率,也會嘗試使用 spark streaming 來提高聚類的實時性。

版權申明:內容來源網路,版權歸原創者所有。除非無法確認,我們都會標明作者及出處,如有侵權煩請告知,我們會立即刪除並表示歉意。謝謝。

-END-