# Java SDK 使用指南

提示

在接入前, 请先阅读接入前准备

您可以在 GitHub (opens new window) 获取 Java SDK 源码。

最新版本为:1.8.2

更新时间为:2021-08-31

# 一、集成并初始化 SDK

1.使用 Maven 集成 SDK,请在pom.xml文件中置入以下依赖信息(推荐):

<dependencies>
    // others...
    <dependency>
        <groupId>cn.thinkingdata</groupId>
        <artifactId>thinkingdatasdk</artifactId>
        <version>1.8.2</version>
    </dependency>
</dependencies>

2.使用 jar 包导入项目

Java SDK JAR 下载地址 (opens new window)

3.初始化 SDK

//初始化SDK两种方式,Consumer包括(LoggerConsumer,BatchConsumer,DebugConsumer
//默认
ta = ThinkingDataAnalytics(Consumer);
//添加UUID去重
bool enableUuid = true;
ta = ThinkingDataAnalytics(Consumer,enableUuid);

您可以通过三种方式获得 SDK 实例(建议初始化一次):

(1)LoggerConsumer: 批量实时写本地文件,文件以天为分隔,需要搭配 LogBus 进行上传

//使用LoggerConsumer,默认按天切分文件
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.LoggerConsumer(LOG_DIRECTORY));

如果您想按小时切分文件,您可以初始化代码如下:

//LoggerConsumer的配置类
ThinkingDataAnalytics.LoggerConsumer.Config config =new  ThinkingDataAnalytics.LoggerConsumer.Config(LOG_DIRECTORY);
//配置按小时切分,默认是RotateMode.DAILY 按天切分
config.setRotateMode(ThinkingDataAnalytics.LoggerConsumer.RotateMode.HOURLY);
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.LoggerConsumer(config));

如果您想按大小切分,您可以初始化代码如下:

//LoggerConsumer的配置类
ThinkingDataAnalytics.LoggerConsumer.Config config =new  ThinkingDataAnalytics.LoggerConsumer.Config(LOG_DIRECTORY);
//设置在按天切分的前提下,按大小切分文件,单位是M,例如设置2G切分文件
config.setFileSize(2*1024);
//设置生成的文件前缀
config.setFilenamePrefix("prefix");
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.LoggerConsumer(config));

LOG_DIRECTORY为写入本地的文件夹地址,您只需将 LogBus 的监听文件夹地址设置为此处的地址,即可使用 LogBus 进行数据的监听上传。

(2)BatchConsumer: 批量实时地向 TA 服务器传输数据,不需要搭配传输工具,因网络问题发送失败时会重试3次,仍然失败将会把数据存入缓存区,可设置缓存区大小,默认50,即缓存区保留的数据总数最大为50*20(20为每次上传的batch值,可设置)。在长时间网络中断情况下,有数据丢失的风险。

//使用BatchConsumer的配置类
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.BatchConsumer(SERVER_URI, APP_ID));

如果您想设置数据压缩方式,您可以初始化代码如下:

//BatchConsumer
ThinkingDataAnalytics.BatchConsumer.Config batchConfig = new ThinkingDataAnalytics.BatchConsumer.Config();
//可配置压缩方式为:gzip,lzo,lz4,none,默认压缩方式为gzip,内网可以使用none
batchConfig.setCompress("gzip");
//可配置连接超时时间,单位ms
batchConfig.setTimeout(10000);//10s
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.BatchConsumer(SERVER_URI, APP_ID,batchConfig));

如果您想设置数据 flush 条数,您可以初始化代码如下:

//BatchConsumer
ThinkingDataAnalytics.BatchConsumer.Config batchConfig = new ThinkingDataAnalytics.BatchConsumer.Config();
//数据主动flush到TA系统默认是20条,可进行如下配置
 batchConfig.setBatchSize(30);//flush条数,默认20,默认上限7000条
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.BatchConsumer(SERVER_URI, APP_ID,batchConfig));

SERVER_URI为传输数据的 uri,APP_ID为您的项目的 APP ID

如果您使用的是云服务,请输入以下 URL:

http://receiver.ta.thinkingdata.cn

如果您使用的是私有化部署的版本,请输入以下 URL:

http://数据采集地址

注:1.4.0 版本之前输入以下 URL:

http://receiver.ta.thinkingdata.cn/logagent
http://数据采集地址/logagent

