博客 / 詳情

返回

貨拉拉用户畫像基於 Apache Doris 的數據模型設計與實踐

貨拉拉是國內領先的同城貨運數字化平台,成立於 2013 年。截⾄2025 年 4⽉ ,貨拉拉業務覆蓋全球 14 個市場 ,400+ 城市 ,其中中國內地總共覆蓋 363 座城市 ,⽉活司機達 120 萬 ,⽉活⽤户達 1400 萬, 並在全球設有 6 個數據中⼼。作為共享經濟模式的代表企業 ,貨拉拉通過移動互聯⽹技術整合社會運⼒資源 ,為⽤户提供即時貨運、企業物流、搬家服務等多元化解決⽅案。

在龐⼤的業務規模下 ,構建完善的⽤户畫像平台成為實現精細化運營的重要基礎 ,可以有效提升運營效率和⽤户體驗。

畫像服務背景與架構

目前貨拉拉的畫像平台已深度應用於多個核心業務場景,各業務場景對標籤的使⽤⽅式和時效性要求各不相同。從 22 年到 25 年,用户呈現穩定增長趨勢,業務對服務的壓力也是逐年遞增,累計接入了 300+ 業務,3,000+ 個標籤以及 5 萬多人羣。

畫像服務背景與架構.png

01 應用架構

貨拉拉用户畫像應用架構.PNG

上圖是貨拉拉畫像平台整體架構圖,Apache Doris 作為統一查詢引擎,為人羣畫像提供高效的分析能力。該平台通過架構分層實現了業務需求與技術能力的精準匹配。其中有兩個核心模塊:

  • API 層(接⼝服務層):基於重點使⽤場景和對接系統搭建的畫像接口服務 ,從⽽精準地⽣成用户畫像 ,給到對接業務⽅使⽤。其中包括:

    • persona-api:⾯向⾼併發查詢場景
    • persona-analysis-api:承接分析計算與推送作業請求
    • persona-web-api:⽀持管理後台的 Web 服務
  • BE 層(計算引擎層) :建造基於大數據體系的用户標籤鏈路的畫像管理平台 ,⽤於在特定業務形態下描述業務主體;其中包括:

    • persona-task:執⾏分佈式計算作業 ,⽀持橫向擴展
    • persona-scheduler :調度⼈羣計算任務

兩大模塊協同工作,共同支撐業務方的精細化運營需求。

貨拉拉用户畫像應用架構-1.PNG

02 畫像平台計算引擎演進

在核心計算引擎的選型與演進過程中,技術團隊經歷了三個主要階段。

  • 第一階段,受限於成本因素,採用了三方服務結合 Impala+KUDU 的架構作為用户畫像計算引擎。該架構在實際應用中暴露出諸多問題:單次人羣計算耗時 10 分鐘以上,高峯期甚至超過 30 分鐘;同時,數據導入耗時較長,經常超時。此外,該架構存在橫向擴展困難、複雜查詢效率偏低及運維複雜等不足。
  • 第二階段,為尋求改進,我們嘗試引入 Elasticsearch,雖在一定程度上有所緩解,但仍面臨開發成本高、語法複雜、多維分析能力不足等挑戰,且在動態擴展和複雜查詢方面未實現根本性改善。尤其在處理人羣間存在依賴關係的特殊業務場景時,Elasticsearch 架構難以有效支持。
  • 基於此,我們最終轉向採用 Doris 作為核心計算引擎。選擇 Doris 的關鍵因素如下:

    • 性能優越:基於 MPP 架構、具備向量化引擎和先進的優化器能力,查詢性能優秀。
    • 社區資源豐富:Doris 擁有活躍的社區支持以及豐富的文檔資料,自行搭建遇到卡點時,可向社區幫助尋求專業的指導與幫助。
    • 支持多種數據類型:畫像場景可以使用 BITMAP 實現高效的交併集運算,成為支撐多樣化標籤類型與人羣分析業務的技術基礎。
    • 支持多種數據模型:針對多維複雜的人羣畫像,可以使用不同的數據模型支撐各種標籤類型與人羣業務。

自引入 Doris 後,系統穩定性得到了顯著提升,至今未出現過重大穩定性問題,整體鏈路的時效性與可靠性均實現了根本性的優化,具體如下:

  • 在計算效率方面,單個人羣的計算能夠實現秒級響應,即使在高峯期,響應時間也保持在 1 分鐘以內。相比之下,Impala 架構下該計算過程通常需要 10 至 30 分鐘。採用 Doris 後,計算效率提升了近 30 倍。
  • 在數據導入方面,Doris 同樣表現出色。在處理 4 億行 200 列的單表數據時,Doris 可在 30 分鐘內完成導入操作。而在同等條件下,Impala 架構則需要 90 分鐘以上,Doris 數據導入效率是 Impala 架構的 3 倍

