什麼年代了!你還在寫 ETL 代碼抽取特徵?

from here

TL;DR: 這篇文章介紹了美團點評實現的一個特徵抽取框架。使用這個框架開發人員只需要加幾個配置文件,就可以把事務事實表中的原始數據加工成線上可以直接使用的特徵數據,而不是寫 ETL 代碼。

因為大部分的特徵都可以歸結為:在某幾個維度上的,對一些對象,針對某些度量,進行某類統計:

  1. 對象:統計對象類似關係資料庫中的實體,例如由 uuid 唯一標識的用戶

  2. 維度:是進行統計時所需要關注得變數,例如用戶的年齡、使用平台等

  3. 度量:有物理意義的量化值,例如曝光次數、點擊次數等

  4. 統計:針對度量值進一步的加工處理結果,例如求一個分布/佔比,或者就是簡單地累加一下(在美團點評的業務場景中,一共只有六種計算模式,具體還請看原文)

這個框架會把上面這個配置文件轉化為等價的 Spark 代碼,(不考慮時間衰減的部分)其等價的 SQL 為:

SELECT uuid, // 統計對象,每一個用戶 tag, // 計算維度:品類 rate(order) AS tag_click_rate // 用戶下單品類偏好 rate(click) AS tag_click_rate // 用戶點擊品類偏好FROM usersGROUP BY uuid, tag SELECT uuid, // 統計對象,每一個用戶 price, // 計算維度:下單金額 percentile(order) AS price_order_dist // 分位點函數FROM usersGROUP BY uuid, price

如果考慮時間維度的衰減,計算應該分為兩個階段,得到每一天的度量值,然後根據時間進行衰減,之後再進行累加:

SELECT uuid, price, percentile(sum(decay_value)) // 對加權以後的度量值再進行統計計算FROM (SELECT uuid, // 統計對象,每一個用戶 price, // 統計維度:下單金額 dt, // 時間維度 order * log(factor) * (dt - end) AS decay_value FROM users GROUP BY uuid, dt, price) tGROUP BY uuid, price

每一次計算時,所有歷史的值都會參與計算,更老的值會衰減得更嚴重,在加權之後的總和中影響因素更小。這裡也可以考慮只計算最近一段時間的(例如七天)用戶的下單數據,並求平均,不過這種方法有明顯的缺點(引入了閾值)。

數據的同步也是整個框架很重要的一部分:因為數據落地在 HDFS 中,線上的應用無法直接(隨機)訪問,因此需要把特徵推送到線上的 KV 存儲中。同步方式就是應該就是起一個 MapReduce 任務把數據全量 Scan 出來,然後在 mapper 中迭代寫入 KV 中。而維度數據其實是一個 Map<K, Map<K, V>> 結構,在存儲到 KV 時其實是一個複雜數據類型,這部分的邏輯要麼藉助於 KV 系統本身的類型系統 (如 Cassandra),要麼就自己在 MapReduce 的代碼中實現。

美團點評的實現依賴一個 ORM POJO 庫,把 Hive 中的數據類型映射為 Java 的基本類型,甚至是 POJO,並序列化為某種通用格式(Protobuf/JSON)寫到 KV 中。這個庫嚴格來講算是這個 KV 服務的客戶端,只是在 MapReduce 中引入。每當需要抽取一個新的特徵時,就需要實現這個 Domain 類,並實現它的 key() 介面,在實際寫入 KV 時真正的 key 則是這個 Domian 類的類名再拼上 key() 返回的結果。這種方法的好處是,Domain 類只需要被實現並維護一次,而 MapReduce 任務本身則是通用的。

最後配置文件的 Parser 也沒有必要自己開發,美團點評用的是 TOML 這個開源語言。
推薦閱讀:

工程師要不要寫ETL?——教你構建高效的演算法/數據科學部門
kettle插件架構
衛星ETL技術的發展?
kettle 8 新變化

TAG:特徵工程 | ETL | MapReduce |