2023-08-16 16:22:14來源:字節(jié)跳動技術(shù)團(tuán)隊
由于流量紅利逐漸消退,越來越多的廣告企業(yè)和從業(yè)者開始探索精細(xì)化營銷的新路徑,取代以往的全流量、粗放式的廣告轟炸。精細(xì)化營銷意味著要在數(shù)以億計的人群中優(yōu)選出那些最具潛力的目標(biāo)受眾,這無疑對提供基礎(chǔ)引擎支持的數(shù)據(jù)倉庫能力,提出了極大的技術(shù)挑戰(zhàn)。
背景人群圈選分析是客戶畫像平臺(CDP)中的核心功能。分析師利用各種標(biāo)簽組合,挑選出最合適的人群,進(jìn)而進(jìn)行廣告推送,達(dá)到精準(zhǔn)投放的效果。同時由于人群查詢在不同標(biāo)簽組合下的結(jié)果集大小不同,在一次廣告投放中,分析師需要經(jīng)過多次的邏輯調(diào)整,以獲得"最好"的人群包。在這種高頻的操作下,畫像平臺通常會遇到兩方面的問題:
第一,由于此類查詢分析是臨時性的,各種標(biāo)簽組合數(shù)巨大,離線預(yù)計算無法滿足此類靈活性。第二,由于此類查詢是實時場景,查詢性能變得非常關(guān)鍵, 通常一次查詢在分鐘級,耗時較長,無法滿足分析師需求。這篇文章中,我們將會分享人群圈選查詢在實時分析OLAP場景下的解決思路,同時介紹如何利用ByteHouse來加速此類查詢。從數(shù)據(jù)表現(xiàn)上看,在10億級用戶測試數(shù)據(jù)下,ByteHouse的人群查詢P99小于10s,展現(xiàn)了優(yōu)異的性能。
(資料圖)
一個支持人群圈選的數(shù)據(jù)架構(gòu)大致如下:
圖片
用戶的注冊信息通過用戶流進(jìn)入數(shù)據(jù)湖,同時用戶的行為信息通過事件流進(jìn)入數(shù)據(jù)湖。之后通過標(biāo)簽生產(chǎn)任務(wù),我們?yōu)槊總€用戶打上標(biāo)簽。
由于即時查詢的實時性和靈活性,轉(zhuǎn)化好的數(shù)據(jù)通常會寫入OLAP引擎,例如ByteHouse,以提供靈活且實時的SQL查詢。用戶在分析時,一般會從畫像平臺應(yīng)用界面去可視化構(gòu)建標(biāo)簽邏輯,再由平臺應(yīng)用將這些邏輯轉(zhuǎn)化成SQL,發(fā)給ByteHouse進(jìn)行處理。
從數(shù)據(jù)模型上看, 數(shù)據(jù)倉庫或者數(shù)據(jù)湖里存儲的格式多數(shù)以id-tag為主,例如:
user_id | sex | age | tags |
10001 | F | 20 | [] |
10002 | M | 22 | [tag_1,tag_2] |
10003 | F | 23 | [tag_1] |
10004 | M | 24 | [tag_2] |
10005 | F | 25 | [tag_1,tag_2] |
在人群分析中,以下以tag為主的模式會更合適,例如:
tags | active_users |
tag_1 | [10002,10003,10005] |
tag_2 | [10002,10005] |
數(shù)據(jù)是通常是基于用戶作為主體存儲,這種情況導(dǎo)致用戶數(shù)量非常多,同時存在很多不必要字段。那么當(dāng)用戶通過組合標(biāo)簽(tag) 過濾人群時,幾乎所有的行都需要被掃描, 使得性能開銷隨著標(biāo)簽和用戶的增長越來越大。
當(dāng)數(shù)據(jù)以標(biāo)簽作為主體時,有兩個比較大的改動:
其一,只有跟人群相關(guān)的維度會被保留,其他信息例如sex,age等會被移除。其二,active_users以數(shù)組(array)的形式存放所有的用戶id, 這種操作帶來的一個重要的收益是減少了行數(shù),同時減少了數(shù)據(jù)大小。在這種模型下, 根據(jù)tag組合選取用戶就會變成集合的交并補操作,性能對比第一種模型會有顯著提升。
ByteHouse Bitmap類型第二種存儲模型可以用如下ByteHouse SQL建表:
CREATE TABLE id_tags ( tags String, active_users Array) Engine = CnchMergeTree() order by tags
人群圈選查詢,例如找到同時滿足tag_1和tag_2的人群的數(shù)量,可以用如下SQL完成:
WITH (SELECT active_users as tag_1 FROM id_tags WHERE tags = "tag_1") as tag_1_user,WITH(SELECT active_users as tag_2 FROM id_tags WHERE tags = "tag_2") as tag_2_user,SELECT length(arrayIntersect(tag_1_user, tag_2_user))
雖然該模型可以簡化部分操作,但是每個tag的選取需要有一個子查詢(with 部分)。這種方式對于表的掃描有大量浪費,而且跟標(biāo)簽的數(shù)量線性相關(guān)。
為了解決這個問題,ByteHouse內(nèi)置BitMap類型,可以直接用位(bit)來表示一個tag是否能存在。
沿用以上例子, 在利用BitMap后,建表語句改為:
CREATE TABLE id_tags ( tags String, active_users BitMap64) Engine = CnchMergeTree() order by tags
此處注意,我們只是將active_users的類型由Array改成 BitMap64,其余的部分沒有變動。
對于同樣的“找到同時滿足tag_1和tag_2的人群的數(shù)量”的查詢,用以下查詢:
SELECT bitmapCount("tag_1&tag_2")FROM tag_uids_map
我們用bit代替了原始的數(shù)組,使得該查詢可以被優(yōu)化到在一次表掃描中完成。
基于字節(jié)跳動內(nèi)部線上場景,我們觀測到上述的查詢優(yōu)化在多標(biāo)簽場景下,能有10~50倍的性能提升。
數(shù)據(jù)導(dǎo)入寫入數(shù)據(jù)進(jìn)入bitmap表跟普通表沒有顯著差異。例如,小批量insert的方式可以用如下方式:
INSERT INTO TABLE id_tags values ("tag_1", [2,4,6]),("tag_2", [1,3,5])
因為id_tags中active_users定義為BitMap64的類型, 數(shù)組值[1,3,5], [2,4,6]會被自動轉(zhuǎn)化為BitMap64。之后的計算和存儲都會是BitMap64類型。
大批量文件導(dǎo)入時,我們可以利用ByteHouse提供的導(dǎo)入服務(wù),目前離線(TOS, LASFS)以及實時(Kafka)等導(dǎo)入模式均已支持BitMap數(shù)據(jù)導(dǎo)入。流式寫入(如Flink直寫)可以通過JDBC接口用insert的方式寫入。
相關(guān)函數(shù)ByteHouse除了支持BitMap類型的數(shù)據(jù)進(jìn)行交并補操作,也內(nèi)置了大量的列函數(shù),例如bitmapColumnAnd
用來接收一個bitmap列,對該列所有bitmap做and
運算;以及bitmapColumnCardinality
用來返回一個列中所有bitmap的元素個數(shù)。詳情可以參考官方文檔。
假設(shè)一個用戶ID用32位unsigned integer表示, 那么使用常規(guī)bit存儲的方式需要2^32 bits ~ 512MB 的空間。如果需要為每個標(biāo)簽對應(yīng)512MB空間,在標(biāo)簽量增長時,存儲量會變得巨大。實際上,很少有業(yè)務(wù)會遇到2^32 大約40億用戶,因此實際場景中用戶ID的分布是很稀疏的。
我們可以基于這個特性,利用Roaring bitmap來進(jìn)一步壓縮這個空間。如下圖所示:
圖片
在32位的Roaring bitmap中,前16位用于分桶,該取值范圍內(nèi)沒有數(shù)據(jù)則bucket不會被創(chuàng)建,后16位存在對應(yīng)的container中。Container有兩種類型:
Array container: 數(shù)據(jù)量較少的時候(一般少于8K容量),更省空間Bitmap container 適合存儲稠密數(shù)據(jù)、占用空間小在計算的時候只要對某些bucket中的值進(jìn)行計算即可。擴(kuò)展到64位的roaringbitmap的時候,我們可以通過一個map
在大部分場景中,以上的roaring bitmap已經(jīng)有很好的性能。但是在字節(jié)的實際場景中,我們發(fā)現(xiàn)由于user_id 不是連續(xù)生成的,array container的數(shù)量占比會很高。對兩個稀疏人群的交并補操作就變成了對兩個有序數(shù)組的計算,這種計算對比單純的位計算,在性能上還是有明顯的差異。
因此在ByteHouse中,我們通過字典方式,對數(shù)據(jù)進(jìn)行編碼,讓數(shù)據(jù)更加集中。
開啟字典優(yōu)化的方式如下:
CREATE TABLE id_tags ( tags String, active_users BitMap64 BitEngineEncode) Engine = CnchMergeTree() order by tags
本質(zhì)上字典服務(wù)是個onto映射, 可以通過key 查找value, 也可以通過value反查key, 其中key原始值,value時編碼值。開啟編碼之后,ByteHouse會依賴一個字典文件。在默認(rèn)情況下,ByteHouse會在內(nèi)部維護(hù)一個字典文件。
當(dāng)?shù)妆砀聲r,內(nèi)部字典文件也會隨之異步更新。ByteHouse同時也支持用戶維護(hù)外部字典,這里不做展開。
總結(jié)人群分析是畫像平臺的基礎(chǔ)功能,本文介紹了如何利用ByteHouse內(nèi)置的BitMap類型來支持實時的畫像查詢分析。目前ByteHouse云數(shù)倉以及企業(yè)版均已登陸火山引擎。未來,火山引擎將通過 ByteHouse 來為客戶持續(xù)提供字節(jié)跳動和外部最佳實踐,構(gòu)建交互式大數(shù)據(jù)分析平臺,以應(yīng)對復(fù)雜多變的業(yè)務(wù)需求和高速增長的數(shù)據(jù)場景。
關(guān)鍵詞:
由于流量紅利逐漸消退,越來越多的廣告企業(yè)和從業(yè)者開始探索精細(xì)化營銷
如果聯(lián)合國糧食及農(nóng)業(yè)組織的預(yù)測正確,到2050年,地球上將有97億人口。
近日,OpenAI宣稱已經(jīng)開發(fā)出一種使用其最新的生成式人工智能模型GPT-4
作者|蔡正鋒軟件開發(fā)中,為你的軟件系統(tǒng)編寫文檔并不是一件新鮮的事情
司南導(dǎo)航上市募7 8億首日漲27 6%4年現(xiàn)金流有2年負(fù)
人民網(wǎng)北京8月16日電(記者孫博洋)記者從市場監(jiān)管總局獲悉,近日,市場
人類審核員恐將迎來大面積失業(yè)?在GPT-4公開的四個月后,OpenAI開發(fā)了
本來已經(jīng)快被各權(quán)威機(jī)構(gòu)下場錘得奄奄一息的LK-99,最近獲得了一位支持
嵌入式用戶身份模塊(eSIM)技術(shù)于十多年前推出。盡管它并沒有像許多人預(yù)
一、介紹1、分布式系統(tǒng)中的數(shù)據(jù)同步定義數(shù)據(jù)同步猶如合唱團(tuán)里的B角歌手
物聯(lián)網(wǎng)傳感器、云計算和人工智能等新技術(shù)可以降低成本、提高生產(chǎn)力并改
以ChatGPT為代表的大模型,正在深刻地改變乃至重塑各行各業(yè),越來越多
2023年的金融科技行業(yè)正在見證變革性的人工智能趨勢。機(jī)器學(xué)習(xí)、機(jī)器人
AI大模型之風(fēng),吹到電信行業(yè)了。據(jù)報道,美國AI初創(chuàng)公司Anthropic與韓
說到IT項目,DaraghMahon喜歡從小處著眼。作為運輸和物流公司W(wǎng)ernerEnt