講解ID-Mapping算法之前,先說幾個重要概念:
MAC(Media Access Control),MAC位址,爲網卡的標識,唯一標識網絡設備。
IMEI(International Mobile Equipment Identity),通常說的手機序列號、手機“串號”,在移動電話網絡中識別每一部獨立的手機等行動通訊裝置;序列號共有15位數字,前6位(TAC)是型號覈准號碼,代表手機類型。接着2位(FAC)是最後裝配號,代表產地。後6位(SNR)是串號,代表生產順序號。最後1位(SP)一般爲0,是檢驗碼,備用。
IMSI(International Mobile SubscriberIdentification Number),儲存在SIM卡中,區別移動用戶的有效信息;其總長度不超過15位,同樣使用0~9的數字。其中MCC是移動用戶所屬國家代號,佔3位數字,中國的MCC規定爲460;MNC是移動網號碼,最多由兩位數字組成,用於識別移動用戶所歸屬的移動通信網;MSIN是移動用戶識別碼,用以識別某一移動通信網中的移動用戶。
Android ID是系統隨機生成的設備ID 爲一串64位的編碼(十六進制的字符串),通過它可以知道設備的壽命(在設備恢復出廠設置或刷機後,該值可能會改變)。
UDID (Unique Device Identifier),蘋果IOS設備的唯一識別碼,它由40個字符的字母和數字組成,爲了保護用戶隱私蘋果已經禁止讀取這個標識了。
UUID(Universally Unique IDentifier),是基於iOS設備上面某個單個的應用程序,只要用戶沒有完全刪除應用程序,則這個 UUID 在用戶使用該應用程序的時候一直保持不變。如果用戶刪除了這個應用程序,然後再重新安裝,那麼這個 UUID 已經發生了改變。缺點是用戶刪除了你開發的程序後,基本上無法獲取關聯之前的數據。
OpenUDID,不是蘋果官方的,是一個替代 UDID 的第三發解決方案, 缺點是如果你完全刪除全部帶有OpenUDID SDK 包的App(比如恢復系統等),那麼OpenUDID 會重新生成,而且和之前的值會不同。
IDFA (廣告標示符),蘋果禁用UDID後想出了折中辦法,就是提供另外一套和硬件無關的標識符,用於給商家監測廣告效果,這就是IDFA。用戶可以在手機設置裏改變這串字符,會導致商家沒有辦法長期跟蹤用戶行爲。
telphone(手機號)。 手機號也可以唯一的標識用戶。因爲兩個人的手機號在同一時間內不會一樣。
上面給出的這幾個信息都可以唯一標識一位用戶,可以作爲用戶ID號。
假設有一位用戶張三,在第一個手機上使用百度地圖, 在ipad上觀看百度愛奇藝視頻,在第二個手機上使用手機百度app, 在pc電腦上使用百度搜索,如何將同一個用戶在這些不同端的用戶信息聚合起來呢?
ID-Mapping主要解決這個問題,用來關聯ID信息。
算法思路
我們把用戶在各個端的信息收集起來,假設輸入兩條日誌的id信息爲:
line1: < mac1,mac2> < imei1> < tel1>
line2: < mac1> < imei2> < tel1,tel2>
上下是兩條用戶行爲日誌,看到他們都有mac1,兩條數據應該是同一個用戶。
使用多輪map-reduce的聚合方法,map做數據分塊,reduce做歸併
第一輪,以mac1和 mac2爲key字段來map和reduce
Map 輸出:
mac1 line1 < mac1,mac2 > < imei1> < tel1>
mac2 line1 < mac1,mac2> < imei1> < tel1>
mac1 line2 < mac1> < imei2> < tel1,tel2>
Reduce 輸出:
line1 < mac1,mac2> < imei1,imei2> < tel1,tel2>
line1 < mac1,mac2> < imei1> < tel1>
line2 < mac1,mac2> < imei2,imei1> < tel1,tel2>
第二輪, 以line1和 line2爲key字段來map和reduce
Map 輸出:
line1 < mac1,mac2> < imei1,imei2> < tel1,tel2>
line1 < mac1,mac2> < imei1> < tel1>
line2 < mac1,mac2> < imei2,imei1> < tel1,tel2>
Reduce 輸出:
line1 < mac1,mac2> < imei1,imei2> < tel1,tel2>
line2 < mac1,mac2> < imei1,imei2> < tel1,tel2>
第三輪, 以< mac1,mac2>爲key字段來map和reduce
Map輸出:
< mac1,mac2> < imei1,imei2> < tel1,tel2>
< mac1,mac2> < imei1,imei2> < tel1,tel2>
Reduce輸出:
< mac1, mac2> < imei1,imei2> < tel1,tel2>
依次指定< id >重複上述過程,直到無法歸併
數據和索引設計
數據庫表的設計,設置global-id作爲主key,(類似身份證號的作用),其他的字段都可以有多個(map< string,int>),這些用來表示一個用戶的多個身份標識。
//數據表
global_id string,
imei map<string,int>
mac map<string,int>
imsi map<string,int>
phone_number map<string,int>
idfa map<string,int>
openudid map<string,int>
uid map<string,int>
did map<string,int>
1
2
3
4
5
6
7
8
9
10
例如這四條記錄可以看到其實是一個用戶,存儲的時候就把它們存爲一個用戶,用global_id作爲key。
由此得到
global_id <=> imei,mac,imsi,phone_number,idfa,openudid,uid,did的相互映射關係。
//索引表
id string
global_id string
1
2
3
4
線上查詢的時候,假設獲取了mac1類型ID, 根據mac的索引表獲取global_id,然後根據global_id數據表獲取用戶imei、phone_number等其他ID信息。
ID過期問題
對於殭屍用戶,或者長期不用的用戶,保存數據沒有意義,浪費資源而且數據長期不更新後可能數據不準確。
可以對每個ID加入活躍度參數,一方面代表用戶的活躍程度,一方面可以對ID的存儲做控制。
用戶行爲數據:代表了用戶的活躍度,數據入表活躍度設置爲0
ID Mapping歷史數據:按周更新,代表上週用戶的數據,迭代計算時,活躍度+1
全量用戶信息數據:代表全量用戶,數據引入時,設置活躍度參數爲一個合理值。(eg: 60)