Doris在用戶畫像人羣業務的應用


歐陽利萍html

百度用戶畫像團隊架構負責人web

基於用戶畫像進行人羣定向是一種普遍的業務場景,在廣告、增加等領域有廣泛的應用。如何可以高效分析、規則篩選,特別是在超大規模的互聯網業務場景,是一個有挑戰性的技術問題。在這個分享裏面,咱們會介紹一種基於Doris來實現海量用戶tag下分析與圈選的高性能實現。sql



講座分爲三部份內容:apache

  • 用戶畫像羣體服務的業務場景微信

  • 技術問題、思路與相關業界方案實現狀況網絡

  • 基於Doris的技術實現數據結構






1 用戶畫像羣體服務的業務場景架構

1.1 畫像業務分析場景

百度的用戶畫像是面向百度全產品線的基礎數據和服務平臺。併發

咱們會爲包括百度鳳巢、搜索、Feed等百度各條產品線提供服務,天天有着千億級的離/在線的數據調用規模。app

隨着業務的發展,咱們逐步造成了用戶理解全流程的數據和服務,覆蓋從多元數據的採集、大規模的數據挖掘、高性能的數據服務以及面向業務場景的解決方案。


在咱們的工做中,用戶羣體分析人羣圈選是比較常見的需求,包括羣體分析、業務報表、Geo檢索、圈選等具體的場景。因爲整個數據的規模比較大,同時業務對於時效性的要求比較高,在很多的業務中咱們採用基於Doris的方法來支持和實現。羣體分析你們可能會比較熟悉,也就是對一個給定人羣作人羣報告和多維分析。業務報表也是常見的OLAP場景,對不少業務數據進行統計計算,Doris的基礎能力可以很好的知足這些業務場景。



Geo檢索你們可能不是那麼熟悉,Doris在2019年先後集成了Google Geo的索引,使得對於基於地理位置的數據可以快速地進行查詢、聚合操做。在一部分對於區域位置相關檢索的領域,Doris可以發揮它分佈式的優點,達到不錯的應用效果。

咱們本身的應用測試是經過構建覆蓋全北京的400萬細粒度多層網格數據,去完成一個具體的隨機的 0.1km2 以上的區域的羣體計算。Doris處理 1 平方千米區域的羣體數據的耗時在1.5秒左右,這對於不少的區域報表,像城市大屏、城市綜治管理等場景,它是有很是大的應用空間的。




1.2 超大數據規模下的標籤索引問題

基於用戶標籤的索引,是各大互聯網公司應用最普遍的業務,也是咱們今天重點討論的一個場景。

不管是基礎數據團隊仍是業務團隊都會經過標籤 tag 的挖掘來更好表達對用戶的理解。咱們畫像團隊系統地構建了用戶標籤體系,但咱們的數據規模相對來講更大一些。

這裏有幾個緣由:一個是整個產品線覆蓋和流量規模,此外還有一些特殊狀況,好比咱們的 id 規模遠大於天然人的 id 規模,是一個數百億級別的數據。

另一個方面,咱們從數據挖掘的層面創建了一個比較強、比較全面的畫像標籤體系,它的整個規模會比較大,人均的標籤覆蓋比較廣。它的好處是能夠靈活支撐應用,可是問題是在應用過程當中會產生一些規模上的問題。

基於這些標籤,能夠條件篩選的去構建人羣,進而在用戶推薦、廣告定向、消息推送、用戶增加等領域應用。

通常來講這種業務有兩個特色,一個是客戶對標籤的選擇範圍很是廣,條件組合很複雜,業務靈活度很是高;另外一個是對計算效率,特別是對於人羣圈選的數量,人羣分析計算的時效要求很是高。計算越快,使用越靈活,越可以幫助客戶找到他的目標人羣。





2 技術問題、思路

2.1 早期基於離線計算的方法

早期咱們採用的是基於離線的計算方法,也就是用MapReduce來解決問題。這個方法的問題很是顯而易見,靈活性差、計算成本很是高、時效是業務團隊幾乎不能忍受的,早期基本上是天級,最少也是小時級才能產出結果。


2.2 技術問題

咱們對問題進行了一個簡單的分析,問題的核心仍是前面提到的——被計算的數據規模。

咱們目前是300億——600億的IO規模,標籤數量2000+,因爲標籤下面還可能會有枚舉值,因此最終會有大概300萬左右的tag。對所有數據進行一個掃表操做就要花很是多的時間。

另外一個核心問題是,咱們以前的業務場景過於複雜,爲了配合業務場景在選擇技術方案是作了不少的讓步——更多的考慮知足業務需求而非性能。因此早期在計算邏輯層面沒有處理的特別好,整個計算效率是比較低的。

可是這一類需求在咱們的業務當中卻展示的尤其強烈,咱們很是迫切的想解決性能和功能的問題。因此在調研了很是多相似業務的方案後,咱們提出了一種高性能標籤索引的解決思路,而且考慮開發一套專用的系統來實現和解決相似的問題。


