利用d3.js對大資料資料進行視覺化分析

wyzsk發表於2020-08-19
作者: insight-labs · 2013/12/19 18:18

作者: [email protected] [email protected]

0x00 背景


對於前段時間流出的QQ群資料大家想必已經有所瞭解了,處理後大小將近100G,多達15億條關係資料(QQ號,群內暱稱,群號,群內許可權,群內性別和年齡)和將近9000萬條群資訊(群號,群名,建立時間,群介紹),這些資料都是扁平化的2維表格結構,直接查詢不能直接體現出使用者和群之間的直接或者間接關係。透過資料視覺化,可以把扁平結構的資料作為點和線連線起來,從而更加直觀的顯示出來從而進行分析。

d3.js是一個近年來推出的基於javascript的資料展示庫,全稱為Data Driven Document, 在瀏覽器資料展示領域的地位類似於通用js框架裡的jQuery。d3.js的官網是d3js.org,大家可以在上面看到很多例子和應用。d3.js也是圖形資料庫neo4j所內建的資料展示工具。

說到圖形資料庫,其實正確的翻譯應該是圖資料庫,圖即所謂的Graph,來自於數學裡的圖論,比如四色定理和推銷員過橋的問題(著名的NP問題之一)。圖資料庫著重於資料之間的關聯和屬性,對於關係錯綜複雜的關係分析效率很高。例如,我想知道誰是我朋友的朋友,並且他們有哪些朋友也認識我。對於這種問題,普通關係型資料庫的計算複雜度是O(N^c)左右或者更高,N為選擇範圍的資料集合大小,你好友數量加上好友的好友的數量等,c為關係層數。圖資料庫的計算複雜度在O(N^2)左右或者更低,但是基本不會超過O(N^2)。圖資料庫對於複雜關係資料查詢起來效率高的主要原因是在資料輸入的時候就已經對關係進行了處理和索引,這樣做在查詢的時候具有很高的效率,但是在資料匯入的時候會很慢。QQ群的15億個關係在向圖資料庫neo4j裡匯入的時候花了3天都沒弄完,也沒有進度提示,所以後來我直接放棄了。

0x01 資料處理


在QQ群和群成員關係裡面,對於層數我是這麼定義的:

第1層:目標QQ加入的所有群  
第2層:目標QQ加入的所有群的所有成員  
第3層:目標QQ加入的所有群的所有成員加入的所有群  
.  
.  
.  

大家可以看出這樣的查詢是可以遞迴的,假設每個QQ號所加入的群數量和每個群的成員數量為N,那麼查詢3層資料時總計算量為N*N*N=n^3,所以當查詢層數為c層的時候,計算複雜度是N^c。

前面說過,圖資料庫的計算複雜度一般在N^2以下,所以當使用普通的關係型資料庫的時候,如果查詢的層數不多,效率和圖資料庫比起來差不多,加上關聯式資料庫自帶的便於管理和匯入匯出的屬性,所以我還是選擇了mysql資料庫。

對於QQ和QQ群之間的關係,每個QQ號都能加入群,一個群裡也有很多QQ,基本都在幾十到幾百人,所以兩個QQ號在同一個群裡不一定代表他們的關係很緊密,換句話說QQ和QQ群之間的關係相對於QQ好友而言相對較弱。但是這並不代表我們從中不能分析出有用的資料,俗話說的好,大資料就像一座金礦,只有用力挖才能挖到金子。

d3.js支援多種資料格式,比如JSON,XML,CSV,HTML等,因為PHP的陣列可以很簡單的轉換為JSON格式,所以我選擇用PHP寫API來獲取JSON資料。QQ和QQ群是一種典型的圖資料的應用,QQ和QQ群作為節點(node),QQ加入了哪些群作為關係(link),d3.js內建了一個功能很強大的內建佈局,叫做Force-Directed Graph(受力導向圖),後面簡稱為force。force佈局模擬了一些基本的物理粒子原理,比如引力和斥力(確切的說是模擬了電磁力和引力,在離的遠的時候會互相吸引,在離的近的時候斥力急劇增加),並且可以調節力的大小和受力距離等等,可以說是自由度相當高。關於d3.js的force佈局,在官網有詳細的API和不少例子,這裡我就不貼程式碼了。

在force佈局裡面,資料來源的JSON可以有很多種不同的格式和屬性,但是基本格式如下:

{"nodes":[{"num":10001,type:"qq"},{"num":12345678,type:"qun"}],"links":[{"source":"10001","target":"12345678","auth":1,"nick":"pony"}]} 

