小程序是如何設計百億級用戶畫像分析系統的?

 We 分析是微信小程序官方推出的、面向小程序服務商的數據分析平臺,其中畫像洞察是一個非常重要的功能模塊。微信開發工程師鍾文波將描述 We 分析畫像系統各模塊是如何設計,在介紹基礎標籤模塊之後,重點講解用戶分羣模塊設計。希望相關的技術實現思路,能夠對你有所啓發。

目錄

1 背景介紹

   1.1 畫像系統簡述

   1.2 畫像系統設計目標

2 畫像系統整體概述

3 基礎標籤模塊

   3.1 功能描述

   3.2 技術實現

4 用戶分羣模塊

   4.1 功能描述

   4.2 人羣包實時預估

   4.3 人羣創建

   4.4 人羣跟蹤應用

5 總結

01 背景介紹

   1.1 畫像系統簡述

We 分析是小程序官方推出的、面向小程序服務商的數據分析平臺,其中畫像洞察是一個重要的功能模塊。該功能將爲使用者提供基礎的畫像標籤分析能力,提供自定義的用戶分羣功能,從而滿足更多個性化的分析需求及支撐更多的畫像應用場景。

在此之前,原有 MP 的畫像分析僅有基礎畫像,相當於只能分析小程序大盤固定週期的基礎屬性,而無法針對特定人羣或自定義人羣進行分析及應用。平臺頭部的使用者均希望平臺提供完善的畫像分析能力。除最基礎的畫像屬性之外,也爲使用者提供更豐富的標籤及更靈活的用戶分羣應用能力。因此, We 分析在相關能力上計劃進行優化。

   1.2 畫像系統設計目標

整體來看,平臺支持靈活的標籤及人羣創建方式,使用者按照自己的想法任意圈選出想要的人羣,按不同週期手動或自動選出人羣包。此外也支持人羣的跟蹤分析,人羣在多場景的應用等。

02 畫像系統整體概述

系統從產品形態的角度出發,在下文分成 2 個模塊進行闡述——分別是基礎標籤模塊及用戶分羣模塊

03 基礎標籤模塊

   3.1 功能描述

該模塊主要滿足使用者對畫像的基礎分析需求,預期能滿足絕大部分中長尾使用者對畫像的使用深度要求。主要提供的是針對小程序大盤的基礎標籤分析,及針對特定人羣(如活躍:1 天活躍、7 天活躍、30 天活躍、180 天活躍)的特定標籤分析。如下所示:

   3.2 技術實現

   3.2.1 數據計算

從上述功能的描述,可以看出功能的特點是官方定義數據範圍可控,支持的是針對特定人羣的特定標籤分析。

針對特定人羣的特定標籤分析數據是用離線 T + 1 的 hive 任務進行計算。流程如下。

分別計算官方特定標籤的統計數據、特定人羣的統計數據,以及計算特定人羣交叉特定標籤的數據。

   3.2.2 數據存儲

不同存儲對比存在差異。在上述分析之後,需要存儲的是預計算好的結果數據。此外,業務的特點是按照小程序進行多個數據主題統計的存儲,所以第一直覺是適合用分佈式 OLTP 存儲。團隊也對比了不同的數據庫,在選型過程中,主要考慮對比的點包括數據的寫入、讀取性能。

從上圖和 Datacube / FeatureKV / HBase 的對比可以發現 TDSQL 更符合此業務訴求、更具備優勢。

因此 We 分析平臺基本所有的預計算結果數據,最終選用 TDSQL 來存儲離線預計算結果數據,關於 TDSQL 的幾個關鍵點如下:

當前整個平臺的預計算數據出庫到 TDSQL 的數據達到十億級別,數據表超百張,實際使用存儲上百 T 。TDSQL 整體功能較爲全面,開發者僅需要補充開發數據生命週期管理工具,刪除方式的注意點跟 MySQL 一樣。

