1. 概述

所謂虛擬屬性,是指在數據入庫之後透過 SQL 表達式對已有的事件屬性和用戶屬性進行二次加工,產生一個新的屬性值。

虛擬屬性根據表達式中引用到的屬性型別分為用戶虛擬屬性和事件虛擬屬性,需要注意的是確定了虛擬用戶屬性的型別之後只能引用用戶表內的屬性;虛擬事件屬性支援引用「事件屬性」和「用戶屬性」。

本文件所描述的內容屬於神策分析的高級使用功能,涉及較多技術細節,適用於對相關功能有經驗的用戶參考。如果對文件內容有疑惑,請統一諮詢客戶群內的神策值班同學。

如何使用維度表 >

2. 建立虛擬屬性

進入「元數據」-「虛擬屬性」後點擊「新建」按鈕。選擇此虛擬屬性的分類並完成相關基本資訊的填寫後。在「SQL 表達式」中填寫的 expression 實際上只需要填寫對屬性的加工的 sql 表達式片段即可快速完成一個虛擬屬性的建立,而不需要一個完整的 sql 表達式。注意事項如下:

  1. 建立虛擬屬性時 SQL 表達式最長不能超過 1024 個字元。

  2. events 表中的 time 和 event 屬於特殊欄位,目前支援對 time 欄位二次加工,具體可參考應用場景 5 舉例。不支援對 event 欄位二次加工提取虛擬屬性。

虛擬屬性分為兩種類型,事件虛擬屬性和用戶虛擬屬性,顧名思義。分別含義請見如下說明:

資訊

說明

屬性分類

事件虛擬屬性:指使用現有的 Event 事件表內的屬性進行加工,也可使用 Event 與 用戶表的用戶屬性、Items 表、維度表(在後端透過命令完成關聯配置後)後基於此建立新的事件虛擬屬性。

用戶虛擬屬性:指使用現有的 User 用戶表中的屬性進行二次加工,已完成新的屬性與屬性值的建立。

屬性顯示名

屬性在使用過程中的顯示名稱,100 字元以內。

屬性名

僅可命名為英文,是事件在系統內的唯一標示。

不能以數值、$ 符號開頭,100 字元以內。
注:校驗時,屬性名大小寫不敏感。

數據型別

必填單選:NUMBER、BOOL、STRING、DATETIME

字典

如果此屬性使用了字典,編輯時修改虛擬屬性的 SQL 規則,則需要對該虛擬屬性重新上傳維度字典。,需要在虛擬屬性列表上重新上傳所需的字典文件。

SQL 表達式

必填,只需要填寫對屬性的加工的 sql 表達式片段即可,示例可見下文

可用此屬性的事件要求



此設定只在選擇了屬性分類是「事件虛擬屬性」後需要設定。(如果是「用戶虛擬屬性」那麼在分析時將所有的事件均可使用此屬性進行分析。)

涵蓋 SQL 表達式涉及的所有屬性的事件,方可使用此虛擬屬性。

涵蓋至少一個 SQL 表達式中涉及的屬性的事件,方可使用此虛擬屬性。 

3. 以下我們提供了集中常見的使用場景:

3.1. 屬性計算

【舉例 1】

假設埋點的時候埋了兩個屬性:事件屬性(數值型別的屬性)「商品標價 commodity_price」和「成交的最終價格 final_price」,當我們想判斷商品標價與最終價格的差值時我們可以直接建立一個新的虛擬事件屬性「淨收入 Net Income」。此時,我們可以使用「加減乘除運算」

SQL 表達式:events.commodity_price - events.final_price

【舉例 2】

我們需要基於已有屬性,需要對「理財產品的本息總和」進行計算。此時,我們可以使用「冪次函數」

SQL 表達式:events.capital + events.capital * pow(events.rate_of_interest, events.duration) 

3.2. 屬性抽取

【舉例 1】

例如我們現在有一個事件屬性是 $url,希望從 $url 中抽取出 q= 的屬性,作為 search_keyword 來進行分析,那麼我們可以使用以下表達式建立一個新的虛擬事件屬性。

SQL 表達式:parse_url(events.$url, 'QUERY', 'q') 

parse_url: 屬性抽取, 透過指定URL中的特定部分返回截取值. 可指定要截取的值為'PROTOCOL', 'HOST', 'PATH', 'REF', 'AUTHORITY', 'FILE', ‘USERINFO', ‘QUERY'. 正常我們只需要輸入指定的 url 以及需要截取的部分兩個參數, 特殊的當要截取的部分為 ‘QUERY' 時, 我們可以輸入第三個參數指定 QUERY 鍵值對中的 key,獲取指定參數值.

【舉例 2】

例如我們有一個自定義事件屬性 error_info_map(字符串類型),上報內容為 JSON 字符串,示例:

error_info_map: '{\"error\": {\"reason\": \"timeout\", \"code\": 3001}}'

希望從這個 JSON 字符串中解析出 reason 的值,作為屬性來進行分析,那麼我們可以使用以下表達式創建一個新的虛擬屬性:

SQL 表達式:GET_JSON_OBJECT(events.error_info_map, '$.error.reason')

GET_JSON_OBJECT:從 JSON 字符串中按照給定的 JSON 選擇器解析出 JSON 對象中的值,得到的值為字符串類型。

GET_JSON_OBJECT Impala 官方文檔

如果給定的字符串不符合 JSON 格式,或者 JSON 選擇器沒有匹配到值,則會返回 NULL。

