用戶畫像系統(tǒng)中遇到的比較難的問題是什么?問題一: 我們?cè)谶x擇如何存儲(chǔ)用戶標(biāo)簽時(shí),遇到了問題(標(biāo)簽查詢速度慢,并且構(gòu)建不夠靈活,標(biāo)簽更新和刪除比較麻煩),比如之前用HDFS或者ES存儲(chǔ),后來切換為ClikcHouse,并用BitMap存儲(chǔ)。
原因如下:
針對(duì)標(biāo)簽的表示形式,存儲(chǔ)方式有很多,結(jié)構(gòu)為`寬表,BitMap` 都可以,存儲(chǔ)選擇`HDFS,ES,ClickHouse 等` 也都可以,需要衡量的有兩點(diǎn)`1.標(biāo)簽構(gòu)建的靈活性和構(gòu)建速度 2.標(biāo)簽的查詢效率 `
`HDFS [Presot,Impala]:` 標(biāo)簽的增加,刪除,更新不友好, 一個(gè)小變動(dòng),要重寫整個(gè)`Parquet`, 寫放大問題。 查詢效率還可以,但是不夠優(yōu)秀。 支持查詢并發(fā)較小。
`ES:`標(biāo)簽的構(gòu)建的寫入速度一般, 新增和修改標(biāo)簽需要對(duì)ES文檔結(jié)構(gòu)更新,ES的DSL語法不友好,有一定學(xué)習(xí)成本。查詢效率還算優(yōu)秀,同時(shí)支持高并發(fā)。 ES資源占用高,需要較好的硬件配置。
`ClickHouse[BitMap]` 標(biāo)簽可以并行構(gòu)建,查詢效率優(yōu)秀,標(biāo)簽的增加非常方便,標(biāo)簽的更新和刪除可以實(shí)現(xiàn),但是并不高效,并發(fā)查詢支持比Presto,Impala要好,但同樣不支持高并發(fā),能夠滿足大部分場(chǎng)景需求。注意兩點(diǎn)`1. BitMap存儲(chǔ)的是用戶ID 2. BitMap使用了RoaringBitMap, 解決BitMap空間占用問題,不然1億這一個(gè)數(shù)也要占用11.9M空間`
用戶畫像系統(tǒng)中遇到的比較難的問題是什么?問題二:如何構(gòu)建用戶的稠密向量的問題
如果我們直接將用戶的標(biāo)簽轉(zhuǎn)換為稀疏向量來存儲(chǔ),對(duì)于類別標(biāo)簽使用`one-hot`編碼,但這樣會(huì)出現(xiàn)維度爆炸的問題,向量過于稀疏,向量之間的余弦相似度計(jì)算結(jié)果基本沒有意義,根本無法實(shí)現(xiàn)用戶相似度的計(jì)算。所以就開始思考如何將用戶表示為轉(zhuǎn)換為稠密向量,經(jīng)過調(diào)研發(fā)現(xiàn),Word2Vec可以將詞轉(zhuǎn)換為稠密向量,同時(shí)借助Word2Vec思想,也可以將物品轉(zhuǎn)換為向量Item2Vec,比如將一個(gè)Session內(nèi),用戶購買的物品或者點(diǎn)擊的物品列表,看成是一句話,每個(gè)物品看成是一個(gè)單詞,就可以借助Word2Vec的思想將物品轉(zhuǎn)換為稠密向量表示。(這里注意如果是文章,可以使用分詞,然后抽取關(guān)鍵詞,將詞通過Word2Vec轉(zhuǎn)換為向量的方式) ,我們?cè)賹⒂脩酎c(diǎn)擊或者購買的物品列表中物品向量加和求平均,就可以得到用戶的稠密向量。后來發(fā)現(xiàn)通過ALS模型`矩陣分解`的方式也可以得到用戶的稠密向量,兩者`表達(dá)的用戶向量含義`是不同的,一個(gè)是有濃重的物品屬性特征的,一個(gè)是有協(xié)同特征的向量。但是都可以作為用戶的向量表示方式。
HBase得二級(jí)索引的設(shè)計(jì)(或者Phoenix 二級(jí)索引-說說原理)
HBase二級(jí)索引的設(shè)計(jì)方案一般有如下幾種
1. 協(xié)處理器coprocessor方案。 原理就是自定義協(xié)處理器,實(shí)現(xiàn)`雙寫`,就是寫主表的時(shí)候,同時(shí)寫索引表[這里這個(gè)索引表是根據(jù)業(yè)務(wù)對(duì)查詢的需求建立的]。 比如我們要查詢的主表是A, 里面有RowKey,還有一列ColumnA. 如果想對(duì)ColumnA這一列建立索引,就自定義一個(gè)協(xié)處理器(觀察者模式),當(dāng)我們寫入A表中一條數(shù)據(jù),比如 行鍵rowkey(123),cloumnA列值:abc,這時(shí)協(xié)處理在索引表(自己建立,比如A_INDEX)中插入一條記錄 行鍵為剛才列A的值abc,列值為主表的rowkey(123). 查詢的時(shí)候,先查索引表得到rowkey,然后根據(jù)rowkey在主表中查。
2. ES 方案,將想要構(gòu)建的二級(jí)索引的字段值存儲(chǔ)到ES中,查詢時(shí)先去ES根據(jù)條件查到rowkey,然后根據(jù)rowkey再去hbase查數(shù)據(jù)。
3. Phoenix 方案。 Phoenix構(gòu)建構(gòu)建索引的方式,本質(zhì)也在HBase中建立索引表。只不建表的過程,索引維護(hù)的過程,Phoenix自己內(nèi)部實(shí)現(xiàn),暴露給用戶的只是SQL接口。
# 其實(shí)在HBase構(gòu)建二級(jí)索引,萬變不離其宗,最終的方向都是構(gòu)建索引字段與行鍵的映射關(guān)系,先更加索引表查行鍵,在根據(jù)行鍵,查最終數(shù)據(jù)。
怎么提高Flink的執(zhí)行性能(代碼方面)
• 通用的優(yōu)化方式
1. 盡早fliter掉一些不需要的數(shù)據(jù)以及避免一些不必要的序列化。
2. 避免使用深層嵌套數(shù)據(jù)類型。
3. 對(duì)于數(shù)據(jù)傾斜使用調(diào)整并行度或者雙層聚合的方式。
4. 一些基數(shù)較少的并且本身較長維度可以采用數(shù)據(jù)字典的方式減少網(wǎng)絡(luò)傳輸及內(nèi)存占用、gc開銷。
• 數(shù)據(jù)類型和序列化
Flink支持java、scala基本數(shù)據(jù)類型,以及java Tuples、scala Case Class、Flink Value,對(duì)于這些數(shù)據(jù)類型,flink會(huì)采用自身的序列化反序列化器去做序列化操作,對(duì)于其他數(shù)據(jù)類型,flink會(huì)采用kyro方式序列化,kyro序列化方式效率會(huì)比flink自帶的方式低很多。因此在數(shù)據(jù)序列化方面我們可以做如下工作
1. 嘗試使用transient修飾不需要序列化的變量,或者修飾你可以在下游通過其他方式獲取到變量,這個(gè)可以減少序列化流程和網(wǎng)絡(luò)傳輸(但可能帶來更多的內(nèi)存占用用和gc消耗)
2. 對(duì)于一些特殊的數(shù)據(jù)你可以嘗試重寫writeObject() 和 readObject() 來自己控制一些序列化方式,如果更高效的話
3. 如果使用了lambda或者泛型的話,顯式的指定類型信息讓flink類型提取系統(tǒng)識(shí)別到以提升性能。
• 多組相同keyby可使用DataStreamUtils
在多組keyby的場(chǎng)景可以采用DataStreamUtils.reinterpretAsKeyedStream的方式避免多次shuffle操作
• 盡量減少狀態(tài)的大小
1. 設(shè)置合適的state TTL, 清洗過期狀態(tài),避免狀態(tài)無限增大。
2. 減少狀態(tài)字段數(shù), 比如使用aggreteFunction 做窗口聚合時(shí),可以只將要聚合的信息放入狀態(tài),其他keyBy字段以及窗口信息,可以通過processWindowFunction的方式獲取,這樣就是 aggregateFunction + ProcessWindowFunction,agg函數(shù)獲取聚合信息,輸出的結(jié)果到processwindowFunction中取獲取窗口信息。
3. checkpoint頻率不宜過高,超時(shí)時(shí)間不要太長,可以異步化的地方盡量異步化
更多關(guān)于“大數(shù)據(jù)面試題”的問題,歡迎咨詢千鋒教育在線名師。千鋒已有十余年的培訓(xùn)經(jīng)驗(yàn),課程大綱更科學(xué)更專業(yè),有針對(duì)零基礎(chǔ)的就業(yè)班,有針對(duì)想提升技術(shù)的好程序員班,高品質(zhì)課程助理你實(shí)現(xiàn)java程序員夢(mèng)想。