1. FormatImporter 概述

FormatImporter 用於將一些常見格式的外部數據匯入到神策分析,目前支援讀取 csv 表格、Nginx Log、mysql 資料庫、oracle 資料庫,以及符合 數據格式 的 json 數據。

下載請點擊此連結,腳本下載後是一個壓縮包,注意執行此腳本需要 python3.4。另外如果需要匯入 mysql、oracle 數據庫中的數據的話需要確保電腦上包含相關用戶端的程式包。

注意:當匯入數據到神策之前,請確認數據中 distinct_id 是登入 id 還是匿名 id。若是登入 id,則需在匯入命令中增加參數 --is_login,詳情請見下面範例場景。

2. 經典使用方法

2.1. 取得數據接收網址

首先從神策分析的主頁中,取得數據接收的 URL 和 Token(Cloud 版)。

如果使用神策分析 Cloud 服务,需取得的設定資訊為:

  • 數據接收網址,建議使用不帶埠號的: http://{$service_name}.datasink.sensorsdata.cn/sa?project={$project_name}&token={$project_token}
  • 數據接收網址,帶埠號的: http://{$service_name}.cloud.sensorsdata.cn:8106/sa?project={$project_name}&token={$project_token}

如果用戶使用單機版私有部署的神策分析,預設的設定資訊為:

數據接收網址: http://{$host_name}:8106/sa?project={$project_name}

(注:神策分析 1.7 及之前的版本,單機版私有部署預設埠號為 8006)

如果用戶使用叢集版私有部署的神策分析,預設的設定資訊为:

數據接收網址: http://{$host_name}:8106/sa?project={$project_name}

其中 {$host_name} 可以是叢集中任意一台電腦。

如果私有部署的過程中修改了 Nginx 的預設設定,或透過 CDN 等連接神策分析,則請諮詢相關人員取得設定資訊。

2.2. 範例場景

假設有一個電商網站,需要採集以下用戶事件:

  • 瀏覽事件,包括瀏覽的商品名稱 ( item_name ) 和商品 id ( item_id)
  • 購買事件,包括購買的商品名稱 ( item_name ) 和商品 id ( item_id)

範例事件如下

用戶事件時間商品id商品名稱
bug29瀏覽2018-05-12 13:01:1113245男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒
bug29購買2018-05-12 13:05:0313245男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒
小武瀏覽2018-05-13 10:20:3223421New Order Technique 2CD豪華版 歐版行貨 全新未拆
菠菜瀏覽2018-05-13 20:42:533442NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型

並採集以下用戶屬性:

* 用戶的性別 ( gender ),男或女
* 用戶是否是會員 ( is_member )
* 用戶的會員積分 ( score )

範例用戶屬性如下

用戶名 性别是否為會員會員積分
bug29131
小武<沒有積分>

2.3. 匯入 csv 格式的數據

2.3.1. 匯入事件

假設有以下 csv 檔案描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.csv )。

user_id,action,time,item_id,item_name,item_cate
bug29,view,2018-05-12 13:01:11,13245,男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒,男裝
bug29,buy,2018-05-12 13:05:03,13245,男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒,男裝
小武,view,2018-05-13 10:20:32,23421,New Order Technique 2CD豪華版 歐版行貨 全新未拆,音像
菠菜,view,2018-05-13 20:42:53,3442,NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型,母嬰
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id,以 time 作為事件發生的時間,以 action 作為事件名稱,只匯入 item_id 和 item_name 作為事件屬性。

注意:若匯入事件名為 $SignUp 事件的 csv 格式的數據,在神策裡不會寫用戶關聯關係,只會作為普通事件寫入事件表。

python3 format_importer.py csv_event \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--timestamp_from 'time' \
--event_from 'action' \
--filename './examples/events.csv' \
--property_list 'item_id,item_name' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/csv_event.conf )。

url: http://localhost:8106/sa
distinct_id_from: user_id
is_login
event_from: action
timestamp_from: time
filename: ./examples/events.csv
property_list: item_id,item_name
debug
CODE

然後執行

python3 format_importer.py csv_event @./conf/csv_event.conf
CODE

2.3.2. 匯入用戶屬性

假設有以下 csv 檔案描述了上面的範例用戶屬性 ( 參考程式碼包 examples/profiles.csv )。

user_id,gender,is_member,score
bug29,男,true,131
小武,女,false,
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id。

python3 format_importer.py csv_profile \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--filename './examples/profiles.csv' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/csv_profile.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
filename: ./examples/profiles.csv
debug
CODE

然後執行

python3 format_importer.py csv_profile @./conf/csv_profile.conf
CODE

2.3.3. 匯入 item 數據

假設有以下 csv 檔案描述了上面的範例用戶事件 ( 參考程式碼包 examples/item.csv )。

item_type,item_id,item_name,item_cate,action
view,13245,男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒,男裝,買買買
buy,13245,男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒,男裝,缺貨
view,23421,New Order Technique 2CD豪華版 歐版行貨 全新未拆,音像,缺貨
view,3442,NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型,母嬰,買買
CODE

將數據匯入 item 表中,--item_type 和 --item_id 指令分別指定 item 數據的 item_type 和 item_id 欄位值

python3 format_importer.py csv_item \
--url 'http://localhost:8106/sa?project=xxx' \
--item_type 'item_type' \
--item_id 'item_id' \
--property_list 'item_name,item_cate,action' \
--filename './examples/item.csv' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/csv_item.conf )。

url: http://localhost:8106/sa?project=xxx
item_type: item_type
item_id: item_id
filename: ./examples/events.csv
debug
CODE

然後執行

python3 format_importer.py csv_item @./conf/csv_item.conf
CODE

2.4.  匯入 nginx log

2.4.1. 匯入事件

假設有以下 nginx log 描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.log )。

