1. 引言
在分析廣告日志時,會有這樣的多維分析需求:
- 曝光、點擊用戶分別有多少?
- 標簽能覆蓋多少廣告用戶?
- 各個標簽(標注)類別能覆蓋的曝光、點擊在各個DSP上所覆蓋的用戶數
- ……
廣告數據與標簽數據join之后,存儲orc file的schema如下:
create external table default.ad_tag
(
uid string
,dsp string
,view string
,click string
,tags array<struct<tag:string,label:string,src:string>>
)
partitioned by (day_time date)
stored as orc
location '/<path>/<to>';
用戶可能會有多個標簽,因此采用array<struct>
數據類型來作為用戶的標簽字段。可是,當用Kylin做多維分析時,會出現問題——Kylin只能導入扁平化的Hive表,簡而言之,其不支持Hive的復雜數據類型,如array、struct、map等。為了解決這個問題,我們希望能從這張ad_tag
表中抽象出一張扁平化的邏輯表,並且這張邏輯表的partition能跟ad_tag
表保持同步更新。
2. 視圖
眾所周知,在RDBMS中,視圖(view)可用來抽象出邏輯表,比如,得到CS系所開設的所有課程及相關教師信息:
create view as
select course, teacher, building
from teaches, teacher_table
where teaches.teacher_id = teacher_table.teacher_id
and teaches.dept_name = 'CS'
在有一些數據庫解決方案中提供了物化視圖(materialize view),即物理存儲視圖。同RDBMS一樣,Hive也提供視圖,但視圖不能被物化。在Hive中創建視圖時,只是將該視圖的元信息寫進metastore;只有在執行引用視圖語句時,才會觸發其select子句的執行。雖然Hive不能物化視圖,但提供了其等價解決方案——由一張表生成另外一張表:
create table
as select ...
這種類物化的方式,在創建表時會觸發select子句的執行,存在缺點:對於partition增量更新表,做不到view的partition與之同時更新。所以,對於我們的場景不太適用。
3. inline
如何在創建視圖時,將復雜數據類型平鋪開來呢?Hive內置UDTF做這種平鋪化(flatten)操作,但是UDTF並不能配合select用,而在lateral view子句中使用;比如,explode平鋪array:
select pageid, adid
from pageAds
lateral view explode(adid_list) adTable as adid;
inline平鋪array<struct>
:
select *
from test_bid
lateral view inline(tags) tag_table_1;
4. Partition
數據在增量更新,對應地partition也在變化,創建的視圖也應同步partition的變化;並且,Kylin的增量cube是根據hive表的partition進行refresh的。因此,該視圖應保持與基礎表相同的partition。正好,Hive提供PartitionedView,為view添加partition。完整地創建視圖的命令如下:
create view if not exists ad_tag_view
partitioned on (day_time)
as
select uid, dsp, view, click, tag, label, src, day_time
from ad_tag lateral view inline(tags) tags_table;
經測試,在Kylin中讀取view沒問題,基礎表的增量更新,也會同步地反映到view中。至此,Kylin導入復雜數據類型的Hive表問題已解決。此外,這篇文章《Kylin實踐之使用Hive視圖》介紹幾種不同場景下使用視圖的例子。