(3)DebugConsumer: 逐条实时地向 TA 服务器传输数据,不需要搭配传输工具,如果数据出现错误,整条数据都将不会入库,并且返回详细的错误说明,不建议在正式环境中使用

ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.DebugConsumer(SERVER_URI, APP_ID));

如果您不想数据入库,只想校验数据格式,您可以初始化代码如下:

//默认是true
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.DebugConsumer(SERVER_URI, APP_ID,false));

SERVER_URI为传输数据的 uri,APP_ID为您的项目的 APP ID

如果您使用的是云服务,请输入以下 URL:

http://receiver.ta.thinkingdata.cn

如果您使用的是私有化部署的版本,请输入以下 URL:

http://数据采集地址

# 二、发送数据

在 SDK 初始化完成之后,您就可以调用track来上传事件,一般情况下,您可能需要上传十几到上百个不同的事件,如果您是第一次使用 TA 后台,我们推荐您先上传几个关键事件。

如果您对需要发送什么样的事件有疑惑,可以查看快速使用指南了解更多信息。

# 2.1 发送事件

您可以调用track来上传事件,建议您根据先前梳理的文档来设置事件的属性以及发送信息的条件,此处以用户付费作为范例:

//初始化SDK
ThinkingDataAnalytics ta = new ThinkingDataAnalytics(new ThinkingDataAnalytics.BatchConsumer(SERVER_URI, APP_ID));

//设置访客ID"ABCDEFG123456789"
String distinct_id = "ABCDEFG123456789";

//设置账号ID"TA_10001"
String account_id = "TA_10001";

//设置事件属性
Map<String,Object> properties = new HashMap<String,Object>();

// 设置事件发生的时间,如果不设置的话,则默认使用为当前时间
properties.put("#time", new Date());

// 设置用户的ip地址,TA系统会根据IP地址解析用户的地理位置信息,如果不设置的话,则默认不上报
properties.put("#ip", "192.168.1.1");

properties.put("Product_Name", "商品A");
properties.put("Price", 30);
properties.put("OrderId", "订单号abc_123");

//
上传事件,包含用户的访客ID与账号ID,请注意不要将访客ID与账号ID写反
try {
            ta.track(account_id,distinct_id,"payment",properties);
            ta.flush();
        } catch (Exception e) {
		   //异常处理
            System.out.println("except:"+e);
     }

注: 为了保证访客 ID 与账号 ID 能够顺利进行绑定,如果您的游戏中会用到访客 ID 与账号 ID,我们极力建议您同时上传这两个 ID,否则将会出现账号无法匹配的情况,导致用户重复计算,具体的 ID 绑定规则可参考用户识别规则一章。

  • 事件的名称是String类型,只能以字母开头,可包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感。
  • 事件的属性是一个Map<String,Object>对象,其中每个元素代表一个属性。
  • Key 的值为属性的名称,为String类型,规定只能以字母开头,包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感。
  • Value 为该属性的值,支持StringNumberBooleanDateList

# 2.2 设置公共事件属性

对于一些需要出现在所有事件中的属性,您可以调用setSuperProperties将这些属性设置为公共事件属性,公共事件属性将会添加到所有使用track上传的事件中。

Map<String, Object> superProperties = new HashMap<String,Object>();
//设置公共属性:服务器名称
superProperties.put("server_name", "S10001");
//设置公共属性:服务器版本
superProperties.put("server_version", "1.2.3");
//设置公共事件属性
ta.setSuperProperties(superProperties);

Map<String,Object> properties = new HashMap<String,Object>();
//设置事件属性
properties.put("Product_Name", "商品A");
properties.put("Price", 30);
//上传事件,此时事件中将带有公共属性以及该事件的属性
try {
            ta.track(account_id,distinct_id,"payment",properties);
        } catch (Exception e) {
		   //异常处理
            System.out.println("except:"+e);
     }

/** 相当于在每个事件中加入这些属性
 *  properties.clear();
 *  properties.put("server_name", "S10001");
 *  properties.put("server_version", "1.2.3");
 *  properties.put("Product_Name", "商品A");
 *  properties.put("Price", 30);
 *try {
 *        ta.track(account_id,distinct_id,"payment",properties);
 *       } catch (Exception e) {
 *		   //异常处理
 *          System.out.println("except:"+e);
 *   }
 */
  • 公共事件属性同样也是一个Map<String, Object>对象,其中每个元素代表一个属性。
  • Key 的值为属性的名称,为String类型,规定只能以字母开头,包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感。
  • Value 为该属性的值,支持StringNumberBooleanDateList