123.4.5.6 - [12/May/2018:13:01:11 +0800] "GET /item?id=13245&action=view&cate=%e7%94%b7%e8%a3%85" 200 1127 "Mozilla/5.0 ( Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" "http://fake_web.com/login.html" "男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒" "bug29"
123.4.5.6 - [12/May/2018:13:05:03 +0800] "GET /item?id=13245&action=buy&cate=%e7%94%b7%e8%a3%85" 200 1127 "Mozilla/5.0 ( Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" "http://fake_web.com/login.html" "男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒" "bug29"
123.4.5.7 - [13/May/2018:10:20:32 +0800] "GET /item?id=23421&action=view&cate=%e9%9f%b3%e5%83%8f" 200 1127 "Mozilla/5.0 ( Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "http://www.baidu.com?q=abc" "New Order Technique 2CD豪華版歐版行貨全新未拆" "小武"
123.8.5.7 - [13/May/2018:20:42:53 +0800] "GET /item?id=&action=view&cate=%e6%af%8d%e5%a9%b4" 200 1127 "Mozilla/5.0 ( Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "http://www.baidu.com?q=abc" "NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型" "菠菜"
CODE

對應 nginx 設定的格式如下:

log_format compression '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$title" "$user_id"';
access_log /data/nginx_log/access.log compression;
CODE

將這些數據匯入到本地私有部署的環境,以$user_id 作為用戶的id,以$time_local 作為事件發生的時間,$reqeust 解析後的參數action 對應的值是事件名,只匯入兩個事件屬性: $request 解析後的id 作為item_id,自定義的變量$title 作為item_name。

python3 format_importer.py nginx_event \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--timestamp_from 'time_local' \
--timestamp_format '%d/%b/%Y:%H:%M:%S %z' \
--event_from '__request_param_action' \
--filename './examples/events.log' \
--log_format '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$title" "$user_id"' \
--property_list '__request_param_id,title' \
--property_list_cnames 'item_id,item_name' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/nginx_event.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
event_from: __request_param_action
timestamp_from: time_local
timestamp_format: %d/%b/%Y:%H:%M:%S %z
filename: ./examples/events.log
log_format: $remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$title" "$user_id"
property_list: __request_param_id,title
property_list_cnames: item_id,item_name
debug
CODE

然後執行

python3 format_importer.py nginx_event @./conf/nginx_event.conf
CODE

2.4.2. 匯入用戶屬性

假設有以下 nginx log 描述了上面的範例用戶屬性 ( 參考程式碼包 examples/profiles.log )。

123.4.5.6 - [12/May/2018:13:01:11 +0800] "POST /profile?user=bug29&is_member=true" 200 1127 "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" "http://fake_web.com/login.html" "男" "131"
123.4.5.7 - [13/May/2018:10:20:32 +0800] "POST /profile?user=%e5%b0%8f%e6%ad%a6&is_member=false" 200 1127 "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "http://www.baidu.com?q=abc" "女" ""
CODE

對應 nginx 設定的格式如下:

log_format compression '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$gender" "$score"';
access_log /data/nginx_log/access.log compression;
CODE

將這些數據匯入到本地私有部署的環境,以 $reqeust 解析後的參數 user 作為用戶的 id,匯入三個用戶屬性: 自定義變量 $gender 和 $score ,以及 $reqeust 解析後的參數 is_member。

python3 format_importer.py nginx_profile \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from '__request_param_user' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--filename './examples/profiles.log' \
--log_format '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$gender" "$score"' \
--property_list 'gender,score,__request_param_is_member' \
--property_list_cnames 'gender,score,is_member' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/nginx_profile.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: __request_param_user
is_login
filename: ./examples/profiles.log
log_format: $remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$gender" "$score"
property_list: gender,score,__request_param_is_member
property_list_cnames: gender,score,is_member
debug
CODE

然後執行

python3 format_importer.py nginx_profile @./conf/nginx_profile.conf
CODE

2.4.3. 匯入 item 數據

假設有以下 nginx log 描述了上面的範例用戶屬性 ( 參考程式碼包 examples/item.log )。

123.4.5.6 - [12/May/2018:13:01:11 +0800] "GET /item?id=13245&action=view&cate=%e7%94%b7%e8%a3%85" 200 1127 "Mozilla/5.0 ( Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" "http://fake_web.com/login.html" "男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒" "bug29"
123.4.5.6 - [12/May/2018:13:05:03 +0800] "GET /item?id=13245&action=buy&cate=%e7%94%b7%e8%a3%85" 200 1127 "Mozilla/5.0 ( Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" "http://fake_web.com/login.html" "男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒" "bug29"
123.4.5.7 - [13/May/2018:10:20:32 +0800] "GET /item?id=23421&action=view&cate=%e9%9f%b3%e5%83%8f" 200 1127 "Mozilla/5.0 ( Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "http://www.baidu.com?q=abc" "New Order Technique 2CD豪華版歐版行貨全新未拆" "小武"
123.8.5.7 - [13/May/2018:20:42:53 +0800] "GET /item?id=&action=view&cate=%e6%af%8d%e5%a9%b4" 200 1127 "Mozilla/5.0 ( Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36" "http://www.baidu.com?q=abc" "NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型" "菠菜"
CODE

對應 nginx 設定的格式如下:

log_format compression '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$title" "$user_id"';
access_log /data/nginx_log/access.log compression;
CODE

將這些數據匯入到本地私有部署的環境,以 $reqeust 解析後的參數 user 作為用戶的 id,匯入三個用戶屬性: 自定義變量 $gender 和 $score ,以及 $reqeust 解析後的參數 is_member。

python3 format_importer.py nginx_item \
--url 'http://localhost:8106/sa?project=xxx' \
--item_id 'user_id' \
--item_type '__request_param_action' \
--filename './examples/item.log' \
--log_format '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$title" "$user_id"' \
--property_list '__request_param_id,title' \
--property_list_cnames '$gender,$score' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/nginx_item.conf )。

url: http://localhost:8106/sa?project=xxx
item_id: user_id
filename: ./examples/profiles.log
log_format: $remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$gender" "$score"
property_list: gender,score,__request_param_is_member
property_list_cnames: gender,score,is_member
debug
CODE

