人人妻人人澡人人爽人人精品av_精品乱码一区内射人妻无码_老司机午夜福利视频_精品成品国色天香摄像头_99精品福利国产在线导航_野花社区在线观看视频_大地资源在线影视播放_东北高大肥胖丰满熟女_金门瓶马车内剧烈运动

首頁>國內(nèi) > 正文

廣告案例|10億數(shù)據(jù)、查詢

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ù)。詳情可以參考官方文檔。

BitEngine原理介紹BitMap結(jié)構(gòu)解析

假設(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來支持,前32位作為map的key,后32位用roaringbitmap存儲。

字典優(yōu)化

在大部分場景中,以上的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)鍵詞:

相關(guān)新聞

Copyright 2015-2020   三好網(wǎng)  版權(quán)所有 聯(lián)系郵箱:435 22 [email protected]  備案號: 京ICP備2022022245號-21