畫像平台計算引擎演進.png

數據模型設計與異構查詢實現

01 核心挑戰

核心挑戰.png

首先是用户畫像標籤存儲的挑戰。面對 3000+ 標籤的體系,我們發現標籤數據天然存在三個維度的分裂特徵:業務屬性(行為/屬性/地理等)、聚合粒度(明細/聚合/人羣)、更新時效(離線/近實時/實時)。不同業務屬性的數據在更新頻率、查詢模式、存儲密度上差異巨大。

此外,用户使用畫像標籤的時候,對人羣標籤/明細標籤/聚合標籤等概念不清晰,只會進行簡單的拖拉拽拼接規則。因此在標籤使用場景,如何選擇存儲模型成為了核心問題。若使用寬表,將面臨動態更新以及列拓展的挑戰;而高表則面臨複雜查詢與嵌套邏輯的挑戰。

02 存儲模型設計

面對複雜的標籤管理,我們採用了基於 Apache Doris 分而治之的存儲方案,具體分為三類模型來進行協同工作。

標籤寬表

  • 存儲低頻更新的標籤。
  • 存儲無法用高表存儲的密集標籤。
  • 利用 Doris 的列式存儲技術,利用索引、物化視圖等優化手段,支持高效的多維分析。

標籤寬表建表 SQL 參考:

CREATE TABLE  wide_table  (
 user_id  varchar(1000) NULL COMMENT "",
 age  bigint(20) REPLACE_IF_NOT_NULL NULL COMMENT "",
 height  bigint(20) REPLACE_IF_NOT_NULL NULL COMMENT "",
 ......) ENGINE=OLAP AGGREGATE KEY( user_id ) COMMENT "OLAP"
DISTRIBUTED BY HASH( user_id ) BUCKETS 40
PROPERTIES ( ... )

標籤高表

  • 存儲高頻更新的稀疏標籤。
  • 支持秒級/分鐘級數據更新,標籤新增的場景下,可以規避寬表頻繁 ALTER TABLE 導致的鎖表問題。
  • 多個標籤的位圖交併計算,並且支持毫秒級響應。

標籤高表建表 SQL 參考:

CREATE TABLE  high_table  (
 tag  varchar(45) NULL COMMENT "標籤名",
 tag_value  varchar(45) NULL COMMENT "標籤值",
 time  datetime NOT NULL COMMENT "數據灌入時間",
 user_ids  bitmap BITMAP_UNION NULL COMMENT "用户集"
) ENGINE=OLAP AGGREGATE KEY( tag ,  tag_value ,  time  ) COMMENT "OLAP"
DISTRIBUTED BY HASH( tag ) BUCKETS 128
PROPERTIES ( ... )

人羣位圖表

  • 用於存儲標籤規則圈選出來的人羣結果。
  • 用户 ID 集合使用 RoaringBitmap 壓縮,降低存儲成本。
  • 支持人羣依賴計算,避免表數量膨脹問題,⽀持⼈羣營銷實驗業務。

人羣位圖表建表 SQL 參考:

CREATE TABLE  routine_segmentation_bitmap (
 time  datetime NOT NULL COMMENT "數據灌入時間",
 seg_name  varchar(45) NULL COMMENT "標籤值",
 user_ids  bitmap BITMAP_UNION NULL COMMENT "人羣ID集合"
) ENGINE=OLAP AGGREGATE KEY( time ,  seg_name )
COMMENT "OLAP" PARTITION BY RANGE(`time`) (...)DISTRIBUTED BY HASH( seg_name )
BUCKETS 128
PROPERTIES (..., "dynamic_partition.enable" = "true", ...);

03 人羣圈選與異構組合查詢

基於上述提到了三種存儲模型,我們構建了以位圖計算為核心的異構組合計算體系,並將其作用於整個人羣圈選的場景,實現寬表、高表及人羣表這三類存儲模型之間的無縫聯動。

  1. 第一步:將所有單一標籤或子查詢的結果都處理成 Bitmap 位圖,處理寬表的標籤使用TO_BITMAP聚合多列 ID 結果,處理標籤高表和人羣表則直接使用預聚合的 Bitmap,加速邏輯複用。
  2. 第二步,通過UNION ALL整合寬表/高表/人羣表三種數據源的 Bitmap,並使用外層的BITMAP_INTERSECT/BITMAP_UNION實現跨模型交併集運算(AND/OR 邏輯)。
  3. 第三步,由於BITMAP_INTERSECT/BITMAP_UNION的結果也是 Bitmap,所以可以用同樣的處理方式,遞歸整合子查詢的查詢結果,並支持直接導出或對接業務系統。

人羣圈選與異構組合查詢.png