2.3 技術思路

(1)解決IO規模問題

原先的方法不管是基於MapReduce仍是其餘相似的邏輯,核心的問題在於咱們要對全局數據進行遍歷掃。由於咱們是以 uid 爲 key 的一個正向的數據結構,對標籤進行掃必需要掃全量。

這裏咱們的解決辦法是作倒排索引,以標籤爲 key 把 uid 做爲value。這樣構建一個反向索引以後,原來咱們是全表掃,如今變成只處理關注的標籤,這樣總體的IO規模會瞬間降低好幾個數量級。

其次咱們要作一個計算加速的優化,這裏面主要是邏輯的變化。把原來圈選的邏輯變成交併集的處理

在細節上須要作考慮兩個問題:

一個是把原來標籤的枚舉變成二值化的 tag。

好比:標籤球類運動,它的每個枚舉值,就須要拆解爲具體的 tag,如籃球、足球等。基於這個轉化,能夠把條件圈選變成交集、並集計算的組合。例如,選擇喜歡籃球運動、不喜歡足球運動,就能夠變成 tag-籃球 1,tag-足球 0 的交集。

另外一個是咱們有超過300萬個 tag ,在對 tag 作倒排索引時存儲空間會成爲一個很是大的問題,因此須要進一步下降存儲,提高計算效率。

咱們選擇採用 Bitmap 來優化標籤索引,用一個 bit 來標記一個 value,將用戶做爲整個 Bitmap 裏的一個位,這樣能夠實如今存儲上的空間節省。同時因爲位運算在交併集上自然的優點,在計算上也能帶來性能提高。

(2)加速計算過程

在解決計算規模問題時,核心的邏輯是用並行計算來加速過程。因爲數據的 tag 是 key 構建的,尤爲一些基礎的標籤的數據覆蓋率很是高,有些能夠達到90%以上,整個 Bitmap 會很是長。

這個狀況下,對於一個百億級的 uid 範圍,bitmap 的 size 將會很是大,這些 bitmap 會成爲計算平響,須要進一步對 bitmap 進行縱向的分桶,以加速計算,減小長尾。考慮 tag 數乘以分桶的狀況,這是一個數量可觀的分佈式並行的儲存與計算過程,對於分佈式系統有着很高的要求,也是一種典型的 MPP 場景。

比較巧的是,在和 Doris 同窗的交流過程中,咱們得知 Doris 正在作類似的工做。Doris 的 MPP 架構和正在進行的 Bitmap 集成,恰好是咱們業務須要的能力。能夠說是不謀而合。

咱們也調研了其餘開源解決方案好比說 Kylin 和 Druid,Kylin 在這個場景下有必定的侷限性,它須要預計算,這就帶來了維度和空間的爆炸,而且不能知足咱們對細粒度數據的需求。Druid 在這方面能夠知足咱們的需求,可是在一些特定使用場景下咱們是依賴Doris 的,因此咱們最終選擇了 Doris





3 基於Doris的技術實現

3.1 Doris分佈式查詢引擎

結合業務場景,咱們將方案調整爲基於Doris實現全套的標籤索引服務。

Doris 採用的 MPP 架構很是簡潔,由 FE 和 BE 完成從服務接入到數據存儲、管理、計算的分佈式服務。其中,FE 負責存儲以及維護集羣數據、接收、解析、查詢、設計規劃總體查詢流程,BE 負責數據存儲和具體的實施過程。FE 會根據用戶的查詢去生成一個完整的邏輯規劃,進一步構建分佈式的邏輯發給整個集羣去執行。

在右邊規劃圖中,由一個 BE 去執行的時候,須要經過 RPC 進行數據交換,不一樣的計算方法和內容,交換的數據也不一樣。


3.2 Bitmap在Doris的應用

Bitmap 一般做爲 OLAP 系統和存儲系統的索引,Doris 很早就集成了 Bitmap 來加速數據查詢的過程。

如上圖所示,右邊是 Doris Bitmap 索引的數據結構。

和索引應用不一樣,Bitmap 做爲數據應用,能夠解決明細數據的查詢、交併集問題。咱們在使用的時候將 Bitmap 做爲數據結構,直接使用 Bitmap 做爲實際存儲數據來解決明細數據查詢和交併集計算的問題。

基於Doris,首先咱們經過離線的MR形式完成了標籤 tag 的二值化和 uid 倒排(這裏還包括對ID的順序處理)。

而後咱們用 Bitmap 做爲數據結構,Bitmap Union爲聚合函數,採用Doris Load的方法完成了數據建庫和數據Load,這個過程可能比較慢但很可行。

接下來,咱們須要把條件查詢轉變成交併集計算,對單個節點來講,intersect_count / union_count 的方法 Doris 能夠自動完成分佈式的計算過程,實現已經 Bitmap 化的標籤數據的聚合計算。