如果调用setSuperProperties设置先前已设置过的公共事件属性,则会覆盖之前的属性值。如果公共事件属性和track上传事件中的某个属性的 Key 重复,则该事件的属性会覆盖公共事件属性:

Map<String, Object> superProperties = new HashMap<String,Object>();
superProperties.put("server_name", "S10001");
superProperties.put("server_version", "1.2.3");
//设置公共事件属性
ta.setSuperProperties(superProperties);


superProperties.clear();
superProperties.put("server_name", "Q12345");
//再次设置公共事件属性,此时"server_name"被覆盖,值为"Q12345"
ta.setSuperProperties(superProperties);

Map<String,Object> properties = new HashMap<String,Object>();
properties.put("Product_Name", "商品A");
//设置与公共事件属性重复的属性
superProperties.put("server_version", "1.2.4");
//上传事件,此时"server_version"的属性值会被覆盖为"1.2.4","server_name"的值为"Q12345"

try {
           ta.track(account_id,distinct_id,"payment",properties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

如果您想要清空所有公共事件属性,可以调用clearSuperProperties

# 三、用户属性

TA 平台目前支持的用户属性设置接口为 user_set、user_setOnce、user_add、user_del。

# 3.1 user_set

对于一般的用户属性,您可以调用user_set来进行设置,使用该接口上传的属性将会覆盖原有的属性值,如果之前不存在该用户属性,则会新建该用户属性,类型与传入属性的类型一致,此处以设置用户名为例:

Map<String,Object> userSetProperties = new HashMap<String,Object>();
userSetProperties.put("user_name", "ABC");
userSetProperties.put("#time",new Date());

//上传用户属性
try {
          ta.user_set(account_id,distinct_id,userSetProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }
userSetProperties.clear();
userSetProperties.put("user_name","abc");
userSetProperties.put("#time",new Date());

//再次上传用户属性,此时"user_name"的值会被覆盖为"abc"
try {
         ta.user_set(account_id,distinct_id,userSetProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

user_set设置的用户属性是一个Map<String,Object>对象,其中每个元素代表一个属性。
Key 的值为属性的名称,为String类型,规定只能以字母开头,包含数字,字母和下划线“_”,长度最大为 50 个字符,对字母大小写不敏感。
Value 为该属性的值,支持StringNumberBooleanDateList

# 3.2 user_setOnce

如果您要上传的用户属性只要设置一次,则可以调用user_setOnce来进行设置,当该属性之前已经有值的时候,将会忽略这条信息,再以设置用户名为例:

Map<String,Object> userSetOnceProperties = new HashMap<String,Object>();
userSetOnceProperties.put("user_name", "ABC");
userSetOnceProperties.put("#time",new Date());

//上传用户属性,新建"user_name",值为"ABC"
try {
        ta.user_setOnce(account_id,distinct_id,userSetOnceProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

userSetOnceProperties.clear();
userSetOnceProperties.put("user_name","abc");
userSetOnceProperties.put("user_age",18);
userSetOnceProperties.put("#time",new Date());

//再次上传用户属性,此时"user_name"的值不会被覆盖,仍为"ABC";"user_age"的值为18
try {
        ta.user_setOnce(account_id,distinct_id,userSetOnceProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

user_setOnce设置的用户属性类型及限制条件与user_set一致。

# 3.3 user_add

当您要上传数值型的属性时,您可以调用user_add来对该属性进行累加操作,如果该属性还未被设置,则会赋值 0 后再进行计算,可传入负值,等同于相减操作。此处以累计付费金额为例:

Map<String,Object> userAddProperties = new HashMap<String,Object>();
userAddProperties.put("total_revenue",30);
userAddProperties.put("#time",new Date());

//上传用户属性,此时"total_revenue"的值为30
try {
        ta.user_add(account_id,distinct_id,userAddProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

userAddProperties.clear();
userAddProperties.put("total_revenue",60);
userAddProperties.put("#time",new Date());

//再次上传用户属性,此时"total_revenue"的值会累加为90
try {
        ta.user_add(account_id,distinct_id,userAddProperties);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

user_add设置的用户属性类型及限制条件与user_set一致,但只支持传入数值型的用户属性。

# 3.4 user_append

当您要为 list 类型追加用户属性值时,您可以调用user_append来对指定属性进行追加操作,如果该属性还未在集群中被创建,则user_append创建该属性

        List<String> appendList1 = new ArrayList<>();
        appendList1.add("12.2");
        appendList1.add("str");
        properties.put("arr1", appendList1);//为arr1的数组类型追加属性
        List<String> appendList2 = new ArrayList<>();
        appendList2.add("2");
        appendList2.add("true");
		properties.put("arr2", appendList2);//为arr2的数组类型追加属性
		try {
            tga.user_append(account_id, distinct_id, properties);
        } catch (Exception e) {
            //异常处理
            System.out.println("except:"+e);
        }

# 3.5 user_unset

当您要清空用户的用户属性值时,您可以调用user_unset来对指定属性进行清空操作,如果该属性还未在集群中被创建,则user_unset不会创建该属性

// 重置单个用户属性
try {
        ta.user_unset("key1");
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

// 重置多个用户属性
try {
      ta.user_unset("key1", "key2", "key3");
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

// 重置多个用户属性,传入字符串数组
String[] keys = {"key1", "key2"};
try {
        ta.user_unset(keys);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

# 3.6 user_del

如果您要删除某个用户,可以调用user_del将这名用户删除,您将无法再查询该名用户的用户属性,但该用户产生的事件仍然可以被查询到,该操作可能产生不可逆的后果,请慎用

try {
        ta.user_del(account_id,distinct_id);
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

# 四、其他操作

# 4.1 立即提交数据

ta.flush();

立即提交数据到相应的接收器

# 4.2 关闭 sdk

try {
       ta.close();
      } catch (Exception e) {
		   //异常处理
           System.out.println("except:"+e);
     }

关闭并退出 sdk,请在关闭服务器前调用本接口,以避免缓存内的数据丢失

# 五、相关预置属性

# 5.1 所有事件带有的预置属性

以下预置属性,是 Java SDK 中所有事件(包括自动采集事件)都会带有的预置属性

属性名 中文名 说明
#ip IP 地址 用户的 IP 地址,需要进行手动设置,TA 将以此获取用户的地理位置信息
#country 国家 用户所在国家,根据 IP 地址生成
#country_code 国家代码 用户所在国家的国家代码(ISO 3166-1 alpha-2,即两位大写英文字母),根据 IP 地址生成
#province 省份 用户所在省份,根据 IP 地址生成
#city 城市 用户所在城市,根据 IP 地址生成
#lib SDK 类型 您接入 SDK 的类型,如 Java 等
#lib_version SDK 版本 您接入 Java SDK 的版本

# 六、进阶功能

从 v1.6.0 开始,SDK 支持上报两种特殊类型事件: 可更新事件、可重写事件。这两种事件需要配合 TA 系统 2.8 及之后的版本使用。由于特殊事件只在某些特定场景下适用,所以请在数数科技的客户成功和分析师的帮助下使用特殊事件上报数据。

# 6.1 可更新事件

您可以通过可更新事件实现特定场景下需要修改事件数据的需求。可更新事件需要指定标识该事件的 ID,并在创建可更新事件对象时传入。TA 后台将根据事件名和事件 ID 来确定需要更新的数据。

// 示例: 上报可被更新的事件,假设事件名为 UPDATABLE_EVENT
Map<String, Object> properties = new HashMap<>();
properties.put("price",100);
properties.put("status",3);
// 上报后事件属性 status 为 3, price 为 100
ta.track_update(account_id, distinct_id,"UPDATABLE_EVENT","test_event_id",properties);

// 上报后同样test_event_id + UPDATABLE_EVENT 的事件属性 status 被更新为 5, price 不变
Map<String, Object> protertiesNew = new HashMap<>();
protertiesNew.put("status",5);
ta.track_update(account_id, distinct_id, "UPDATABLE_EVENT", "test_event_id", protertiesNew);

# 6.2 可重写事件

可重写事件与可更新事件类似,区别在于可重写事件会用最新的数据完全覆盖历史数据,从效果上看相当于删除前一条数据,并入库最新的数据。TA 后台将根据事件名和事件 ID 来确定需要更新的数据。

// 示例: 上报可被重写的事件,假设事件名为 OVERWRITE_EVENT
Map<String, Object> properties = new HashMap<>();
properties.put("price",100);
properties.put("status",3);
// 上报后事件属性 status 为 3, price 为 100
ta.track_overwrite(account_id, distinct_id, "OVERWRITE_EVENT","test_event_id", properties);

Map<String, Object> protertiesNew = new HashMap<>();
protertiesNew.put("status",5);

// 上报后事件属性 status 被更新为 5, price 属性被删除
ta.track_overwrite(account_id, distinct_id, "OVERWRITE_EVENT", "test_event_id", protertiesNew);

# 6.3 首次事件校验功能

使用”首次事件校验“特性,需要在properties中设置#first_check_id字段,类型为字符串,该字段是校验首次事件的标识 ID,该 ID 首条出现的数据将入库,之后出现的都无法入库。不同事件的#first_check_id互相独立,因此每个事件的首次校验互不干扰

// 示例: 上报可被重写的事件,假设事件名为 OVERWRITE_EVENT
Map<String, Object> properties = new HashMap<>();
properties.put("price",100);
properties.put("status",3);
properties.put("#first_check_id","123456");
// 上报事件属性 
ta.track(account_id, distinct_id, "EVENT","test_event_id", properties);

# 6.4 定时刷新功能

默认情况下,JAVA SDK 只会根据当前的数据大小自动 flush(),默认超过 8K 时会调用一次 flush(),v1.7.0 版本增加定时刷新功能,BatchConsumer 和 LoggerConsumer 可以配置 Config 中的 interval 和 autoFlush 参数开启定时刷新功能。

ThinkingDataAnalytics.BatchConsumer.Config config = new ThinkingDataAnalytics.BatchConsumer.Config();
config.setAutoFlush(true);
//interval 定时时间,单位秒,默认值3
config.setInterval(5);
ThinkingDataAnalytics tga = new ThinkingDataAnalytics(new ThinkingDataAnalytics.BatchConsumer("http://localhost:8991", "APP_ID", config));

# ChangeLog

# v1.8.2 2021/08/31

  • 修复一处链接异常关闭的错误

# v1.8.1 2021/06/17

  • 更新httpclient版本
  • 增加异常日志

# v1.8.0 2021/03/22

  • 新增缓存池,用于存储因网络原因发送的数据,在后续发送时重试
  • LoggerConsumer增加支持#app_id属性

# v1.7.0 2020/12/08

  • 新增定时 flush 功能
  • 新增 LoggerConsumer 自动创建目录功能

# v1.6.0 2020/08/24

  • 新增 track_update 接口,支持可更新事件
  • 新增 track_overwrite 接口,支持可重写事件
  • 支持 LoggerConsumer 前缀名配置

# v1.5.3 2020/07/08

  • 修复 v1.5.2 找不到 fastjson 依赖问题

# v1.5.2 2020/07/07(废弃)

  • fastjson 版本号 1.2.44 变更到 1.2.71,修复用户使用该版本号出现反序列化漏洞
  • 修复 BatchConsumer 可能内存泄漏的问题

# v1.5.1 2020/04/21

  • 去除 #time 类型拦截

# v1.5.0 2020/02/10

  • 数据类型支持 list 类型
  • 新增 user_append 接口,支持用户的数组类型的属性追加

# v1.4.0 2020/01/06

  • 新增 user_unset 接口,支持删除用户属性
  • BatchConsumer 性能优化:支持配置压缩模式;移除 Base64 编码
  • DebugConsumer 优化: 在服务端对数据进行更完备准确地校验

# v1.3.1 2019/09/27

  • 去除 LooggerConsumer 默认文件大小的 1G 上限,用户可自行配置按天,小时,大小切分

# v1.3.0 2019/09/26

  • 去除 ProduceKafka,避免过多的依赖

# v1.2.0 2019/09/12

  • 新增 DebugConsumer,便于调试接口
  • 优化 LoggerConsumer,支持按小时切分日志文件
  • 优化代码,提升稳定性

# v1.1.17 2019/08/23

  • 优化数据上报异常时异常打印提示
  • BatchConsumer 请求异常返回码提醒

# v1.1.16 2019/05/30

  • 解决 LoggerConsumer 多线程下会出现关闭不 flush 数据的 bug
  • 解决 BatchConsumer 多线程下数据重复的情况

# v1.1.15 2019/04/28

  • 修复 Java 1.7 兼容性 bug
  • LoggerConsumer 不根据时间间隔落盘

# v1.1.14 2019/04/25

  • 兼容 Java 1.7
  • 优化了 loggerConsumer 的上报机制

# v1.1.13 2019/04/11

  • 优化数据上报的性能及稳定性
  • 调整了 Consumer 的默认参数

# v1.1.9 2018/09/03

  • BatchConsumer 新增异步传输功能,详情查看 API 文档