如果採用 KV 類型的引擎進行存儲,需要根據 KV 的特性合理設計存儲 Key 。在查詢端對 Key 進行拼接組裝,發送 BatchGet 請求進行查詢。整個過程開發邏輯會相對繁複些, 需要更加註重 Key 的設計。若要實現一個只有概要數據的趨勢圖,那麼存儲的 Key 需要設計成類似格式:{日期} # {小程序} # {指標類型} 。

04 用戶分羣模塊

   4.1 功能描述

該模塊主要提供自定義的用戶分羣能力。 用戶分羣依據用戶的屬性及行爲特徵將用戶羣體進行分類,以便使用者對其進行觀察分析及應用。自定義的用戶分羣能夠滿足中頭部客戶的個性化分析運營需求,例如客戶想看上次 618 參加了某活動的用戶人羣,在接下來的活躍交易趨勢跟大盤的差異對比;或者客戶想驗證對比某些人羣對優惠券的敏感程度、圈選人羣后通過 AB 實驗進行驗證。上述類似的應用會非常多。

在功能設計上,平臺需要做到數據豐富、規則靈活、查詢快速,需要支持豐富的人羣圈選數據,並且預置標籤、人羣標籤、平臺行爲、自定義上報行爲等。支持靈活的標籤及人羣創建方式,讓客戶能按照自己的想法任意圈選出想要的人羣,按不同週期手動或自動選出人羣包,支持人羣的跟蹤分析、人羣在多場景的應用能力。

   4.2 人羣包實時預估

人羣包實時預估是根據使用者客戶定義的規則,計算出當前規則下有多少用戶命中了該規則。產品交互通常如下所示:

   4.2.1 數據加工

爲了滿足客戶能隨意根據自己的想法圈出想要的人羣,平臺支持豐富的數據源。整體畫像的數據量較大,其中預置的標籤畫像在離線 HDFS 上的豎表存儲達近萬億 / 天,平臺行爲百億級 / 天,且維度細,自定義上報行爲百億級 / 天。

怎麼設計能節省存儲同時加速查詢是重點考慮的問題之一。大體的思路是:對預置標籤畫像轉成 Bitmap 進行壓縮存儲,對平臺行爲明細進行預聚合及對維度枚舉值進行 ID 自增編碼,字符串轉成數據整型節省存儲空間。同時在產品層面增加啓用按鈕,開通後導入近期數據,從而控制存儲消耗,具體細節如下。

屬性標籤數據通常建設用戶畫像的核心工作就是給用戶打標籤,標籤是人爲規定的高度精煉的特徵標識,如性別、年齡、地域、興趣,也可以是用戶的一些行爲集合。這些標籤集合抽象出一個用戶的信息全貌,每個標籤分別描述該用戶的一個維度,各標籤維度間相互聯繫,構成對用戶的整體描述。當前的用戶屬性及人羣標籤是由平臺方提供,由平臺每天進行統一的加工處理生成官方標籤。平臺暫時沒有支持用戶自定義的標籤,因此這裏主要說明平臺標籤是如何計算加工管理。

例如活躍標籤 10002 ,對標籤的每個標籤值進行編碼如下:

對特定人羣進行編碼,基準人羣是作爲必選的過濾條件,用於限定用戶的範圍:

標籤數據在離線的存儲上,採用豎表的存儲方式。 表結構如下所示,標籤之間可以並行構建相互獨立不影響。採用豎表的結構設計,好處是不需要開發畫像大寬表,即使任務出現異常延時也不會影響到其它標籤的產出。而畫像大寬表需要等待所有畫像標籤均完成後才能開始執行該寬表數據的生成,會導致數據的延時風險增大。當需要新增或刪除標籤時,需要修改表結構。因此,在線的存儲引擎是否支持與離線豎表模式相匹配的存儲結構,成爲很重要的考量點。