其中nodes陣列對應的是節點列表,links對應的是關係列表。

每個節點可以有很多自定義屬性,在d3.js可以針對每個節點存取節點的屬性,比如我定義num是QQ號或者群號,type代表節點是QQ還是群,另外我在js裡設定在type==‘qun’的時候顯示群的圖示,是qq的時候顯示qq的圖示。關係裡面預設的屬性有source和target,分別對應一個關係的兩頭,預設情況下關係裡面的source和target對應的數字是節點在節點陣列裡面的位置index。但是我自定義成了qq號和群號。另外你也可以定義其他屬性,比如auth代表這個QQ號在群裡的許可權,nick是群暱稱。

對於QQ群這樣的關係來說,基本上在第4層和以上的QQ和群的關係就比較弱了,所以為了提高查詢速度和減少節點數量,我只查詢2層關係(少麼?不少,要想想有些群有超過500人……)。

首先,d3.js需要在瀏覽器裡面執行,我的首選是Google Chrome,V8引擎的效率果然不錯,在節點和關係不多的時候基本感覺不到延遲,後來在FF和IE11裡面測試了一次,FF比Chrome卡一半左右,IE的話我只能呵呵了……

先拿小馬哥做個測試,QQ號是霸氣的10001。當d3.js匯入完資料JSON的時候,各種節點會在螢幕上亂飛幾秒鐘,直到他們的力達到一個穩定的平衡點。結果如下:

說明:

企鵝圖示的節點代表QQ,群圖示的節點是群(廢話麼)。  
每條線代表一個關係,一個QQ可以加入N個群,一個群也可以有N個QQ加入。  
線的顏色分別代表:  
土豪金:群主  
狗腿綠:群管理員  
屌絲藍:群成員 

大家也可以看到,群主和管理員的關係線也比普通的群成員長一些,這是為了突出群內的重要成員的關係。

圖示旁邊自動標註了QQ號和群號,如果有的話還有群名。沒有在QQ號旁邊標註暱稱是因為很多人加入不同的群使用的是不同暱稱,所以把暱稱放到了其他的地方顯示。

在下圖中大家可以隱約的看到,所有的關係都是以QQ 10001為起點的。

2013121917474689613.png

在圖上節點是可以拖拽的,拖拽後會固定在你釋放的地方。我們把幾個群稍微拖的分開一點,關係就一目瞭然了

2013121917491099821.png

這個時候我們可以看到在目標的QQ群裡也有很多共同QQ號,比如有些QQ號同時加入了2,3個群。群名顯示的都是各種產品開發討論群,這些同時加入2,3個產品群的人估計不是產品經理就是主管吧……

2013121917494053558.png

滑鼠懸停到群圖示上可以看到群的詳細資訊(如果有的話)

圖3.1
2013121917500358308.png

因為很多人在不同群裡的暱稱不一樣,所以群內暱稱等資訊就只能放到link上面了,因為線比較細,所以滑鼠比較難對準,這個功能還待修改。

這個傢伙和小馬哥一起同時在3個群裡,好基友?

圖4
2013121917502854910.png

小馬哥的QQ群資訊展示完了,下面我們來看看更加實際的應用,比如把某圈子裡的人找出來。我們先從某土豪大黑闊大牛的QQ號入手:

初始資料好多……此大黑闊加入的群夠雜的,不過就是因為雜所以才能更深入的瞭解一個人的所有喜好。看看群名神馬的,我好像看到了dota,XX國際俱樂部,web技術交流,XXsec等群……充分說明了此人……是個屌絲技術宅大黑闊,XX國際俱樂部又似乎帶著那麼種高大上的感覺……

圖中錯綜複雜的各種關係組成了一朵朵盛開的菊花,向我們訴說著他的歷史……

2013121917525168384.png

為了理清他那不堪回首的過去和關係網,我特地把瀏覽器視窗拖到第二個螢幕上,然後把群挨個分開。為了保護當事人的隱私,這張圖我打碼了。

這張圖比較寬,建議大家下載下來放大看

2013121917540927073.png

0x02 總結


假如把層數擴充套件到4層,不知能否篩選出中國所有黑闊的QQ號呢?至少我已經在這張圖裡看到了很多熟悉的名字和號碼。

騰訊總是說漏洞早已修復,不存在問題了,廣大網民放心,但實際上資訊洩露這種事情,豈是你漏洞修復好了就結束了的事情?

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章