基於以上的邏輯,咱們只用了兩週就完成了測試過程。


3.3 標籤索引應用在Doris基礎實現的問題

以上的方案在比較小的計算規模上能夠獲得計算結果,對於稍微複雜的計算場景,就出現了一些問題。

咱們作了一個測試,在300億的 uid,平均標籤數爲300的狀況下,可以完成不包含稠密 Bitmap 的 tag 進行6個標籤的交集和並集的計算,但當咱們把條件 tag 換成稠密的 Bitmap 以後,用14個標籤就已經超時了。(這裏稠密的Bitmap指 tag 數據在全量用戶 id 的覆蓋率很是高的狀況,而這種 tag 偏偏是咱們業務中最經常使用到的。)

除此以外還有一個功能問題,當時Doris還不支持批量ID導出。


3.4 標籤索引應用在Doris基礎實現的性能問題

結合 Doris 的計算過程,咱們分析認爲問題的核心主要有兩點。第一點在於 Bitmap 自己實現的邏輯,第二點在於在 Doris 中 Bitmap 分佈式實現的問題。

通常來講,32位 Bitmap 在壓縮比和計算效率上有很好的平衡,可是64位的 Bitmap 的計算效率就相對比較差。畫像的數據在百億級別,因此須要用64位的 Bitmap ,那麼計算效率就比較低。

第二個,當 Bitmap 基數比較大時,數據規模也比較大,網絡磁盤和網絡IO處理時間比較長。Doris 在計算過程當中須要 scan 數據後所有傳輸到頂層節點進行求交和求並運算,但本質上交併集計算是在單節點進行的,同時要通過網絡IO以後才能進行處理,這都成爲了影響性能的關鍵點。


3.5 性能解決方案

(1)Bitmap縱向切分建庫

針對以上的問題,咱們提出了一種正交的Bitmap計算的UDAF解決辦法。

咱們對 Bitmap 進行縱向的切分建庫,如右圖所示,咱們的出發點是減小或避免高32位的計算,而且進一步提高併發能力。

具體來說,首先咱們按照 uid 進行數據縱向切分,以 rid 範圍進行分片,下降單個 Bitmap 的 size。這同時帶來了一個好處,這種切分方式知足正交方式,不管在 tag 維度層面仍是在 id 範圍層面,同一個分片內是能夠相互獨立的。基於這種正交關係,咱們進一步優化分佈式計算的實現。


(2)分佈式計算優化

首先在數據層面,咱們讓相同 id 範圍的數據(即便不一樣 tag)也在相同的實例部署。在數據的交併集計算上,咱們讓各個分片分別在各自的節點上完成計算,merge的是計算結果而不是原始數據。這樣可讓計算的節點數變多、實現併發,還能夠在數據傳輸過程當中不進行全量傳輸,網絡通訊的成本也降到最低。

右圖所示是進行 count 計算時,在本地完成了 local 的交併集計算以後只須要把 count 值給出去,最後將不一樣的 count 值 merge 就完成了整個計算過程。


3.5 性能測試

通過以上的處理,咱們的總體計算效率獲得了很大的提高,小數據量的狀況下獲得了兩個數量級的提高,在大數據量下咱們由不可能變成了可能

從上圖中能夠看出,性能變得更加可用,能夠在秒級完成咱們的業務需求。


3.6 標籤索引應用在Doris基礎實現的功能問題

(1)數據灌庫、建庫

目前仍是基於以前的離線計算方式,這種方式效率不夠高,可是引入新的解決方法——Enhanced Spark-based Load,這種方式如今還在測試,預計性能會有很是大的提高。

(2)批量ID導出

Doris 自身的 SQL API 沒有支持億級數據導出。結合業務場景 Doris 的同窗幫咱們想出了一種解決方法——經過修改現有的 select outfile 將 MysqlWriter 改寫成 FileWriter,而且經過 Broker 把結果數據寫到遠端存儲。這樣就能夠實現批量原始 id 的數據導出,知足咱們對細粒度用戶數據的需求。





4 業務效果


  • 標籤索引知足主要人羣圈選業務場景

  • 人羣圈選時效從天/小時級提高到秒級響應

  • 業務應用效率大幅度提高,支持更加靈活的業務應用

  • 在廣告、增加等方向取得良好的業務效果




5 應用指南


咱們在今年8月已經將相關的代碼和使用指南已經提交到 Apache Doris 的代碼庫,供你們分享使用:http://doris.incubator.apache.org/master/zh-CN/extending-doris/udf/contrib/udaf-orthogonal-bitmap-manual.html

這裏須要有一個額外的編譯過程來知足UDAF的應用:

最終使用的時候只須要寫一個select BITMAP_COUNT 就能夠快速獲得須要的數據結果。


本文分享自微信公衆號 - 小晨說數據(flink-spark)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索