該實現方法具備三大核心優勢:

  • 靈活拓展:動態嵌套子查詢支持無限層級規則(如 “A 且(B 或 C)且(D 且(E 或 F))” ) ,靜態屬性、動態行為以及預計算人羣等複雜的標籤規則皆可無縫嵌入。
  • 資源節省:複用人羣表(預計算人羣)的數據從而大幅減輕計算壓力,並允許不同人羣間相互依賴進行計算;人羣計算結果使用 RoaringBitmap 存儲,不需要額外新增表。
  • 業務友好:支持人羣+標籤的複雜混合嵌套查詢,用户無需技術基礎,僅通過簡單的拖拽標籤條件即可高效圈定目標用户羣體,適用於營銷等多種場景。

查詢 SQL 示例:

SELECT BITMAP_INTERSECT(b) FROM (
  -- Layer1: 寬表條件A
  SELECT TO_BITMAP(...) AS b FROM 標籤寬表 WHERE 條件A
  UNION ALL
  -- Layer1: 高表條件B
  SELECT user_ids AS b FROM 標籤高表 WHERE 條件B
  UNION ALL
  -- Layer1: 人羣條件C
  SELECT user_ids AS b FROM 人羣表 WHERE 條件C
  UNION ALL
  -- Layer2: 嵌套子查詢(新條件D/E/F)
  SELECT BITMAP_INTERSECT(b) FROM (
    SELECT TO_BITMAP(...) AS b FROM 標籤寬表 WHERE 條件D  -- 新寬表條件
    UNION ALL
    SELECT user_ids AS b FROM 標籤高表 WHERE 條件E      -- 新高表條件
    UNION ALL
    SELECT BITMAP_INTERSECT(...) AS b FROM 人羣表 WHERE 條件F -- 新人羣條件
  )
) t;

04 數據導入

貨拉拉畫像服務的實時標籤/人羣點查主要採用 HBase 與 Redis 相結合的方式,Doris 主要承擔人羣圈選、人羣洞察、行為分析等任務。實時和近實時標籤寫入 Doris 則通過 Flink 完成,離線導入依賴 Doris 的 Broker Load 功能。對應的數據導⼊⽅式和應⽤場景如下:

實時/近實時標籤

定義:秒級/小時級更新的動態數據(如點擊、登錄事件)。

數據源:Kafka 日誌、API 埋點、雲文件存儲。

處理方式:

  • 秒級/分鐘級標籤:Flink -> Doris / Hbase。
  • 小時級標籤:雲文件存儲 -> BrokerLoad。

場景:用户行為分析,用户實時人羣。

離線標籤

定義:T+1 更新的歷史數據(如年齡、歷史訂單)。

數據源:Hive。

處理方式:

  • 數據量:3000+ 標籤,4 億+用户總量。
  • 定時調度:BrokerLoad。
  • 調優手段:寬表導入拆分多表和多個 BrokerLoad 任務。數據量少的稀疏標籤使用高表導入。
  • 導入效率:200+ 標籤寬表 4 億行+導入 30min 以內,高表標籤導入 5min 以內。

場景:用户人羣圈選、用户畫像分析。

數據導入.png

特別值得注意的是,大規模數據導入時,建議拆分多個表並行導入以提升效率,例如在早期 1.2.4 版本集羣測試中,單個包含 200 餘標籤、四億行記錄的寬表導入耗時超過 1.5 小時,而拆分為 6 個任務並行導入後,總耗時縮短至約 20 分鐘,效率提升近 5 倍

貨拉拉畫像工程查詢優化實踐

01 DSL 與 SQL 優化

首先是離線人羣包圈選的流程,主要分為三步:【運營通過平台進行多規則拼接,前端完成 DSL 構建】-【DSL 經過服務後端優化】-【最終將業務規則自動轉化為高效 SQL】。DSL 優化的目的是提前排除冗餘計算,從而將優化後的 DSL 直接翻譯為高效易用的 SQL。

  1. 為什麼需要優化?當前異構查詢 SQL 痛點:

    1. 部分標籤在業務邏輯上可以合併 ,引擎側沒有覆蓋識別;
    2. 多層聚合導致冗餘掃描:複雜嵌套的場景下,嵌套的 UNION ALLBITMAP_INTERSECT 導致執行計劃層級膨脹,導致冗餘的掃描。
    3. 穩定性:高峯期人羣計算時,內存佔用高、網絡傳輸量大,高內存開銷影響集羣穩定性。
  2. 如何實現優化?DSL 優化:

    1. 條件合併(染色):將同類標記的標籤條件合併為同個子查詢。
    2. 結構扁平化(剪枝):去除冗餘的 AND/OR 邏輯節點