然後執行

python3 format_importer.py nginx_item @./conf/nginx_item.conf
CODE

2.5. 匯入 mysql 的數據

注意使用 mysql 匯入需要先安裝函式庫,請執行下面命令來安裝 PyMySQL。

python3 -m pip install PyMySQL --upgrade
CODE

2.5.1. 匯入事​​件

假設有以下 mysql 表描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.sql )。

drop table if exists events;
create table events (
user_id varchar(100),
action varchar(100),
time timestamp,
item_id int,
item_name text,
item_cate varchar(100));
insert into events values('bug29', 'view', '2018-05-12 13:01:11', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('bug29', 'buy', '2018-05-12 13:05:03', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('小武', 'view', '2018-05-13 10:20:32', 23421, 'New Order Technique 2CD豪華版 歐版行貨 全新未拆', '音像');
insert into events values('菠菜', 'view', '2018-05-13 20:42:53', 3442, 'NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型', '母嬰');
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id,以 time 作為事件發生的時間,以 action 作為事件名稱,只匯入 item_id 和 item_name 作為事件屬性。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

注意:若匯入事件名為 $SignUp 事件的 mysql 的數據,在神策裡不會寫用戶關聯關係,只會作為普通事件寫入事件表。

python3 format_importer.py mysql_event \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--timestamp_from 'time' \
--event_from 'action' \
--user 'root' \
--password 'pass' \
--host 'localhost' \
--port 3307 \
--db 'test_db' \
--sql 'select user_id, action, time, item_id, item_name from events order by time;' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/mysql_event.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
event_from: action
timestamp_from: time
user: root
password: pass
host: localhost
port: 3307
db: test_db
sql: select user_id, action, time, item_id, item_name from events order by time;
debug
CODE

然後執行

python3 format_importer.py mysql_event @./conf/mysql_event.conf
CODE

2.5.2. 匯入用戶屬性

假設有以下 mysql 表描述了上面的範例用戶屬性 ( 參考程式碼包 examples/profiles.sql )。

drop table if exists profiles;
create table profiles (
user_id varchar(100),
gender varchar(20),
is_member bool,
score int);
insert into profiles values('bug29', '男', true, 131);
insert into profiles values('小武', '女', false, null);
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id,匯入全部用戶屬性。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

python3 format_importer.py mysql_profile \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--user 'root' \
--password 'pass' \
--host 'localhost' \
--port 3307 \
--db 'test_db' \
--sql 'select user_id, gender, is_member, score from profiles order by user_id;' \
--bool_property_list 'is_member' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包下 conf/mysql_profile.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
user: root
password: pass
host: localhost
port: 3307
db: test_db
sql: select user_id, gender, is_member, score from profiles order by user_id;
bool_property_list: is_member
debug
CODE

然後執行

python3 format_importer.py mysql_profile @./conf/mysql_profile.conf
CODE

2.5.3. 匯入 item 數據

假設有以下 mysql 表描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.sql )。

drop table if exists events;
create table events (
user_id varchar(100),
action varchar(100),
time timestamp,
item_id int,
item_name text,
item_cate varchar(100));
insert into events values('bug29', 'view', '2018-05-12 13:01:11', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('bug29', 'buy', '2018-05-12 13:05:03', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('小武', 'view', '2018-05-13 10:20:32', 23421, 'New Order Technique 2CD豪華版 歐版行貨 全新未拆', '音像');
insert into events values('菠菜', 'view', '2018-05-13 20:42:53', 3442, 'NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型', '母嬰');
CODE

將這些數據匯入到本地私有部署的環境,以數據庫中的 item_id 作為 item 數據的 item_id,以數據庫的 action 作為 item_type 。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

format_importer.py mysql_item \
--url 'http://localhost:8106/sa?project=xxx' \
--item_type 'action' \
--item_id 'item_id' \
--user 'root' \
--password 'root1234' \
--host 'localhost' \
--port 3306 \
--db 'sa_item' \
--sql 'select user_id, gender, is_member, score from profiles order by user_id' \
--debug \ # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/mysql_event.conf )。

url: http://localhost:8106/sa?project=xxx
item_id: user_id
item_type: action
user: root
password: pass
host: localhost
port: 3307
db: test_db
sql: select user_id, gender, is_member, score from profiles order by user_id;
debug
CODE

然後執行

python3 format_importer.py mysql_event @./conf/mysql_item.conf
CODE

2.6. 匯入 json 格式的 log

用戶也可以將 log 寫入檔案中,每行是一個 數據格式  表示事件或屬性或者 item 數據。假設有以下 log 描述了上面的範例的事件、用戶屬性、item 數據 ( 參考程式碼包 examples/json_data.json )。

{"type":"track","time":1526101271000,"distinct_id":"bug29","properties":{"item_id":13245.0,"item_name":"\u7537\u58eb\u62a4\u8033\u4fdd\u6696\u9e2d\u820c\u76ae\u5e3d\u5e73\u9876\u516b\u89d2\u5e3d\u5934\u5c42\u725b\u76ae\u5e3d\u5b50\u65f6\u5c1a\u4f11\u95f2"},"event":"view","time_free":true}
{"type":"track","time":1526101503000,"distinct_id":"bug29","properties":{"item_id":13245.0,"item_name":"\u7537\u58eb\u62a4\u8033\u4fdd\u6696\u9e2d\u820c\u76ae\u5e3d\u5e73\u9876\u516b\u89d2\u5e3d\u5934\u5c42\u725b\u76ae\u5e3d\u5b50\u65f6\u5c1a\u4f11\u95f2"},"event":"buy","time_free":true}
{"type":"track","time":1526178032000,"distinct_id":"\u5c0f\u6b66","properties":{"item_id":23421.0,"item_name":"New Order Technique 2CD\u8c6a\u534e\u7248 \u6b27\u7248\u884c\u8d27 \u5168\u65b0\u672a\u62c6"}, "event":"view","time_free":true}
{"type":"track","time":1526215373000,"distinct_id":"\u83e0\u83dc","properties":{"item_id":3442.0,"item_name":"NUK\u5b89\u629a\u5976\u5634\u5b9d\u5b9d\u9632\u80c0\u6c14\u5b89\u6170\u5976\u5634\u4e73\u80f6\u8fea\u58eb\u5c3c\u5b89\u7761\u578b"},"event":"view","time_free":true}
{"type":"profile_set","time":1526263297951,"distinct_id":"bug29","properties":{"gender":"\u7537","is_member":true,"score":131.0},"time_free":true}
{"type":"profile_set","time":1526263297951,"distinct_id":"\u5c0f\u6b66","properties":{"gender":"\u5973","is_member":false},"time_free":true}
{"type":"item_set","properties":{"name":"yuejz","OrderPaid":12.1},"item_id":"item_id","time":1566022866941,"item_type":"item_type"}
{"type":"item_set","properties":{"name":"yuejz"},"item_id":"item_id","time":1566022866941,"item_type":"item_type"}
{"type":"item_set","time":1566023226152,"properties":{"OrderTime":"2019-07-01 12:02:36","OrderPaid":12.1},"item_id":"item_id","item_type":"item_type"}
{"type":"itpe":"profile_set","time":1526263297951,"distinct_id":"\u5c0f\u6b66","properties":{"gender":"\u5973","is_member":false},"time_free":true}
CODE

將這些數據匯入到本地私有部署的環境,

注意:若事件或屬性數據中 distinct_id 為登入 id,需在 properties 裡增加 "$is_login_id":true 屬性來標識。

python3 format_importer.py json \
--url 'http://localhost:8106/sa?project=xxx' \
--path './examples/json_data.json' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入 json.conf

url: http://localhost:8106/sa?project=xxx
path: ./examples/events_and_profiles.json
debug
CODE

然後執行

python3 format_importer.py json @./conf/json.conf
CODE

2.7. 匯入 oracle 的數據

注意使用 oracle 匯入需要先安裝函式庫,請執行下面命令來安裝 cx_Oracle 並需要確保電腦上包含了相關 oracle 用戶端程式包。

python3 -m pip install cx_Oracle --upgrade
CODE

2.7.1. 匯入事​​件

假設有以下 oracle 表描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.plsql )。

drop table if exists events;
create table events (
user_id varchar(100),
action varchar(100),
time timestamp,
item_id int,
item_name text,
item_cate varchar(100));
insert into events values('bug29', 'view', '2018-05-12 13:01:11', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('bug29', 'buy', '2018-05-12 13:05:03', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('小武', 'view', '2018-05-13 10:20:32', 23421, 'New Order Technique 2CD豪華版 歐版行貨 全新未拆', '音像');
insert into events values('菠菜', 'view', '2018-05-13 20:42:53', 3442, 'NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型', '母嬰');
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id,以 time 作為事件發生的時間,以 action 作為事件名稱,只匯入 item_id 和 item_name 作為事件屬性。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

注意:若匯入事件名為 $SignUp 事件的 oracle 的數據,在神策裡不會寫用戶關聯關係,只會作為普通事件寫入事件表。

python3 format_importer.py oracle_event \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--timestamp_from 'time' \
--event_from 'action' \
--user 'root' \
--password 'pass' \
--dsn '127.0.0.1/orcl' \
--sql 'select user_id, action, time, item_id, item_name from events order by time' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/oracle_event.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
event_from: action
timestamp_from: time
user: root
password: pass
dsn: 127.0.0.1/orcl
sql: select user_id, action, time, item_id, item_name from events order by time;
debug
CODE

然後執行

python3 format_importer.py oracle_event @./conf/oracle_event.conf
CODE

2.7.2. 匯入用戶屬性

假設有以下 oracle 表描述了上面的範例用戶屬性 ( 參考程式碼包 examples/profiles.plsql )。

drop table if exists profiles;
create table profiles (
user_id varchar(100),
gender varchar(20),
is_member bool,
score int);
insert into profiles values('bug29', '男', true, 131);
insert into profiles values('小武', '女', false, null);
CODE

將這些數據匯入到本地私有部署的環境,以 user_id 作為用戶的 id,匯入全部用戶屬性。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

python3 format_importer.py oracle_profile \
--url 'http://localhost:8106/sa?project=xxx' \
--distinct_id_from 'user_id' \
--is_login \ # 標識 distinct_id 為登入 id,若 distinct_id 為匿名 id,則去掉--is_login
--user 'root' \
--password 'pass' \
--dsn '127.0.0.1/orcl \
--sql 'select user_id, gender, is_member, score from profiles order by user_id' \
--bool_property_list 'is_member' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/oracle_profile.conf )。

url: http://localhost:8106/sa?project=xxx
distinct_id_from: user_id
is_login
user: root
password: pass
dsn: 127.0.0.1/orcl
sql: select user_id, gender, is_member, score from profiles order by user_id
bool_property_list: is_member
debug
CODE

然後執行

python3 format_importer.py oracle_profile @./conf/oracle_profile.conf
CODE

2.7.3. 匯入 item 數據

假設有以下 oracle 表描述了上面的範例用戶事件 ( 參考程式碼包 examples/events.plsql )。

drop table if exists events;
create table events (
user_id varchar(100),
action varchar(100),
time timestamp,
item_id int,
item_name text,
item_cate varchar(100));
insert into events values('bug29', 'view', '2018-05-12 13:01:11', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('bug29', 'buy', '2018-05-12 13:05:03', 13245, '男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒', '男裝');
insert into events values('小武', 'view', '2018-05-13 10:20:32', 23421, 'New Order Technique 2CD豪華版 歐版行貨 全新未拆', '音像');
insert into events values('菠菜', 'view', '2018-05-13 20:42:53', 3442, 'NUK安撫奶嘴寶寶防脹氣安慰奶嘴乳膠迪士尼安睡型', '母嬰');
CODE

將這些數據匯入到本地私有部署的環境,以數據庫中的 item_id 作為item 數據的 item_id,以數據庫的 action 作為 item 數據的 item_type,只匯入 item_cate 和 item_name 作為事件屬性。最後的 ORDER BY 主要是確保多次查詢數據順序一致,這樣假如匯入一半失敗了,可以使用我們的參數跳過匯入成功的行數。

python3 format_importer.py oracle_item \
--url 'http://localhost:8106/sa?project=xxx' \
--item_id 'item_id' \
--item_type 'action' \
--user 'root' \
--password 'pass' \
--dsn '127.0.0.1/orcl' \
--sql 'select item_id, action, item_cate, item_name from events order by time' \
--debug # 校驗數據格式,不會匯入數據,正式使用的時候去掉--debug
CODE

也可以將上述參數寫入設定檔案中 ( 參考程式碼包 conf/oracle_item.conf )。

url: http://localhost:8106/sa?project=xxx
item_id: user_id
item_type: action
user: root
password: pass
dsn: 127.0.0.1/orcl
sql: select item_id, action, item_cate, item_name from events order by time;
debug
CODE

然後執行

python3 format_importer.py oracle_item @./conf/oracle_item.conf
CODE

3. 使用建議

1. 先選用部分數據,增加 --debug 選項測試通過後再正式匯入。增加 --debug 後進入除錯模式,不會匯入數據。對於每條數據,若成功則發送的數據列到標準輸出上,否則會列印出錯資訊。執行完畢之後列印讀取多少條,錯誤多少條。

匯入 csv / nginx log 的時候,可以先用 head -1000 file_name > test_file 的方式先匯入一部分數據到測試檔案,然後使用測試檔案匯入
匯入 mysql 數據的時候,可以在查詢語句後面加上 LIMIT 1000 然後測試匯入
2. 執行時在 format_importer 目錄下會產生 log, log 名為 format_importer.log,包含比輸出更全的除錯資訊,如果增加 --debug 後螢幕上輸出比較多,可以查看 log 查找出錯資訊和除錯資訊。
3. 由於參數比較複雜,建議 使用設定檔案的方式傳遞參數,具體設定檔案範例可以解壓後查看 conf 目錄。
4. 對於 csv log 匯入,需要確保 log 檔是有效的 csv 格式,建議先閱讀 csv 轉義 相關的內容。
5. 由於 nginx 的 log 格式所限,匯入的 property 的名字可能看起來並不具有可讀性,比如 __request_param_action 這樣的,強烈建議使用 property_list_cnames 來轉化成可讀的屬性名。
6. 對於mysql 匯入,如果sql 語句寫的比較長的時候,容易出現sql 傳遞給程式後shell 轉義錯誤的問題,建議錯誤時查看在format_impoter 目錄下的 log,會在啟動後第一條 log 裡面寫上傳遞的參數,請仔細查看和傳遞的sql 是否一致。另外建議如果 sql 比較長,建議使用 --filename 的方式寫入檔案傳遞。
7. 對於 mysql 匯入,如果 sql 語句是兩個表的 join, 那麼指定列名的時候需要指定的是別名或者列名,而不是<表名>.<列名>。詳細解釋參見 用 mysql 將兩張表 join 起來匯入,明明有數據為什麼提示我 distinct_id / timestamp / event 為空
8. 如果需要更高效率匯入,建議先使用 --output_file 來導出到 log 檔中去,然後使用 BatchImporter 或者 HDFSImporter匯入到叢集中去。

4. 使用方法詳解

4.1. 子命令說明

子命令就是跟在執行腳本後的第一個參數,比如 2.1 中執行

python3 format_importer.py csv_event \
--url 'http://localhost:8106/sa?project=xxx' \
--event_default 'UserBuy' \
--distinct_id_from 'user' \
--timestamp_from 'buy_time' \
--filename 'buy.csv'
CODE

使用的子命令是 csv_event,表示 csv 格式數據匯入為event。目前支援以下7種子命令。

自命令名稱解釋
csv_profile將 csv 格式檔案匯入, 匯入 profile
csv_event將 csv 格式檔案匯入, 匯入event
csv_item將 csv 格式檔案匯入, 匯入 item
mysql_profile提供 sql,將 mysql 的數據匯入, 匯入 profile
mysql_event提供 sql,將 mysql 的數據匯入, 匯入 event
mysql_item提供 sql,將 mysql 的數據匯入, 匯入 item
nginx_profile將 Nginx Log 匯入, 匯入 profile
nginx_event將 Nginx Log 匯入, 匯入 event
nginx_item將 Nginx Log 匯入, 匯入 item
json將 Json Log匯入,注意 Log 不區分 event、profile、item
oracle_profile提供 sql,將 oracle 的數據匯入, 匯入 profile
oracle_event提供 sql,將 oracle 的數據匯入, 匯入 event
oracle_item提供 sql,將 oracle 的數據匯入, 匯入 item

如果想看單個子命令支援哪些參數,可以在子命令之後加 -h,將取得所有的參數和說明,如

python3 format_importer.py csv_event -h
python3 format_importer.py json -h
CODE

4.2. 從設定檔案中匯入

format_importer 支援從設定檔案中讀取參數,使用方法是在子命令之後增加 @<設定檔案路徑>。下載後的原始碼包裡面即包含了預設的幾個設定,在 conf 目錄下,可以修改後使用設定檔案匯入。

舉例想匯入 csv 的 event,可以修改 conf/csv_event.conf,然後執行

python3 format_importer.py csv_event @./conf/csv_event.conf
CODE

4.3. 公共參數

通用的公共參數包括:

參數名別名是否必填解釋
--url-l和 output_file 選一個必填發送數據的 url,取得方式在 2.1 節已經進行過描述。
--output_file-O和 url 選一個必填輸出的檔案名,輸出每行是一個符合格式的json。
--project-j指定的project名,預設是default
--skip_cnt-c第一次執行請忽略,如果執行失敗,需要跳過成功的那幾行,這個就是指定跳過幾行的。
--debug-D如果指定了就是使用debug模式,不會匯入數據,只在stdout顯示數據,參見除錯模式
--quit_on_error-Q如果選中,則出現一條錯誤 log 就會退出

此外,匯入 csv log / nginx log / mysql 數據時需要區分是匯入 event 還是 profile,二者有不同的公共參數;匯入 json log 時,只支援設定如上的公共參數。

4.4. event/profile/item 公共參數

對於profile, 匯入需要指定哪一列作為 distinct_id.

對於 event,除了指定 distinct_id,還需要指定 event 和 timestamp。指定 event 目前支援兩種方法,一種將所有的數據都認為是同一個 event,另一種是指定哪一列作為 event。同樣指定 timestamp 目前支援兩種方法,一種將所有數據都認為是同一個 timestamp,另一種是指定哪一列作為 timestamp。

對應 item,必須指定 item_type 和 item_id。

參數名别名匯入 profile 是否需要 匯入 event 是否需要 匯入 item 是否需要解釋
--distinct_id_from-df必填必填不可以填從哪個欄位作為 distinct_id,如果指定,則每條數據算作對應欄位的用戶的行為。
--is_login
選填選填不可以填distinct_id 是否是 login id,預設不是;注:匯入 json 格式數據不支援此參數,如需使用請在 json 數據中增加 "$is_login_id" 屬性。
--event_from-ef不可以填和 event_default 選一個必填不可以填哪個欄位作為 event 名,如果指定,則每條數據的事件名為對應欄位的值。
--event_default-ed不可以填和 event_from 選一個必填不可以填預設的 event 名,如果指定,則將所有數據都算作這個 event 的。
--timestamp_from-tf不可以填選填不可以填哪個欄位作為 time, 如果指定,則每條數據對應的時間為對應欄位的值。
--timestamp_default-td不可以填選填不可以填預設的 timestamp, 如果指定,則將所有數據都算作這個時間的事件。
--timestamp_format-tf不可以填選填不可以填和 timestamp_from 一起使用,如果指定,並 timestamp_from 對應的欄位是個字串,可以透過這種方式指定時間格式。預設是%Y-%m-%d %H:%M:%S。
--item_type
不可以填不可以填必填匯入 item 數據時,指定 item_type 欄位的值
--item_id
不可以填不可以填必填匯入 item 數據時,指定 item_id 欄位的值

4.5. 匯入 csv 格式的其他參數

參數名别名是否必填 解釋
--filename-fcsv檔案路徑
--property_list-pl用逗號分割選取的 property, 舉例-p name,time將會將 name 和 time 兩列作為 property 匯入。如果不填寫則表示全部作為 property 匯入。
--skip_identify-i對應的列將不會做自動型別判斷,舉例--skip_identify name,id將會將 name 和 id 不做型別判斷,完全作為 string 匯入如果不填寫則表示全部的選中列都會自動做型別判斷。
--ignore_value
指定某些值為空,比如指定 --ignore_value null 則所有的null都被認為是空值
--add_cname-ac是否增加中文名,只對 event 有效. 如果 csv 的表頭是中文,程式會將對應的 property 名改為對應的拼音。這時,如果將 add_cname 選中,會自動在程式的最後把中英文的映射關係填上去,這樣在Ui上看到的對應 property 就是中文的了。
--web_url-w如果選擇 add_cname 則必填

web 連接的 url ,單機版類似 http://localhost:8007/, cloud 版類似 http://xxx.cloud.sensorsdata.cn。

--username-u如果選擇 add_cname 則必填web 登入帳號。
--password-p如果選擇 add_cname 則必填web 登入密碼。
--csv_delimiter
csv檔案的列分隔符號,預設為',',只接受單字元參數, 也可以傳\ + ascii的數字,比如\9表示是\t
--csv_quotechar
csv檔案的引用字元,用於指定csv字串的開始和結尾,預設為'"',只接受單字元參數, 也可以傳\ + ascii的數字,比如\9表示是\t
--csv_prefetch_lines
csv檔案預讀行數,預讀用於判斷列的類型,預設為-1,即預讀整個檔案。注意如果數據分佈不均(比如前幾行某個欄位沒有但是後面有)不要加這個參數
--file_encoding
設定 csv 檔案編碼格式,預設為 utf-8

4.6. 匯入 nginx log 的其他參數

參數名別名 是否必填 解釋
--filename-fnginx log 檔案路徑
--log_format-Fnginx log 設定,類似'"$remote_addr" "$time_local" "$http_refer" "$status"'。
--property_list-pl用逗號分割選取的 property, 舉例--property_list http_refer,status將會將http_refer和status兩列作為 property 匯入。
--skip_identify-i對應的列將不會做自動型別判斷,舉例--skip_identify request_user,status將會將 request_user, status 不做型別判斷,完全作為 string 匯入。如果不填寫則表示全部的選中列都會自動做型判斷。
--url_fields-uf對應的列將作為url解析,用逗號分割。解析後會產生__<欄位名>_<解析內容>這樣命名的property,解析內容包括netloc, path, query, param_<參數名>。舉例對於$my_url欄位值為http://www.abc.com/path/to/mine?k1=v1&k2=2,會解析為{"__my_url_netloc": "www.abc.com","__my_url_path": "/path/to/mine", "__my_url_query":"k1=v1&k2=v", "__my_url_param_k1": "v1","__my_url_param_k2":2}。注意可以再 property_list 設定這些欄位。預設是"http_referer"。
--filter_path-fp過濾對應的 path ,可多選。這裡的 path 取的是 $request的path。支援正規。舉例--filter_path '.*\.gif' --filter_path '/index\.html' 將過濾對 gif 的請求和 index 的請求。
--ip_from-if只對 event 有效, 哪個欄位作為 ip, 如果指定,則每條數據對應的 ip 為對應欄位的值, 預設是$remote_addr
--ignore_value
指定某些值為空,比如指定 --ignore_value null 則所有的null都被認為是空值
--property_list_cnames
用逗號分割property的對應名稱, 需要和--property_list一一對應

4.7. 匯入 mysql 數據的其他參數

参數名别名 是否必填解釋
--user-umysql 的 username
--password-pmysql 的 password
--host-imysql 的網址
--port-Pmysql 的埠號
--db-dmysql 對應的 db 名,一次只能指定一個
--sql-q和 filename 選一個必填查詢語句,建議加 order by 等方式確保多次查詢結果順序一致。
--filename-f和 sql 選一個必填查詢語句所在的檔案路徑,建議加 order by 等方式確保多次查詢結果順序一致。
--bool_property_list-bp逗號分割的bool型別屬性列表,會將對應的屬性值為1的轉化為true,0轉化為false
--case_sensitive-cs匯入的屬性名是否是大小寫敏感,注意如果大小寫不敏感會全部轉化為大寫,預設為true

4.8. 匯入 json log 的其他參數

參數名别名 是否必填解释
--path-plog 的檔案/目錄路徑

注意匯入 json log,如果傳遞了 log 目錄,那麼會遍歷該目錄下一級的所有的檔案,並且按照字母順序匯入。本參數不支援嵌套目錄。

4.9. 匯入 oracle 數據的其他參數

参数名别名是否必填解釋
--user-uoracle 的 username
--password-poracle 的 password
--dsn-dsnoracle 的 dsn
--sql-q和 filename 選一個必填查詢語句,建議加 order by 等方式確保多次查詢結果順序一致。
--filename-f和 sql 選一個必填查詢語句所在的檔案路徑,建議加 order by 等方式確保多次查詢結果順序一致。
--bool_property_list-bp逗號分割的 bool 型別屬性列表,會將對應的屬性值為 1 的轉化為 true,0 轉化為 false
--case_sensitive-cs匯入的屬性名是否是大小寫敏感,注意如果大小寫不敏感會全部轉化為大寫,預設為 false

5. 常見文提

5.1. csv 的表頭是中文是否可以支援

根據我們在 數據格式 裡面的說明,property 的名稱是不可以包含中文的,但是可以設定 property 在 UI 上顯示為對應的中文名。透過設定 --add_cname 即可自動完成這一過程。使用上面的例子,buy.csv 格式如下:

用戶名,購買時間,商品id,商品名稱,商品類別
小明,2015-01-20 10:35:22,13579,真皮帽子 男士護耳保暖鴨舌皮帽平頂八角帽頭層牛皮帽子時尚休閒,男裝
小芳,2015-07-13 23:12:03,24680,官方正品ZINO 3D透亮無瑕BB霜SPF30PA++ 防曬遮瑕美白 小樣 3ml,護膚
小武,2015-04-03 20:30:01,31415,New Order Technique 2CD豪華版 歐版行貨 全新未拆,音像
CODE

匯入參數如下:

python3 format_importer.py csv_event \
--url 'http://localhost:8006/sa?project=xxx' \
--event_default 'UserBuy' \
--distinct_id_from '用戶名' \
--is_login \
--timestamp_from '購買時間' \
--filename 'buy.csv' \
--add_cname \
--web_url 'http://localhost:8007' \
--username admin \
--password password
CODE

注意在不同的平台上對編碼要求不同,需要確保預設編碼和檔案編碼一致,具體請參考 windows下使用說明。

5.2. 如何設定 nginx 可以過濾掉靜態檔案?

假設 nginx log 中包含了對 gif 檔案, css 檔案和 js 檔案的請求,這些請求希望過濾掉,可以使用  --filter_path 來過濾。

python3 format_importer.py nginx_event \
--filter_path '.*\.gif' \
--filter_path '.*\.css' \
--filter_path '.*\.js' \
# 其他參數。。。
CODE

5.3. 匯入了一半出錯了怎麼辦?

預設的情況下,出現解析錯誤的數據,匯入工具會在執行過程中對錯誤列印錯誤原因和錯誤的行數,然後丟棄錯誤數據繼續處理。列印 log 類似這樣的:

2015-10-28 14:58:52,020 808 WARNING failed to parse line 12
2015-10-28 14:58:52,021 809 WARNING Traceback (most recent call last):
File "format_importer.py", line 804, in main
sa.track(distinct_id, event, properties)
File "/Users/padme/git/sa2/tools/format_importer/sensorsanalytics/sdk.py", line 118, in track
data = self._normalize_data(data)
File "/Users/padme/git/sa2/tools/format_importer/sensorsanalytics/sdk.py", line 149, in _normalize_data
raise SensorsAnalyticsIllegalDataException("property [distinct_id] must not be empty")
sensorsanalytics.sdk.SensorsAnalyticsIllegalDataException: property [distinct_id] must not be empty
CODE

在執行結束的時候會列印讀取(total_read)了多少行,寫入(total_write)多少行,出錯(error)了多少行,跳過(skip)了多少行,類似這樣:

2015-10-28 14:58:52,023 618 INFO end import nginx
2015-10-28 14:58:52,024 838 INFO counter = {'error': 3, 'skip': 0, 'total': 300, 'total_read': 100, 'total_write': 97}.
CODE

如果希望能夠出錯就提示,可以增加選項 --quit_on_error,這樣的話出錯了的 log 如下:

2015-10-28 14:58:29,499 808 WARNING failed to parse line 12
2015-10-28 14:58:29,502 809 WARNING Traceback (most recent call last):
File "format_importer.py", line 804, in main
sa.track(distinct_id, event, properties)
File "/Users/padme/git/sa2/tools/format_importer/sensorsanalytics/sdk.py", line 118, in track
data = self._normalize_data(data)
File "/Users/padme/git/sa2/tools/format_importer/sensorsanalytics/sdk.py", line 149, in _normalize_data
raise SensorsAnalyticsIllegalDataException("property [distinct_id] must not be empty")
sensorsanalytics.sdk.SensorsAnalyticsIllegalDataException: property [distinct_id] must not be empty

2015-10-28 14:58:29,502 618 INFO end import nginx
2015-10-28 14:58:29,502 835 ERROR failed to import, please fix it and run with[--skip_cnt 11] again!
CODE

注意下方提示,說明已經成功匯入了11行,修復第12行的數據後在之前的命令上再加上參數 --skip_cnt 11 即可。

需要特別說明的是,對於 mysql,為了防止數據錯誤後不可恢復的問題,請務必確保 查詢sql多次呼叫結果一致,即:

沒有新數據再寫入,比如透過增加 WHERE 確保只匯入歷史數據。
查詢結果增加排序選項確保順序一致,比如增加 ORDER BY id。

5.4. 用 mysql 將兩張表 join 起來匯入,明明有數據為什麼提示我 distinct_id / timestamp / event 為空?

注意如果使用兩個表 join,列名要是唯一的,或要取別名。這裡的列名一方面是表示使用 distinct_id_from, timestamp_from, event_from 的參數,另一方面也是匯入後 property 的名字。

舉例,sql 如下:

SELECT a.uid, a.event, a.time, b.property1, b.property2
FROM a JOIN b ON a.action_id = b.action_id

那麼執行參數需要指定為

--distinct_id_from 'uid' \
--timestamp_from 'time' \
--event_from 'event'

匯入的 property 的名字也分別是(property1, property2) 而不是(b.property1, b.property2)。

如果列名不是唯一的,另一種方法是取別名. 舉例sql如下:

SELECT a.u AS uid, a.e AS event, a.t AS time, b.property AS property1, a.property AS property2
FROM a JOIN b ON a.action_id = b.action_id

那麼執行的參數指定為:

--distinct_id_from 'uid' \
--timestamp_from 'time' \
--event_from 'event'

匯入的 property 的名字也分別是(property1, property2)。

5.5. 用 mysql 匯入的時候,如何將數值轉化成文字/文字轉化成數值匯入?

mysql 的 CAST 方法支援型別轉化。

舉例,mysql 中有個型別為 int 的列 property1 和一個型別為 varchar(10) 的列為 property2,可以使用 sql:

SELECT CAST(property1 AS CHAR(10)) AS property1, CAST(property2 AS SIGNED) AS property2 FROM test_table;


將 property1 的值轉化成 10 個字元長的文字,將 property2 的值​​轉化為數值。

5.6. 如何匯入其他Project

如果沒有顯示指定 project,則預設匯入預設 project (default)。

可以透過 --url 裡面包含 project=<project_name> 來指定project 名,也可以透過 --project 參數來指定。如果同時指定則採用 --project 的參數。

注意,如果 --url 的值是透過右上角“帳號” -> “數據接入” -> “複製數據接收網址” 來取得的話,則複製的介面裡面自帶 project 參數,不需要額外指定。

此外,如果是匯入 json log,可以在 json 中增加 "project":"project名稱" 來使用一份數據匯入多個 project。log 裡面的 project 欄位優先級高於參數。

5.7. csv如何轉義

csv是用逗號分割的檔案格式,如果某一列的內容中包含逗號,需要用雙引號分割開,否則 format importer 將會報錯。舉例,csv 檔案內容如下:

col1,col2,col3
a,b,c,d

執行時將會報錯:

csv error near line 1: content has 1 more fields than header

即提示內容的列數比頭部的列數多一列。正確的做法是加上雙引號:

col1,col2,col3
a,"b,c",d

將會被識別為:

col1col2col3
ab,cd

注意雙引號可以跨行。舉例,csv檔案內容如下:

col1,col2,col3
a,"b,c
d,e",f

將會被識別為:

col1col2col3
ab,c,d,ef

因此如果某一列以雙引號開頭,那麼csv會一直找到下一個雙引號結尾。如果兩個雙引號直接的字元過多,會報錯列超長:

_csv.Error: field larger than field limit (131072)

解決方法有兩個,一個是可以透過 --csv_quotechar 參數替換 csv 預設的字元串邊界符號,需要確保這個符號沒有出現過。另外就是對雙引號轉義,需要把一個雙引號變成兩個,並且對本列用雙引號引住。舉例,csv檔案內容如下:

col1,col2,col3
a,"""b",c

將會識別為

col1col2col3
a"bc

5.8. 對於 json 格式的 log,使用 FormatImporter 匯入,和使用 LogAgent/BatchImporter匯入有什麼區別?

1. LogAgent 即時流式將 log 內容匯入,如果 log 在不斷更新,建議使用 LogAgent 匯入. 而 FormatImporter 和 BatchImporter 都是一次性匯入。
2. BatchImporter 在三者中匯入效率最高,但是只能在部署神策分析的電腦上使用。 FormatImporter , LogAgent 可以在任意電腦上執行。

5.9. windows下使用說明

在 windows 下使用 FormatImporter 時,由於終端的語法不同,預設編碼不同,有以下幾個注意事項:

1. 盡量使用設定檔案遞參數,而不是命令列傳遞,避免命令轉義。注意上述範例中的命令都是基於 unix 作業系統,如果直接在 windows 下面執行可能會出現語法錯誤或轉義。
2. csv 檔案預設支援 utf-8 編碼,如果出現編碼錯誤,可以先查看檔案編碼格式,然後使用 --file_encoding 命令設定編碼格式
3. 如果需要在 windows 下連接 mysql / oracle,需要對編碼做特殊處理,具體處理方式請諮詢神策技術支援同學。

5.10. 匯入限制

匯入數據時,formatImporter 匯入本身沒有數據量上限,但是如果匯入數據較大時,速度較慢,大約1 分鐘匯入500~700 條左右,且匯入的速度和網絡穩定性有關,如果匯入超時,可以使用內網數據接收網址嘗試是否可以。