第3章 標簽數據存儲
在畫像系統搭建的過程中,數據存儲的技術選型是非常重要的一項內容,不同的存儲方式適用于不同的應用場景。本章主要介紹使用Hive、MySQL、HBase、Elasticsearch存儲畫像相關數據的應用場景及對應的解決方案。
3.1 Hive存儲
3.1.1 Hive數據倉庫
建立用戶畫像首先需要建立數據倉庫,用于存儲用戶標簽數據。Hive是基于Hadoop的數據倉庫工具,依賴于HDFS存儲數據,提供的SQL語言可以查詢存儲在HDFS中的數據。開發時一般使用Hive作為數據倉庫,存儲標簽和用戶特征庫等相關數據。
“數據倉庫之父”W.H.Inmon在《Building the Data Warehouse》一書中定義數據倉庫是“一個面向主題的、集成的、非易失的、隨時間變化的、用來支持管理人員決策的數據集合”。
數據抽取到數據倉庫的流程如圖3-1所示。
在數據倉庫建模的過程中,主要涉及事實表和維度表的建模開發(圖3-2)。
事實表主要圍繞業務過程設計,就應用場景來看主要包括事務事實表,周期快照事實表和累計快照事實表:
?事務事實表:用于描述業務過程,按業務過程的單一性或多業務過程可進一步分為單事務事實表和多事務事實表。其中單事務事實表分別記錄每個業務過程,如下單業務記入下單事實表,支付業務記入支付事實表。多事務事實表在同一個表中包含了不同業務過程,如下單、支付、簽收等業務過程記錄在一張表中,通過新增字段來判斷屬于哪一個業務過程。當不同業務過程有著相似性時可考慮將多業務過程放到多事務事實表中。
?周期快照事實表:在一個確定的時間間隔內對業務狀態進行度量。例如查看一個用戶的近1年付款金額、近1年購物次數、近30日登錄天數等。
?累計快照事實表:用于查看不同事件之間的時間間隔,例如分析用戶從購買到支付的時長、從下單到訂單完結的時長等。一般適用于有明確時間周期的業務過程。
維度表主要用于對事實屬性的各個方面描述,例如,商品維度包括商品的價格、折扣、品牌、原廠家、型號等方面信息。維度表開發的過程中,經常會遇到維度緩慢變化的情況,對于緩慢變化維一般會采用:
①重寫維度值,對歷史數據進行覆蓋;
②保留多條記錄,通過插入維度列字段加以區分;
③開發日期分區表,每日分區數據記錄當日維度的屬性;
④開發拉鏈表按時間變化進行全量存儲等方式進行處理。
在畫像系統中主要使用Hive作為數據倉庫,開發相應的維度表和事實表來存儲標簽、人群、應用到服務層的相關數據。
拉鏈表說明:
拉鏈表 - 維護歷史狀態,以及最新狀態數據的一種表,拉鏈表根據拉鏈粒度的不同,實際上相當于快照,只不過做了優化,去除了一部分不變的記錄而已,通過拉鏈表可以很方便的還原出拉鏈時點的客戶記錄。拉鏈表通常是對賬戶信息的歷史變動進行處理保留的結果。
3.1.2 分區存儲
如果將用戶標簽開發成一張大的寬表,在這張寬表下放幾十種類型標簽,那么每天該畫像寬表的ETL作業將會花費很長時間,而且不便于向這張寬表中新增標簽類型。要解決這種ETL花費時間較長的問題,可以從以下幾個方面著手:
?將數據分區存儲,分別執行作業;
?標簽腳本性能調優;
?基于一些標簽共同的數據來源開發中間表。
下面介紹一種用戶標簽分表、分區存儲的解決方案。根據標簽指標體系的人口屬性、行為屬性、用戶消費、風險控制、社交屬性等維度分別建立對應的標簽表進行分表存儲對應的標簽數據。如圖3-3所示。
?人口屬性表:dw.userprofile_attritube_all;
?行為屬性表:dw.userprofile_action_all;
?用戶消費表:dw.userprofile_consume_all;
?風險控制表:dw.userprofile_riskmanage_all;
?社交屬性表:dw.userprofile_social_all
例如創建用戶的人口屬性寬表:
同樣的,用戶其他id維度(如cookieid、deviceid、registerid等)的標簽數據存儲,也可以使用上面案例中的表結構。
在上面的創建中通過設立人口屬性維度的寬表開發相關的用戶標簽,為了提高數據的插入和查詢效率,在Hive中可以使用分區表的方式,將數據存儲在不同的目錄中。在Hive使用select查詢時一般會掃描整個表中所有數據,將會花費很多時間掃描不是當前要查詢的數據,為了掃描表中關心的一部分數據,在建表時引入了partition的概念。在查詢時,可以通過Hive的分區機制來控制一次遍歷的數據量。
3.1.3 標簽匯聚
在3.1.2節的案例中,用戶的每個標簽都插入到相應的分區下面,但是對一個用戶來說,打在他身上的全部標簽存儲在不同的分區下面。為了方便分析和查詢,需要將用戶身上的標簽做聚合處理。緊接3.1.2節的案例,下面講解標簽匯聚的開發案例(見圖3-4)。
標簽匯聚后將一個每個用戶身上的全量標簽匯聚到一個字段中,表結構設計如下:
開發udf函數“cast_to_json”將用戶身上的標簽匯聚成json字符串,執行命令將按分區存儲的標簽進行匯聚:
匯聚后用戶標簽的存儲格式如圖3-5所示
將用戶身上的標簽進行聚合便于查詢和計算。例如,在畫像產品中,輸入用戶id后通過直接查詢該表,解析標簽id和對應的標簽權重后,即可在前端展示該用戶的相關信息(如圖3-6所示)。
3.1.4 ID-MAP
開發用戶標簽的時候,有項非常重要的內容——ID-MApping,即把用戶不同來源的身份標識通過數據手段識別為同一個主體。用戶的屬性、行為相關數據分散在不同的數據來源中,通過ID-MApping能夠把用戶在不同場景下的行為串聯起來,消除數據孤島。圖3-7展示了用戶與設備間的多對多關系。圖3-8展示了同一用戶在不同平臺間的行為示意圖。
舉例來說,用戶在未登錄App的狀態下,在App站內訪問、搜索相關內容時,記錄的是設備id(即cookieid)相關的行為數據。而用戶在登錄App后,訪問、收藏、下單等相關的行為記錄的是賬號id(即userid)相關行為數據。雖然是同一個用戶,但其在登錄和未登錄設備時記錄的行為數據之間是未打通的。通過ID-MApping打通userid和cookieid的對應關系,可以在用戶登錄、未登錄設備時都能捕獲其行為軌跡。
下面通過一個案例介紹如何通過Hive的ETL工作完成ID-Mapping的數據清洗工作。
緩慢變化維是在維表設計中常見的一種方式,維度并不是不變的,隨時間也會發生緩慢變化。如用戶的手機號、郵箱等信息可能會隨用戶的狀態變化而改變,再如商品的價格也會隨時間變化而調整上架的價格。因此在設計用戶、商品等維表時會考慮用緩慢變化維來開發。同樣,在設計ID-Mapping表時,由于一個用戶可以在多個設備上登錄,一個設備也能被多個用戶登錄,所以考慮用緩慢變化維表來記錄這種不同時間點的狀態變化(圖3-9)。
拉鏈表是針對緩慢變化維表的一種設計方式,記錄一個事物從開始到當前狀態的全部狀態變化信息。
在上圖中,通過拉鏈表記錄了userid每一次關聯到不同cookieid的情況。如userid為44463729的用戶,在20190101這天登錄某設備,在6號那天變換了另一個設備登錄。其中start_date表示該記錄的開始日期,end_date表示該記錄的結束日期,當end_date為99991231時,表示該條記錄當前仍然有效。
首先需要從埋點表和訪問日志表里面獲取到cookieid和userid同時出現的訪問記錄。下面案例中,ods.page_event_log是埋點日志表,ods.page_view_log是訪問日志表,將獲取到的userid和cookieid信息插入cookieid-userid關系表(ods.cookie_user_signin)中。代碼執行如下:
創建ID-Map的拉鏈表,將每天新增到ods.cookie_user_signin表中的數據與拉鏈表歷史數據做比較,如果有變化或新增數據則進行更新。
數據寫入表中,如圖3-9所示。對于該拉鏈表,可查看某日(如20190801)的快照數據。
例如,目前存在一個記錄userid和cookieid關聯關系的表,但是為多對多的記錄(即一個userid對應多條cookieid記錄,以及一條cookieid對應多條userid記錄)。這里可以通過拉鏈表的日期來查看某個時間點userid對應的cookieid。查看某個用戶(如32101029)在某天(如20190801)關聯到的設備id(圖3-10)。
上圖可看出用戶‘32101029’在歷史中曾登錄過3個設備,通過限定時間段可找到特定時間下用戶的登錄設備。
在開發中需要注意關于userid與cookieid的多對多關聯,如果不加條件限制就做關聯,很可能引起數據膨脹問題。
在實際應用中,會遇到許多需要將userid和cookieid做關聯的情況。例如,需要在userid維度開發出該用戶近30日的購買次數、購買金額、登錄時長、登錄天數等標簽。前兩個標簽可以很容易地從相應的業務數據表中根據算法加工出來,而登錄時長、登錄天數的數據存儲在相關日志數據中,日志數據表記錄的userid與cookieid為多對多關系。因此在結合業務需求開發標簽時,要確定好標簽口徑定義。
本節中通過案例介紹了將userid和cookieid打通的一種解決方案,實踐中還存在需要將用戶在不同平臺間(如Web端和App端)行為打通的應用場景。
3.2 MySQL存儲
MySQL作為關系型數據庫,在用戶畫像中可用于元數據管理、監控預警數據、結果集存儲等應用中。下面詳細介紹這3個應用場景。
3.2.1 元數據管理
Hive適合于大數據量的批處理作業,對于量級較小的數據,MySQL具有更快的讀寫速度。Web端產品讀寫MySQL數據庫會有更快的速度,方便標簽的定義、管理。在7.2節和7.3節中,我們會介紹元數據錄入和查詢功能,將相應的數據存儲在MySQL中。用戶標簽的元數據表結構設計會在7.3節進行詳細的介紹。這里給出了平臺標簽視圖(如圖3-11所示)和元數據管理頁面(如圖3-12所示)。
平臺標簽視圖中的標簽元數據可以維護在MySQL關系數據庫中,便于標簽的編輯、查詢和管理。
3.2.2 監控預警數據
MySQL還可用于存儲每天對ETL結果的監控信息。從整個畫像調度流的關鍵節點來看,需要監控的環節主要包括對每天標簽的產出量、服務層數據同步情況的監控等主要場景。圖3-13所示是用戶畫像調度流主要模塊,下面詳細介紹。
1.標簽計算數據監控
主要用于監控每天標簽ETL的數據量是否出現異常,如果有異常情況則發出告警郵件,同時暫停后面的ETL任務。
2.服務層同步數據監控
服務層一般采用HBase、Elasticsearch等作為數據庫存儲標簽數據供線上調用,將標簽相關數據從Hive數倉向服務層同步的過程中,有出現差錯的可能,因此需要記錄相關數據在Hive中的數量及同步到對應服務層后的數量,如果數量不一致則觸發告警。
在對畫像的數據監控中,調度流每跑完相應的模塊,就將該模塊的監控數據插入MySQL中,當校驗任務判斷達到觸發告警閾值時,發送告警郵件,同時中斷后續的調度任務。待開發人員解決問題后,可重啟后續調度。
3.2.3 結果集存儲
結果集可以用來存儲多維透視分析用的標簽、圈人服務用的用戶標簽、當日記錄各標簽數量,用于校驗標簽數據是否出現異常。
有的線上業務系統使用MySQL、Oracle等關系型數據庫存儲數據,如短信系統、消息推送系統等。在打通畫像數據與線上業務系統時,需要考慮將存儲在Hive中的用戶標簽相關數據同步到各業務系統,此時MySQL可用于存儲結果集。
Sqoop是一個用來將Hadoop和關系型數據庫中的數據相互遷移的工具。它可以將一個關系型數據庫(如MySQL、Oracle、PostgreSQL等)中的數據導入Hadoop的HDFS中,也可以將HDFS中的數據導入關系型數據庫中。
下面通過一個案例來講解如何使用Sqoop將Hive中的標簽數據遷移到MySQL中。
電商、保險、金融等公司的客服部門的日常工作內容之一是對目標用戶群(如已流失用戶、高價值用戶等)進行主動外呼,以此召回用戶來平臺進行購買或復購。這里可以借助用戶畫像系統實現該功能。
將Hive中存儲的與用戶身份相關的數據同步到客服系統中,首先在Hive中建立一張記錄用戶身份相關信息的表(dw.userprofile_userservice_all)。設置日期分區以滿足按日期選取當前人群的需要。
在MySQL中建立一張用于接收同步數據的表(userservice_data)。
通過Python腳本調用shell命令,將Hive中的數據同步到MySQL中。執行如下腳本:
其中用到了sqoop從Hive導出數據到MySQL的命令:
同步后MySQL中的數據如圖3-14所示。
3.3 HBase存儲
3.3.1 HBase簡介
HBase是一個高性能、列存儲、可伸縮、實時讀寫的分布式存儲系統,同樣運行在HDFS之上。與Hive不同的是,HBase能夠在數據庫上實時運行,而不是跑MapReduce任務,適合進行大數據的實時查詢。
畫像系統中每天在Hive里跑出的結果集數據可同步到HBase數據庫,用于線上實時應用的場景。下面介紹幾個基本概念:
?row key:用來表示唯一一行記錄的主鍵,HBase的數據是按照row key的字典順序進行全局排列的。
訪問HBase中的行只有3種方式:
○通過單個row key訪問;
○通過row key的正則訪問;
○全表掃描。
由于HBase通過rowkey對數據進行檢索,而rowkey由于長度限制的因素不能將很多查詢條件拼接在rowkey中,因此HBase無法像關系數據庫那樣根據多種條件對數據進行篩選。一般地,HBase需建立二級索引來滿足根據復雜條件查詢數據的需求。
Rowkey設計時需要遵循三大原則:
○唯一性原則:rowkey需要保證唯一性,不存在重復的情況。在畫像中一般使用用戶id作為rowkey。
○長度原則:rowkey的長度一般為10-100bytes。
○散列原則:rowkey的散列分布有利于數據均衡分布在每個RegionServer,可實現負載均衡。
?columns family:指列簇,HBase中的每個列都歸屬于某個列簇。列簇是表的schema的一部分,必須在使用表之前定義。劃分columns family的原則如下:
○是否具有相似的數據格式;
○是否具有相似的訪問類型。
常用的增刪改查命令如下。
1)創建一個表,指定表名和列簇名:[插圖]
create '<table name>','<column family>'
2)掃描表中數據,并顯示其中的10條記錄:[插圖]
scan 'table name',{LIMIT =>10}
3)使用get命令讀取數據:[插圖]
get '<table name>','row1'
4)插入數據:[插圖]
put '<table name>','row ','colfamily:colname','<value>'
5)更新數據:[插圖]
put '<table name>','row','Column family:column name','new value'
6)在刪除表之前先將其禁用,然后刪除:[插圖]
disable '<table name>'
drop '<table name>'
下面通過一個案例來介紹HBase在畫像系統中的應用場景和工程化實現方式。
3.3.2 應用場景
某渠道運營人員為促進未注冊的新安裝用戶注冊、下單,計劃通過App首頁彈窗(如圖3-15所示)發放紅包或優惠券的方式進行引導。在該場景中可通過畫像系統實現對應功能。
業務邏輯上,渠道運營人員通過組合用戶標簽(如“未注冊用戶”和“安裝距今天數”小于××天)篩選出對應的用戶群,然后選擇將對應人群推送到“廣告系統”(產品功能詳見7.4節),這樣每天畫像系統的ETL調度完成后對應人群數據就被推送到HBase數據庫進行存儲。滿足條件的新用戶來訪App時,由在線接口讀取HBase數據庫,在查詢到該用戶時為其推送該彈窗。
下面通過某工程案例來講解HBase在該觸達用戶場景中的應用方式。
3.3.3 工程化案例
運營人員在畫像系統(詳見第7章)中根據業務規則定義組合用戶標簽篩選出用戶群,并將該人群上線到廣告系統中(如圖3-16所示)。
在業務人員配置好規則后,下面我們來看在數據調度層面是如何運行的。
用戶標簽數據經過ETL將每個用戶身上的標簽聚合后插入到目標表中,如dw.userprofile_userlabel_map_all(詳見3.1.3節)。聚合后數據存儲為每個用戶id,以及他身上對應的標簽集合,數據格式如圖3-17所示。
接下來需要將Hive中的數據導入HBase,便于線上接口實時調用庫中數據。
HBase的服務器體系結構遵循主從服務器架構(如圖3-18所示),同一時刻只有一個HMaster處于活躍狀態,當活躍的Master掛掉后,Backup HMaster自動接管整個HBase集群。在同步數據前,首先需要判斷HBase的當前活躍節點是哪臺機器。
執行如下腳本:
執行完畢后,可通過返回的“State”字段判斷當前節點狀態(活躍為“active”,不活躍為“standby”),如圖3-19所示。
為避免數據都寫入一個region,造成HBase的數據傾斜問題。在當前HMaster活躍的節點上,創建預分區表:
將待同步的數據寫入HFile,HFile中的數據以key-value鍵值對方式存儲,然后將HFile數據使用BulkLoad批量寫入HBase集群中。Scala腳本執行如下:
......
提交Spark任務,將HFile中數據bulkload到HBase中。執行完成后,可以在HBase中看到該數據已經寫入“userprofile_labels”中(圖3-20)。
在線接口在查詢HBase中數據時,由于HBase無法像關系數據庫那樣根據多種條件對數據進行篩選(類似SQL語言中的where篩選條件)。一般地HBase需建立二級索引來滿足根據復雜條件查詢數據的需求,本案中選用Elasticsearch存儲HBase索引數據(圖3-21)。
在組合標簽查詢對應的用戶人群場景中,首先通過組合標簽的條件在Elasticsearch中查詢對應的索引數據,然后通過索引數據去HBase中批量獲取rowkey對應的數據(Elasticsearch中的documentid和HBase中的rowkey都設計為用戶id)。
為了避免從Hive向HBase灌入數據時缺失,在向HBase數據同步完成后,還需要校驗HBase和Hive中數據量是否一致,如出現較大的波動則發送告警信息。下面通過Python腳本來看該HBase狀態表數據校驗邏輯:
本案例中將userid作為rowkey存入HBase,一方面在組合標簽的場景中可以支持條件查詢多用戶人群,另一方面可以支持單個用戶標簽的查詢,例如查看某id用戶身上的標簽,以便運營人員決定是否對其進行運營操作。HBase在離線數倉環境的服務架構如圖3-22所示。
3.4 Elasticsearch存儲
3.4.1 Elasticsearch簡介
Elasticsearch是一個開源的分布式全文檢索引擎,可以近乎實時地存儲、檢索數據。而且可擴展性很好,可以擴展到上百臺服務器,處理PB級別的數據。對于用戶標簽查詢、用戶人群計算、用戶群多維透視分析這類對響應時間要求較高的場景,也可以考慮選用Elasticsearch進行存儲。
Elasticsearch是面向文檔型數據庫,一條數據在這里就是一個文檔,用json作為文檔格式。為了更清晰地理解Elasticsearch查詢的一些概念,將其和關系數據庫的類型進行對照,如圖3-23所示。
在關系型數據庫中查詢數據時可通過選中數據庫、表、行、列來定位所查找的內容,在Elasticsearch中通過索引(index)、類型(type)、文檔(document)、字段來定位查找內容。一個Elasticsearch集群可以包括多個索引(數據庫),也就是說,其中包含了很多類型(表),這些類型中包含了很多的文檔(行),然后每個文檔中又包含了很多的字段(列)。Elasticsearch的交互可以使用Java API,也可以使用HTTP的RESTful API方式。
3.4.2 應用場景
基于HBase的存儲方案并沒有解決數據的高效檢索問題。在實際應用中,經常有根據特定的幾個字段進行組合后檢索的應用場景,而HBase采用rowkey作為一級索引,不支持多條件查詢,如果要對庫里的非rowkey進行數據檢索和查詢,往往需要通過MapReduce等分布式框架進行計算,時間延遲上會比較高,難以同時滿足用戶對于復雜條件查詢和高效率響應這兩方面的需求。
為了既能支持對數據的高效查詢,同時也能支持通過條件篩選進行復雜查詢,需要在HBase上構建二級索引,以滿足對應的需要。在本案中我們采用Elasticsearch存儲HBase的索引信息,以支持復雜高效的查詢功能。
主要查詢過程包括:
1)在Elasticsearch中存放用于檢索條件的數據,并將rowkey也存儲進去;
2)使用Elasticsearch的API根據組合標簽的條件查詢出rowkey的集合;
3)使用上一步得到的rowkey去HBase數據庫查詢對應的結果(見圖3-24)。
HBase數據存儲數據的索引放在Elasticsearch中,實現了數據和索引的分離。在Elasticsearch中documentid是文檔的唯一標識,在HBase中rowkey是記錄的唯一標識。在工程實踐中,兩者可同時選用用戶在平臺上的唯一標識(如userid或deviceid)作為rowkey或documentid,進而解決HBase和Elasticsearch索引關聯的問題。
下面通過使用Elasticsearch解決用戶人群計算和分析應用場景的案例來了解這一過程。
對匯聚后的用戶標簽表dw.userprofile_userlabel_map_all(3.1.3節)中的數據進行清洗,過濾掉一些無效字符,達到導入Elasticsearch的條件,如圖3-25所示。
然后將dw.userprofile_userlabel_map_all數據寫入Elasticsearch中,Scala代碼如下:
.......
工程依賴如下:
將該工程打包之后提交任務,傳入日期分區參數“20190101”執行。提交命令“spark-submit--class com.example.HiveDataToEs--master yarn--deploy-mode client--executor-memory 2g--num-executors 50--driver-memory 3g--executor-cores 2 spark-hive-to-es.jar 20190101”。任務執行完畢后,當日userid維度的用戶標簽數據全部導入Elasticsearch中。使用RESTfulAPI查詢包含某個標簽的用戶量,可實時得到返回結果,如圖3-26所示。
。。。
3.5 本章小結
本章講解了使用Hive、MySQL、HBase和Elasticsearch存儲標簽數據的解決方案,包括:Hive存儲數據相關標簽表、人群計算表的表結構設計以及ID-Mapping的一種實現方式;MySQL存儲標簽元數據、監控數據及結果集數據;HBase存儲線上接口實時調用的數據;Elasticsearch存儲標簽用于人群計算和人群多維透視分析。存儲過程中涉及如下相關表。
?dw.userprofile_attritube_all:存儲人口屬性維度的標簽表;
?dw.userprofile_action_all:存儲行為屬性維度的標簽表;
?dw.userprofile_consume_all:存儲用戶消費維度的標簽表;
?dw.userprofile_riskmanage_all:存儲風險控制維度的標簽表;
?dw.userprofile_social_all:存儲社交屬性維度的標簽表;
?dw.userprofile_userlabel_map_all:匯聚用戶各維度標簽的表;
?dw.userprofile_usergroup_labels_all:存儲計算后人群數據的表。
面向不同的工程場景使用不同的存儲方案,本章通過“工程場景+案例”的形式介紹了一種可實現的用戶標簽存儲解決方案。
本文為讀書筆記,更多精彩內容請自行購買書籍。