JSON 選擇器中支持下列操作符:

  • $:標示根節點
  • .:標示取子節點
  • []:標示數組的曲直下標
  • *:標示數組或子節點的通配符

關於JSON選擇器請參考官方文件

3.3. 屬性合併

假設我們在埋點的時候埋了兩個屬性:item_id 和 item_id_1,但實際上它們是一個含義,希望在使用的時候進行合併,也可以使用虛擬屬性功能來定義。

SQL 表達式:coalesce(events.item_id, events.iten_id_1)

coalesce 是一個標準 SQL 函數,返回所有參數中第一個非 NULL 的值,這樣我們在使用的時候只要使用 new_item_id 來進行分析就可以達到屬性合併的目的。

3.4. 聯合去重

在神策分析中,我們支援對某個屬性進行去重數的計算,但是不直接支援對兩個或者更多的屬性進行去重。如果有這類需求,也可以使用虛擬屬性的方式來實現,即定義一個新的屬性,它的值是需要去重的多個屬性的組合。

例如,我們想計算不同用戶瀏覽不同商品的去重次數(即一個用戶瀏覽同一個商品不重複計數,但是瀏覽不同的商品需要計數),那麼可以定義一個虛擬屬性如下:

SQL 表達式:concat(cast(events.user_id as string), events.product_id)

concat: 聯合去重, 把所有string型別的參數連接成一個string型別。

3.5. 高精度小數

預設情況下,神策分析的 NUMBER 型別只支援小數點之後 3 位,如果需要支援高精度型別,可將屬性已字串型別上報給神策,再建立 NUMBER 型別的高精度小數虛擬屬性。

將需要支援高精度的內容以字串的型別來發送給神策分析,以避免精度丟失。此時我們可以透過虛擬屬性將此字串轉化為一個高精度型別的虛擬屬性。

SQL 表達式:cast(events.big_number as decimal(38,16)) 

注:不允許上傳空字串,否則自定義查詢時無法使用select * ,也無法使用「數據校驗」工具

3.6. 校驗數據

神策支援建立一個 Bool 型別的屬性與正則表達式來校驗某個屬性值的數據質量。表達式示例如下:

SQL 表達式:regexp_like(users.user_name, '[a-zA-Z0-9._ //-//[//](){}]{1,15}')

regexp_like(string source, string pattern[, string options]) : 判斷 source 字串中是否包含以 pattern 為正則表達式的內容

3.7. 時間日期再加工

在用到時間日期函數, 只有 Timestamp 型別可以直接使用 impala 的時間日期函數, 所以如果當 Date/Datetime 型別的屬性作為時間日期函數的參數時, 我們需要先使用 EPOCH_TO_TIMESTAMP 函數將屬性轉換為 Timestamp 型別.

【舉例 1】

需要使用每個事件的發生時間,作為分組項來分析數據,或需要在權限中限制某些角色,只可以授權僅可訪問「近 N 天的數據」時。那麼我們需要基於 event 中的 time 建立一個新的虛擬事件屬性,應用在「分析模型」和「角色-數據權限」中。

SQL 表達式:UNIX_TIMESTAMP(events.time)*1000

【舉例 2】

預設情況下,神策分析支援天、週、月等時間聚合方式,如果想要其它的時間聚合方式,也可以使用虛擬屬性實現。例如,如果想要按照 "週X" 來對數據進行分析,可以從 time 屬性中提取出一個 day_of_week 的屬性:

SQL 表達式:dayofweek(EPOCH_TO_TIMESTAMP(events.register_time))

dayofweek: 函數求得的數值,1 表示星期天,7 表示星期六,2-6 表示星期一至星期五。類似的,也可以用 extract(hour from time) 表達式來提取時間中的小時部分。

【舉例 3】

神策支援使用 users 表中的用戶屬性提取虛擬屬性,比如根據用戶屬性 Birthday ,得到用戶的年齡屬性。建立「虛擬用戶屬性」後,使用此表達式即可。

SQL 表達式:cast (extract(year FROM now()) -extract(year FROM EPOCH_TO_TIMESTAMP(users.Birthday)) as int)

extract: 從 TIMESTAMP 值中截取數值型的時間域,例如年度,月份,日期,小時,分鐘,秒/微秒(year,month,day,hour,minute,second,millisecond), 返回時間域的整數值.

注:不支援使用 user 表中的用戶屬性和維度表、事件表中的事件屬性進行關聯。 

【更多表達式參考】

  • adddate: 在一個 TIMESTAMP 值上加一個給定的天數

    SQL 表達式:adddate(EPOCH_TO_TIMESTAMP(users.birthday), INT/BIGINT days)

  • datediff : 返回兩個時間戳間隔天數

    SQL 表達式:datediff(EPOCH_TO_TIMESTAMP(events.enddata), EPOCH_TO_TIMESTAMP(events.startdate))

3.8. 校驗規則與常見錯誤

  1. 表達式中引用的屬性必須存在且已經上報數據
  2. 涉及到兩個屬性的數值計算時必須保證兩個屬性數據型別相同
  3. 虛擬用戶屬性不能引用事件屬性
  4. number型別的虛擬屬性運算符號兩邊必須是數字運算數字
  5. 有維度字典的虛擬屬性表達式返回值也必須為 bigint, string
  6. 數據型別與返回值必須保持一致
  7. 若建立虛擬屬性後,又上報了相同名字的屬性, 虛擬屬性會失效