FormatImporter
|
收藏
1. 概述
FormatImporter 用于将一些常见格式的外部数据导入到神策分析,目前支持读取 CSV 表格、Nginx 日志、MySQL 数据库、Oracle 数据库,以及符合.数据格式 v1.13的 JSON 数据。
2. 使用方法
2.1. 运行环境
此工具支持在 Linux 环境下运行,也支持在 windows 环境下运行,需要 Python3.4 或更高版本。另外如果需要导入 MySQL、Oracle 数据库中的数据的话需要确保机器上包含相关客户端的程序包。
windows 环境下部署时,需要注意文件编码问题,具体注意事项参考本文的 4.8 。
2.2. 下载工具
下载请点击此链接,脚本下载后是一个压缩包,解压后即可使用。
2.3. 获取数据接收地址
首先从神策分析的主页中,获取数据接收地址,获取方法如图(不同版本获取方法略有不同):
①、
②、
2.4. 导入 CSV 格式的数据
2.4.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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型,母婴
将这些数据导入神策系统中,以 user_id 列作为用户 ID,time 列作为事件发生的时间,action 列作为事件名称,只导入 item_id 和 item_name 作为事件属性:
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
注:--url 设置的是数据接收地址,具体的获取放可以参照 数据接入引导 。
2.4.2. 用户属性
假设有 CSV 文件描述了以下用户属性 ( 参考代码包下 examples/profiles.csv ):
user_id,gender,is_member,score
bug29,男,true,131
小武,女,false,
将这些数据导入神策系统中,以 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
2.4.3. 导入物品数据
假设有 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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型,母婴,买买
将这些数据导入神策系统中,--item_type 和 --item_id 配置分别指定物品数据的 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
2.4.4. 导入用户关联关系
注意:导入用户关联关系需要 v1.13.5 及以上版本
假设有 CSV 文件描述了以下用户关联关系 ( 参考代码包下 examples/signup.csv ):
user_id,device_id
小武,ac0eadfb-cd5d-44b6-8a21-079862773c11
菠菜,2903f1d4-e20d-4866-8614-66d9101a3bd3
bug29,0c0c93f5-c747-4c1a-acfc-e75279720da1
将这些数据导入到神策系统中,--login_id_from 和 --anonymous_id_from 配置分别指定用户关联关系的登录 ID 与匿名 ID:
python3 format_importer.py csv_signup \
--url 'http://localhost:8106/sa?project=xxx' \
--login_id_from 'user_id' \
--anonymous_id_from 'device_id' \
--filename './examples/signup.csv' \
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉 --debug
2.5. 导入 Nginx 日志
2.5.1. 导入事件
假设有 Nginx 日志描述了以下用户行为 ( 参考代码包下 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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型" "菠菜"
对应 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;
将这些数据导入神策系统中,以 $user_id 作为用户 ID,以 $time_local 作为事件发生的时间,$request 解析后的参数 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
2.5.2. 导入用户属性
假设有 Nginx 日志描述了以下用户属性( 参考代码包下 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" "女" ""
对应 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;
将这些数据导入神策系统中,以 $reqeust 解析后的参数 user 作为用户 ID,导入三个用户属性: 自定义变量 $gender 和 $score ,以及 $request 解析后的参数 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
2.5.3. 导入物品属性
假设有 Nginx 日志描述了以下物品数据 ( 参考代码包下 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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型" "菠菜"
对应 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;
将这些数据导入神策系统中,--item_type 和 --item_id 配置分别指定物品数据的 item_type 和 item_id 字段值:
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
2.5.4. 导入用户关联关系
注意:导入用户关联关系需要 v1.13.5 及以上版本
假设有 Nginx 日志描述了以下用户关联关系 ( 参考代码包下 examples/signup.log ):
123.4.5.6 - [12/May/2018:13:01:11 +0800] "POST /login?user_id=bug29&device_id=0c0c93f5-c747-4c1a-acfc-e75279720da1" 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 /login?user_id=%e5%b0%8f%e6%ad%a6&device_id=ac0eadfb-cd5d-44b6-8a21-079862773c11" 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" "女" ""
将这些数据导入到神策系统中,--login_id_from 和 --anonymous_id_from 配置分别指定用户关联关系的登录 ID 与匿名 ID:
python3 format_importer.py nginx_signup \
--url 'http://localhost:8106/sa?project=xxx' \
--login_id_from '__request_param_user_id' \
--anonymous_id_from '__request_param_device_id' \
--filename './examples/signup.log' \
--log_format '$remote_addr [$time_local] "$request" $status $bytes_sent "$http_user_agent" "$http_referer" "$gender" "$score"' \
--property_list '__request_param_user_id,__request_param_device_id' \
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉--debug
2.6. 导入 MySQL 的数据
注意使用 MySQL 导入需要先安装相关库,请运行下面命令来安装 PyMySQL:
python3 -m pip install PyMySQL --upgrade
2.6.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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型', '母婴');
将这些数据导入神策系统中,以 user_id 列作为用户 ID,time 列作为事件发生的时间,action 列作为事件名称,只导入 item_id 和 item_name 作为事件属性。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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
2.6.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);
将这些数据导入神策系统中,以 user_id 列作为用户 ID,剩余列全部作为用户属性。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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
2.6.3. 导入物品属性
假设有 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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型', '母婴');
将这些数据导入神策系统中,以表中的 item_id 列作为物品数据的 item_id,action 列作为 item_type 。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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 events order by user_id' \
--debug \ # 校验数据格式,不会导入数据,正式使用的时候去掉 --debug
2.6.4. 导入用户关联关系
注意:导入用户关联关系需要 v1.13.5 及以上版本
假设有 MySQL 数据库描述了以下用户关联关系 ( 参考代码包下 examples/signup.sql ):
drop table if exists users;
create table users (
user_id varchar(100),
device_id varchar(100));
insert into users values('bug29', '0c0c93f5-c747-4c1a-acfc-e75279720da1');
insert into users values('小武', 'ac0eadfb-cd5d-44b6-8a21-079862773c11');
insert into users values('菠菜', '2903f1d4-e20d-4866-8614-66d9101a3bd3');
将这些数据导入到神策系统中,--login_id_from 和 --anonymous_id_from 配置分别指定用户关联关系的登录 ID 与匿名 ID。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
python3 format_importer.py mysql_signup \
--url 'http://localhost:8106/sa?project=xxx' \
--login_id_from 'user_id' \
--anonymous_id_from 'device_id' \
--user 'root' \
--password 'root1234' \
--host 'localhost' \
--port 3306 \
--db 'sa_user' \
--sql 'select user_id, device_id from users order by user_id;' \
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉 --debug
2.7. 导入 JSON 格式的日志
用户也可以将日志写入文件中,每行是一个符合.数据格式 v1.13 的数据。假设有日志描述了以下事件、用户属性、物品数据 ( 参考代码包下 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":"item_delete","item_id":"item_id","properties":{"OrderPaid":12.1,"OrderTime":"2019-07-01 12:02:36"},"item_type":"item_type"}
注意:若事件或用户属性数据中 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
2.8. 导入 Oracle 的数据
注意导入 Oracle 中的数据需要先安装相关库,请运行下面命令来安装 cx_Oracle 并需要确保机器上包含了 Oracle 客户端程序包:
python3 -m pip install cx_Oracle --upgrade
2.8.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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型', '母婴');
将这些数据导入神策系统中,以 user_id 列作为用户 ID,time 列作为事件发生的时间,action 列作为事件名称,只导入 item_id 和 item_name 作为事件属性。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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 as "user_id", ACTION as "action", TIME as "time", ITEM_ID as "item_id", ITEM_NAME as "item_name" from events order by time' \
--case_sensitive true
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉 --debug
2.8.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);
将这些数据导入神策系统中,以 user_id 列作为用户 ID,剩余列全部作为用户属性。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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 as "user_id", GENDER as "gender", IS_MEMBER as "is_member", SCORE as "score" from profiles order by user_id' \
--case_sensitive true
--bool_property_list 'is_member' \
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉--debug
2.8.3. 导入物品数据
假设有 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安抚奶嘴宝宝防胀气安慰奶嘴乳胶迪士尼安睡型', '母婴');
将这些数据导入神策系统中,以数据库中的 item_id 列作为物品数据的 item_id,action 列作为物品数据的 item_type,只导入 item_cate 和 item_name 作为事件属性。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
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 as "item_id", ACTION as "action", ITEM_CATE as "item_cate", ITEM_NAME as "item_name" from events order by time' \
--case_sensitive true
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉--debug
2.8.4. 导入用户关联关系
注意:导入用户关联关系需要 v1.13.5 及以上版本
假设有 Oracle 数据库描述了以下用户关联关系 ( 参考代码包下 examples/signup.plsql ):
create table users (
user_id varchar2(100),
device_id varchar(200));
insert into users (user_id, device_id) values('bug29', '0c0c93f5-c747-4c1a-acfc-e75279720da1');
insert into users (user_id, device_id) values('小武', 'ac0eadfb-cd5d-44b6-8a21-079862773c11');
insert into users (user_id, device_id) values('菠菜', '2903f1d4-e20d-4866-8614-66d9101a3bd3');
commit;
将数据导入到神策系统中,--login_id_from 和 --anonymous_id_from 配置分别指定用户关联关系的登录 ID 与匿名 ID。最后的 ORDER BY 主要是保证多次查询数据顺序一致,这样假如导入一半失败了,可以在顺序不变的情况下用 --skip_cnt 配置跳过导入成功的行数:
python3 format_importer.py oracle_item \
--url 'http://localhost:8106/sa?project=xxx' \
--login_id_from 'USER_ID' \
--anonymous_id_from 'DEVICE_ID' \
--user 'root' \
--password 'pass' \
--dsn '127.0.0.1/orcl' \
--sql 'select USER_ID as "user_id",DEVICE_ID as "device_id" from users order by user_id' \
--case_sensitive true
--debug # 校验数据格式,不会导入数据,正式使用的时候去掉--debug
2.9. 从配置文件中导入
FormatImporter 支持从配置文件中读取参数,使用方法是在子命令之后增加 @<配置文件路径>。下载后的源码包的 conf 目录下就包含了默认的几个配置,可以修改配置的内容后使用。
以 2.2.1 为例,我们可以先把导入参数写到配置文件中 ( 参考代码包下 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 # 校验数据格式,不会导入数据,正式使用的时候去掉 --debug
然后执行:
python3 format_importer.py csv_event @./conf/csv_event.conf
其他类型的数据都可以使用这种方法进行导入。
2.10. 注意事项
- 当导入数据到神策之前,请确认下数据中 distinct_id 是登录 ID 还是匿名 ID。若是登录 ID,则需在导入命令中添加参数 --is_login。
- 先选用部分数据,增加 --debug 选项测试通过后再正式导入。增加 --debug 后进入调试模式,不会真正导入数据。对于每条数据,若成功则发送的数据打到标准输出上,否则会打印出错信息。执行完毕之后打印读取多少条,出错多少条。
- 导入 CSV / Nginx 日志的时候,可以先用 head -1000 file_name > test_file 的方式先导入一部分数据到测试文件,然后使用测试文件导入。
- 导入 MySQL 数据的时候,可以在查询语句后面加上 LIMIT 1000 然后测试导入。
- 运行时在 format_importer 目录下会产生日志, 日志名为 format_importer.log,包含比输出更全的调试信息,如果增加 --debug 后屏幕上输出比较多,可以查看日志查找出错信息和调试信息。
- 由于参数比较复杂,建议使用配置文件的方式传递参数,具体配置文件样例可以解压后查看 conf 目录。
- 对于 CSV 日志导入,需要确保日志文件是有效的 CSV 格式,建议先阅读 CSV 转义 相关的内容。
- 由于 Nginx 的日志格式所限,导入的 property 的名字可能看起来并不具有可读性,比如:__request_param_action 等。强烈建议使用 property_list_cnames 来转化成可读性较强的属性名。
- 对于 MySQL 导入,如果 SQL 语句较长,容易出现 SQL 传递给程序后 shell 转义错误的问题,建议出错时查看在 format_impoter 目录下的日志,会在启动后第一条日志里面写上传递的参数,请仔细查看和传递的 SQL 是否一致。另外 SQL 较长的情况下,建议使用 --filename 的方式将 SQL 语句写入文件传递。
- 对于 MySQL 导入,如果 SQL 语句设计到两个表的 join 操作,那么指定列名时需要使用别名或者列名,而不是<表名>.<列名>。详细解释参见用 MySQL 将两张表 join 起来导入,明明有数据为什么提示我 distinct_id / timestamp / event 为空。
- 如果希望提高导入速度,建议先使用 --output_file 生成日志文件,然后使用 BatchImporter 或者 HDFSImporter 导入数据。
3. 使用详解
3.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'
使用的子命令是 csv_event,表示将 CSV 格式文件转化成事件导入。目前支持以下 17 种子命令:
自命令名称 | 解释 |
---|---|
csv_profile | 将 CSV 格式文件转化成用户属性导入 |
csv_event | 将 CSV 格式文件转化成事件导入 |
csv_item | 将 CSV 格式文件转化成物品数据导入 |
csv_signup | 将 CSV 格式文件转化成用户关联关系导入 |
mysql_profile | 将 MySQL 数据库中数据转化成用户属性导入 |
mysql_event | 将 MySQL 数据库中数据转化成事件导入 |
mysql_item | 将 MySQL 数据库中数据转化成物品数据导入 |
mysql_signup | 将 MySQL 数据库中数据转化成用户关联关系导入 |
nginx_profile | 将 Nginx 日志转化成用户属性导入 |
nginx_event | 将 Nginx 日志转化成事件导入 |
nginx_item | 将 Nginx 日志转化成物品数据导入 |
nginx_signup | 将 Nginx 日志转化成用户关联关系导入 |
json | 将 JSON 日志导入,注意日志不区分 event、profile、item、signup |
oracle_profile | 将 Oracle 数据库中数据转化成用户属性导入 |
oracle_event | 将 Oracle 数据库中数据转化成事件导入 |
oracle_item | 将 Oracle 数据库中数据转化成物品数据导入 |
oracle_signup | 将 Oracle 数据库中数据转化成用户关联关系导入 |
如果想看单个子命令支持哪些参数,可以在子命令之后加 -h,将获取所有的参数和说明,如:
python3 format_importer.py csv_event -h
python3 format_importer.py json -h
3.2. 公共参数
通用的公共参数包括:
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--url | -l | 和 output_file 选一个必填 | 数据接收地址 |
--output_file | -O | 和 url 选一个必填 | 输出的文件名,输出每行是一个符合格式的 JSON。 |
--project | -j | 否 | 指定的 project 名,默认是 default |
--skip_cnt | -c | 否 | 第一次运行请忽略,如果运行失败,可以使用此配置指定跳过开头多少行 |
--debug | -D | 否 | 如果指定了就是使用 debug 模式,不会导入数据,只在 stdout 显示数据,参见.调试模式 v1.13 |
--quit_on_error | -Q | 否 | 如果选中,则出现一条错误日志就会退出 |
-- log_level | -lv | 否 | 日志输出最小等级,默认为 DEBUG |
此外,从 CSV 表格、Nginx 日志、MySQL 数据库、Oracle 数据库导入数据时,需要区分是导入 event、profile、item 还是 signup,四者有不同的公共参数;导入 JSON 日志时,只支持设置如上的公共参数。
3.3. 子命令公共参数
3.3.1. event 相关子命令
参数名 | 别名 | 选填/必填 | 解释 |
---|---|---|---|
--distinct_id_from | -df | 必填 | 指定列作为 distinct_id |
--is_login | 选填 | distinct_id 是否是登录 ID,默认为否 | |
--event_from | -ef | 和 event_default 选一个必填 | 指定列作为事件名 |
--event_default | -ed | 和 event_from 选一个必填 | 指定固定字符串作为事件名 |
--timestamp_from | -tf | 和 timestamp_default 选一个必填 | 指定列作为 time |
--timestamp_default | -td | 和 timestamp_from 选一个必填 | 指定固定时间字符串作为 time |
--timestamp_format | -tf | 选填 | 和 timestamp_from 一起使用,通过此配置指定时间格式。默认是%Y-%m-%d %H:%M:%S |
3.3.2. profile 相关子命令
参数名 | 别名 | 选填/必填 | 解释 |
---|---|---|---|
--distinct_id_from | -df | 必填 | 指定列作为 distinct_id |
--is_login | 选填 | distinct_id 是否是登录 ID,默认为否 |
3.3.3. item 相关子命令
参数名 | 别名 | 选填/必填 | 解释 |
---|---|---|---|
--item_type | 必填 | 指定列作为 item_type | |
--item_id | 必填 | 指定列作为 item_id |
3.3.4. signup 相关子命令
参数名 | 别名 | 选填/必填 | 解释 |
---|---|---|---|
--login_id_from | 必填 | 指定列作为登录 ID | |
--anonymous_id_from | 必填 | 指定列作为匿名 ID |
3.4. 导入 CSV 格式的其他参数
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--filename | -f | 是 | CSV 文件路径。 |
--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 选中,会自动在程序的最后把中英文的映射关系填上去,这样在神策分析页面上看到对应属性显示名就是中文的了。 |
--web_url | -w | 如果选择 add_cname 则必填 | 神策分析页面的地址 ,单机版类似 http://localhost:8007/, cloud 版类似 http://xxx.cloud.sensorsdata.cn。 |
--username | -u | 如果选择 add_cname 则必填 | 神策分析登录用户名。 |
--password | -p | 如果选择 add_cname 则必填 | 神策分析登录密码。 |
--csv_delimiter | 否 | CSV 文件的列分隔符,默认为 ',',只接受单字符参数,也可以传 \ + ascii的数字,比如 \9 表示是 \t 。 | |
--csv_quotechar | 否 | CSV 文件的引用字符,用于指定CSV字符串的开始和结尾,默认为 '"',只接受单字符参数,也可以传 \ + ascii的数字,比如 \9 表示是 \t 。 | |
--csv_prefetch_lines | 否 | CSV 文件预读行数,预读用于判断列的类型,默认为 -1,即预读整个文件。注意如果数据分布不均(比如前几行某个字段没有但是后面有)不要加这个参数。 | |
--file_encoding | 否 | 设置 CSV 文件编码格式,默认为 utf-8。 | |
--list_type | 否 | 指定属性为 list 用逗号分割选取的属性,举例--list_type list_a, list_b 将会将 list_a 和 list_b 两列作为 list 格式导入。list_type:list_a, list_b list 格式数据需要以 | 分割,举例: 1|2|3 |
3.5. 导入 Nginx 日志的其他参数
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--filename | -f | 是 | Nginx 日志文件路径。 |
--log_format | -F | 是 | Nginx 日志配置,类似 '"$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 一一对应。 |
3.6. 导入 MySQL 数据的其他参数
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--user | -u | 是 | 连接 MySQL 数据库所需的用户名。 |
--password | -p | 是 | 连接 MySQL 数据库所需的密码。 |
--host | -i | 是 | 连接 MySQL 数据库所需的地址。 |
--port | -P | 是 | 连接 MySQL 数据库所需的端口。 |
--db | -d | 是 | MySQL 对应的数据库名,一次只能指定一个。 |
--sql | -q | 和 filename 选一个必填 | 查询语句,建议加 order by 等方式保证多次查询结果顺序一致。 |
--filename | -f | 和 sql 选一个必填 | 查询语句所在的文件路径,建议加 order by 等方式保证多次查询结果顺序一致。 |
--bool_property_list | -bp | 否 | 逗号分割的 bool 类型属性列表,会将对应的属性值为 1 的转化为 true,0 转化为 false。 |
--case_sensitive | -cs | 否 | 导入的属性名是否是大小写敏感,注意如果大小写不敏感会全部转化为大写,默认为 true。 |
3.7. 导入 JSON 日志的其他参数
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--path | -p | 是 | 日志的文件/目录路径 |
注意导入 JSON 日志,如果传递了日志目录,那么会遍历该目录下一级的所有的文件,并且按照字母顺序导入。本参数不支持嵌套目录。
3.8. 导入 Oracle 数据的其他参数
参数名 | 别名 | 是否必填 | 解释 |
---|---|---|---|
--user | -u | 是 | 连接 Oracle 数据库所需的用户名。 |
--password | -p | 是 | 连接 Oracle 数据库所需的密码。 |
--dsn | -dsn | 是 | 连接 Oracle 数据库所需的 dsn。 |
--sql | -q | 和 filename 选一个必填 | 查询语句,建议加 order by 等方式保证多次查询结果顺序一致。 |
--filename | -f | 和 sql 选一个必填 | 查询语句所在的文件路径,建议加 order by 等方式保证多次查询结果顺序一致。 |
--bool_property_list | -bp | 否 | 逗号分割的 bool 类型属性列表,会将对应的属性值为 1 的转化为 true,0 转化为 false。 |
--case_sensitive | -cs | 否 | 导入的属性名是否是大小写敏感,注意如果大小写不敏感会全部转化为大写,默认为 false。 |
4. 常见问题
1、CSV 的表头是中文是否可以支持
根据在.数据格式 v1.13里面的说明,property 的名称是不可以包含中文的,但是可以设置 property 在神策分析的属性显示名,通过配置 --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豪华版 欧版行货 全新未拆,音像
导入参数如下:
python3 format_importer.py csv_event \
--url 'http://localhost:8106/sa?project=xxx' \
--event_default 'UserBuy' \
--distinct_id_from '用户名' \
--is_login \
--timestamp_from '购买时间' \
--filename 'buy.csv' \
--add_cname \
--web_url 'http://localhost:8107' \
--username admin \
--password password
注意在不同的平台上对编码要求不同,需要保证默认编码和文件编码一致,具体请参考 Windows 下使用说明。
其中 web_url 与 url 基本一致,只有端口号不同,url 获取方式见上文。
2、如何配置 Nginx 可以过滤掉静态文件?
假设 Nginx 日志中包含了对 gif 文件,css 文件和 js 文件的请求,这些请求希望过滤掉,可以使用 --filter_path 来过滤。
python3 format_importer.py nginx_event \
--filter_path '.*\.gif' \
--filter_path '.*\.css' \
--filter_path '.*\.js' \
# 其他参数。。。
3、导入了一半出错了怎么办?
当出现解析数据出错时,导入工具会直接在终端打印错误原因和错误的行数,然后丢弃错误数据继续处理。打印日志类似:
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
在运行结束的时候会打印读取 (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}.
如果希望能够出错就提示,可以增加选项 --quit_on_error,这样的话出错了的日志如下:
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!
注意下方提示,说明已经成功导入了 11 行,修复第 12 行的数据后在之前的命令上再加上参数 --skip_cnt 11 即可。
需要特别说明的是,对于 MySQL,为了防止数据错误后不可恢复的问题,请务必保证查询 SQL 多次调用结果一致,即:
- 没有新数据在写入,比如通过增加 WHERE 保证只导入历史数据。
- 查询结果增加排序选项保证顺序一致,比如增加 ORDER BY。
4、用 MySQL 将两张表 join 起来导入,明明有数据为什么提示我 distinct_id / timestamp / event 为空?
注意如果 SQL 涉及到两个表 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、用 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 的值转化为数值。
6、如何导入其他项目
如果没有显示指定 project,则导入默认的项目 default。
可以通过 --url 里面包含 project=<project_name> 来指定 project 名,也可以通过 --project 参数来指定。如果同时指定则采用 --project 的参数。
注意,如果 --url 的值是通过右上角 “账号” -> “数据接入” -> “复制数据接收地址” 来获取的话,则复制的接口里面自带 project 参数,不需要额外指定。
此外,如果是导入 JSON 日志,可以在 JSON 中增加 "project":"project名称" 来使用一份数据导入多个 project。日志里面的 project 字段优先级高于参数。
7、CSV 如何转义
CSV 是用逗号分割的文件格式,如果某一列的内容中包含逗号,需要用双引号分割开,否则 FormatImporter 将会报错。举例,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
将会被识别为:
col1 | col2 | col3 |
a | b,c | d |
注意双引号可以跨行。举例,CSV 文件内容如下:
col1,col2,col3 a,"b,c d,e",f
将会被识别为:
col1 | col2 | col3 |
a | b,c,d,e | f |
因此如果某一列以双引号开头,那么 CSV 会一直找到下一个双引号结尾。如果两个双引号直接的字符过多,会报错列超长:
_csv.Error: field larger than field limit (131072)
解决方法有两个,一个是可以通过 --csv_quotechar 参数替换 CSV 默认的字符串边界符号,需要保证这个符号没有出现过。 另外就是对双引号转义,需要把一个双引号变成两个,并且对本列用双引号引住。举例,CSV 文件内容如下:
col1,col2,col3 a,"""b",c
将会识别为:
col1 | col2 | col3 |
a | "b | c |
8、Windows下使用说明
在 Windows 下使用 FormatImporter 时,由于终端的语法不同,默认编码不同,有以下几个注意事项:
1. 尽量使用配置文件传递参数,而不是命令行传递,避免命令转义。注意上述示例中的命令都是基于 Unix 操作系统,如果直接在 Windows 下面运行可能会出现语法错误或转义。
2. CSV 文件默认支持 utf-8 编码,如果出现编码错误,可以先查看文件编码格式,然后使用 --file_encoding 命令设置编码格式
3. 如果需要在 windows 下访问 MySQL / Oracle,需要对编码做特殊处理,具体处理方式请咨询神策技术支持同学。
9、导入限制
导入数据时,FormatImporter 导入本身没有数据量上限,但是如果导入数据较大时,速度较慢,大约 1 分钟导入 500~700 条左右,且导入的速度和网络稳定性有关,如果导入超时,可以尝试下使用内网数据接收地址
注:本文档内容为神策产品使用和技术细节说明文档,不包含适销类条款;具体企业采购产品和技术服务内容,以商业采购合同为准。