將同類合併操作後的 DSL 轉為 SQL,原本查詢 3 次寬表讀取了 3 個 BITMAP 進行合併計算,優化後統一成 1 次寬表查詢和 1 次 BITMAP 讀取,減少了60% 的冗餘讀取。參考下圖,DSL 的每一個圓圈對應一個 BITMAP 查詢:

DSL 與 SQL 優化.png

關於 EXPLAIN 指標優化前後的具體表現,我們在此也分享一則參考示例,詳情如下:

-- 優化前
SELECT BITMAP_INTERSECT(b) AS result 
FROM (
    SELECT BITMAP_INTERSECT(b) AS b 
    FROM (
        SELECT user_bitmap as b FROM user_bitmap WHERE group = ‘A’
        UNION ALL 
        SELECT TO_BITMAP(id) AS b FROM wide_table WHERE city = '東莞'
        UNION ALL
        SELECT TO_BITMAP(id) AS b FROM wide_table WHERE sex = '男'
    ) t1 ) t2;
 
-- 優化後
SELECT BITMAP_INTERSECT(b) AS result 
FROM (    SELECT user_bitmap as b FROM user_bitmap WHERE group = ‘A’    UNION ALL 
    SELECT TO_BITMAP(id) AS b FROM wide_table WHERE city = '東莞' and sex = ‘男’
) t1 ) t2;

DSL 與 SQL 優化-1.png

在業務圈選邏輯不變的情況下,通過將優化前 BITMAP 子查詢合併到 WHERE 條件中以避免重複掃描表,同時減少 BITMAP 子查詢及數據分片合併次數,進而減少聚合層級實現結構扁平化,降低人羣計算時的內存峯值。

在業務高峯期針對大規模人羣展開計算的場景下,此優化措施能夠有效減少 30~50% 的內存開銷。與此同時,JVM 的堆內存使用峯值從原本的 60% 降至 20% 。

02 人羣位圖表讀取優化

人羣位圖表讀取優化.png

人羣位圖結果集通過 BITMAP 存儲於人羣表中,讀取人羣位圖數據主要用於人羣圈選、人羣分析,並將整個結果集推送至下游。

人羣位圖表讀取優化實踐.png

讀取位圖數據的方案有三種:

  • 第一種方案,直接使用 Doris 自帶的 bitmap_to_string 函數,該函數可將位圖轉化為逗號分隔的字符串,客户端按此字符串解析出用户列表。但是當面對大型位圖時,解析難度較大,且數據體積會大幅膨脹。優點是簡單易用,適合測試和導出場景。
  • 第二種方案,採用 explorelateral view先將整個位圖展開,再構建服務端流處理邏輯。不過,Doris 需將位圖展開成用户列表並緩存於服務器,這會給服務端帶來壓力,尤其在高峯期,人羣計算任務繁重時更為明顯。此外,畫像工程側需維護流處理邏輯,開發維護成本較高。該方案適合人羣多表的關聯分析。
  • 第三種方案,也是較為推薦的方案,直接將位圖的二進制數據讀取至服務端內存,再進行反序列化。服務端設置 return_object_data_as_binary=true ,即可直接讀取位圖的二進制數據,畫像服務端可基於 Doris 源碼中的位圖協議進行反序列化。此方式僅需傳輸位圖的原始二進制數據,內存佔用和開銷較低。開發成本初期較高,但後期維護方便且穩定。此讀取方式適用於人羣圈選場景,將位圖全量讀取至服務內存後,高峯期每分鐘可輕鬆處理幾十甚至上百個人羣。

總結與規劃

貨拉拉自引入 Apache Doris 構建用户畫像系統以來,收益十分顯著:業務查詢效率提升近 30 倍,數據導入速度是 Impala+KUDU 的 3 倍,內存開銷降低 30%-50%,系統穩定性大幅提升,滿足了畫像場景數千個標籤的精細化運營需求,同時通過可視化標籤篩選,降低業務分析的操作門檻

後續,貨拉拉將重點投入以下兩個方面:

  • 接入畫像實時業務:當前貨拉拉畫像服務的實時標籤/人羣點查主要使用 Hbase 和 Redis,基於穩定性和遷移升級成本的考慮,Doris 主要承擔人羣圈選、人羣洞察、行為分析等作業。未來規劃使用 Doris 高版本的架構,承擔大部分高併發的實時點查流量,提升人貨匹配效率和體驗。
  • 引入湖倉一體架構:使用 Doris + 數據湖,在存儲架構方面,嘗試落地數據湖解決方案,畫像平台將打通其他數據應用平台、實現超大規模數據的分析。
user avatar haoqingwanqiandehongcha 頭像 u_14522592 頭像 zhuxianzhong 頭像 u_17397181 頭像 u_16213603 頭像 u_12187 頭像
6 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.