採用大寬表方式的存儲如 Elasticsearch 和 Hermes 存儲,等待全部需要線上用到的畫像標籤在離線計算環節加工完成才能開始入庫。而像 ClickHouse 、Doris 則可以採用與豎表相對應的表結構,標籤加工完成就可以馬上出庫到線上集羣,從而減小因爲一個標籤的延時而導致整體延時的風險。

CREATE TABLE table_xxx(
    ds BIGINT COMMENT '數據日期',
    label_name STRING COMMENT '標籤名稱',
    label_id BIGINT COMMENT '標籤id',
    appid STRING COMMENT '小程序appid',
    useruin BIGINT COMMENT 'useruin',
    tag_name STRING COMMENT 'tag名稱',
    tag_id BIGINT COMMENT 'tag id',
    tag_value BIGINT COMMENT 'tag權重值'
)
PARTITION BY LIST( ds )
SUBPARTITION BY LIST( label_name )(
    SUBPARTITION sp_xxx VALUES IN ( 'xxx' ),
    SUBPARTITION sp_xxxx VALUES IN ( 'xxxx' )
)

如果把標籤理解成對用戶的分羣,那麼符合某個標籤的某個取值的所有用戶 ID(UInt 類型) 就構成了一個個的人羣。Bitmap 是用於存儲標籤 - 用戶的映射關係的、非常理想的數據結構,最終需要的是構建出每個標籤的每個取值所對應的 Bitmap。例如性別這個標籤組,背後對應的是男性用戶羣和女性用戶羣。

性別標籤:男 -> 男性用戶人羣包,女 →女性用戶人羣包。

平臺行爲數據是指官方進行上報的行爲數據,例如訪問、分享等行爲數據,使用者不需要進行任何埋點等操作。團隊主要是會對平臺行爲進行預聚合,計算同一維度下的 PV 數據,已減少後續數據的存儲及計算量。

同時會對維度枚舉值進行 ID 自增編碼,目的是減少存儲佔用,寫入以及讀取性能;從效果來看,團隊對可枚舉類型進行字典 ID 編碼對比原本字符類型能節省 60% 的線上存儲空間,同時相同數據量條件下帶來 2 倍查詢速度提升。

自定義上報數據是使用者自己埋點進行數據的上報,上報的內容包括公共參數及自定義內容,其中自定義內容是 key-value 的格式,在 OLAP 引擎中,團隊會將客戶自定義的內容轉成 map 結構類型進行存儲。

   4.2.2 數據寫入存儲

首先講下,在線 OLAP 存儲選型。標籤及行爲明細數據的存儲引擎選型對於畫像系統至關重要,不同的存儲引擎決定了系統不同的設計方式。業務團隊調研瞭解到,行業內建設畫像系統時有多種不同的存儲方案。團隊對常用的畫像 OLAP 引擎做了對比,如下:

綜合上述調研,團隊採用 ClickHouse 作爲畫像數據存儲引擎。在 ClickHouse 中使用 RoaringBitmap 作爲 Bitmap 的解決方案。該方案支持豐富的 Bitmap 操作函數,可以十分靈活方便的判重和進行基數統計操作,如下所示。

採用 RoaringBitmap(RBM) 對稀疏位圖進行壓縮,可以減少內存佔用並提高效率。 該方案的核心思路是,將 32 位無符號整數按照高 16 位分桶,即最多可能有 216=65536 個桶,稱爲 container。存儲數據時,按照數據的高 16 位找到 container (找不到則會新建一個),再將低 16 位放入 container 中。也就是說,一個 RBM 就是很多 container 的集合,具體參考高效壓縮位圖 RoaringBitmap 的原理與應用。

接下來講講,數據導入線上存儲。在確定了採用什麼存儲引擎存儲線上數據後,團隊需要將離線集羣的數據導入到線上存儲。其中對於標籤數據通常的做法是將原始明細的 id 數據直接導入到 ClickHouse 表中,再通過創建物化視圖的方式構建 RBM 結構進行使用。

然而,業務明細數據非常大,每天近萬億。這樣的導入方式給 ClickHouse 集羣帶來了很大資源開銷。而通常業務團隊處理大規模數據都是用 Spark 這樣的離線計算框架來完成處理。最****後團隊把預處理工作全部交給了 Spark 框架,這種方式大大的減少了寫入的數據量,同時也減少了 ClickHosue 集羣的處理壓力。

具體步驟是 Spark 任務首先會按照 id 進行分片處理,然後對每個分片中標籤的每個標籤值生成一個 Bitmap ,保證定製的序列化方式與 ClickHouse 中的 RBM 兼容。其中通過 Spark 處理後的 Bitmap 轉成 string 類型,然後寫入到線上的標籤表中,在表中業務團隊定義了一個物化列字段,用於實際存儲 Bitmap。在寫入過程中會將序列化後的 Bitmap 字符串通過 base64Decode 函數轉成 ClickHouse 中的 AggregateFunction (groupBitmap, UInt32) 數據結構。

具體表結構如下:

CREATE TABLE xxxxx_table_local on CLUSTER xxx
(
    `ds` UInt32,
    `appid` String,
    `label_group_id` UInt64,
          `label_id` UInt64,
          `bucket_num` UInt32,
    `base64rbm` String,
         `rbm` AggregateFunction(groupBitmap, UInt32) MATERIALIZED base64Decode(base64rbm)
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/xxx_table_local', '{replica}')
PARTITION BY toYYYYMMDD(toDateTime(ds))
ORDER BY (appid, label_group_id, label_id)
TTL toDate(ds) + toIntervalDay(5)
SETTINGS index_granularity = 16

值得關注的還有存儲佔用問題。標籤類型數據用 Bitmap 類型存儲,平臺行爲採用編碼方式存儲,存儲佔用大幅減少。

   4.2.3 數據查詢

數據查詢方式:人羣圈選過程中,如何保障大的 APP 查詢、在複雜規則情況下的查詢速度? 團隊在導入過程中對預置畫像、平臺行爲、自定義上報行爲,均按相同分桶規則導入集羣。這保證一個用戶僅會在同一臺機器,查詢時始終進行本地表查詢,避免進行分佈式表查詢。

對於查詢性能的保障,團隊始終保證所有查詢均在本地表完成。上面已經介紹到數據在入庫時,均會按照相同用戶 ID 的 hash 分桶規則出庫到相應的機器節點中。使用維度數字編碼,測試數字編碼後對比字符方式查詢性能有 2 倍以上提升。對標籤對應的人羣轉成 Bitmap 方式處理,用戶的不同規則到最後都會轉成針 Bitmap 的交併差補集操作。

對於平臺行爲,如果在用戶用模糊匹配的情況下,會先查詢維度 ID 映射表,將用戶可見維度轉化成維度編碼 ID,後通過編碼 ID 及規則構建查詢 SQL。整個查詢的核心邏輯是根據圈選規則組合不同查詢語句,然後將不同子查詢通過規則組合器最終判斷該用戶是否命中人羣規則。

基於 rpc 開發服務接口:查詢的服務接口採用 rpc 框架進行開發。

在數據服務的上一層是團隊的數據中間件,統一做了流量控制、異步調用、調用監控及參數安全校驗,特別是針對用戶量較大的 app 在多規則查詢時,耗時較大,因此業務團隊配置了細粒度的流量控制,保障查詢請求的有序及服務的穩定可用。

查詢性能數據:不同 DAU 等級小程序查詢性能。

從性能數據看,對用戶量大的 app 來說,在規則非常多的情況下還是要大幾十秒,等待這麼長時間體驗不佳。因此對於這部分用戶量大的 app,業務團隊採用的策略是抽樣。通過抽樣,速度能得到非常大的提升,並且預估的準確率誤差不大,在可接受的範圍內。

   4.3 人羣創建

   4.3.1 人羣實時創建

人羣包實時創建類似上面描述的人羣大小實時預估,區別是在最後人羣創建是需要將圈選的人羣包用戶明細寫入到存儲中,然後返回人羣包的大小給到用戶。同樣是在本地表執行,生成的人羣包寫入到同一臺機器中,保持分桶規則的一致。

   4.3.2 人羣例行化創建

客戶創建的例行化人羣包,需要每天計算。如何持續跟蹤分析趨勢,並且不會對集羣造成過大的計算壓力? 團隊的做法利用離線超大規模計算的能力,在凌晨啓動所有人羣計算任務,從而減小對線上 ClickHouse 集羣的計算壓力。所有小程序客戶創建的例行化人羣包計算集中到凌晨的一個任務中進行,做到讀一次數據,計算完成所有人羣包,最大限度節省計算資源,詳細的設計如下:

首先,團隊會先將全量的數據(標籤屬性數據 + 行爲數據)按照小程序粒度及選擇的時間範圍進行過濾,保留有效的數據;

其次,對數據進行預聚合處理,將用戶在一段時間範圍的行爲數據,標籤屬性鏡像數據按照小程序的用戶粒度進行聚合處理,最終的數據將會是對於每個小程序的一個用戶僅會有一行數據;那麼人羣包計算,實際上就是看這個用戶在某個時間範圍內所產生的行爲、標籤屬性特徵是否滿足客戶定義的人羣包規則;

最後,對數據按用戶粒度聚合後進行復雜的規則匹配,核心是拿到一個用戶某段時間的行爲及人羣標籤屬性,判斷這個用戶滿足了用戶定義的哪幾個人羣包規則,滿足則屬於該人羣包的用戶。

   4.4 人羣跟蹤應用

   4.4.1 人羣跟蹤分析

在按照用戶規則圈選出人羣后,統一對人羣進行常用指標(如活躍、交易等指標)的跟蹤。整個過程用離線任務進行處理,會從在線存儲中導出實時生成的人羣包,以及離線批量生成的定時人羣包,彙總一起,後關聯對應指標表,輸出到線上 OLTP 存儲進行在線的查詢分析。其中,導出在線人羣包會在凌晨空閒時間進行,通過將人羣 RBM 轉成用戶明細 ID。

具體方法爲:arrayJoin(bitmapToArray(groupBitmapMergeState(rbm)))。

   4.4.2 人羣基礎分析

人羣基礎分析對一個自定義的用戶分羣進行基礎標籤的分析,如該人羣的省份、城市、交易等標籤分佈。人羣行爲分析,分析該人羣不同的事件行爲等。

   4.4.3 實驗人羣定向

在 AB 實驗中的人羣實驗,使用者通過規則圈選出指定人羣作爲實驗組(如想驗證某地區的符合某條件的人羣是否更喜歡參與該活動),跟對照組做相應指標的對比,以便驗證假設。

05 總結

本篇回顧了 We 畫像分析系統各模塊的設計思路。在基礎模塊中,業務團隊根據功能特性,選用了騰訊雲 TDSQL 作爲在線數據的存儲引擎,將所有預計算數據都使用 TDSQL 進行存儲。在人羣分析模塊中,爲了實現靈活的人羣創建、分析及應用,業務團隊使用 ClickHouse 作爲畫像數據的存儲引擎,根據該存儲的特性進行上層服務的開發,以達到最優的性能。

後續,小程序 We 畫像分析系統在產品能力上會持續豐富功能及體驗,同時擴展更多的應用場景。以上是 We 畫像分析系統模塊設計與實現思路的全部內容,歡迎感興趣的讀者在評論區交流。

原創作者|鍾文波

技術責編|鍾文波、謝慧志

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/9HPciYWiqsdxEv4-55urWQ