目录
前言
归因用于判断是什么原因促使用户下载应用,或在激活应用后进行各种操作(如再次打开或重新安装)。归因结果分为以下两种:
- 非自然流量:用户与媒体渠道进行了互动(通常通过展示或点击来完成)
- 自然流量:用户没有与媒体渠道进行互动。请注意:为了便于理解,我们经常会使用“该用户被归因为自然流量”这样的表达,但是严格来说这种说法是不准确的,因为自然流量不会被归因。
归因能极大地推动拉新和促活的优化,并提升优化效果。
一、基本概念
归因(Attribution)是指采用标识符来识别用户的转化路径,并判断其中的有效触点价值。广告平台基于归因结果,进行付费;广告主则可用于投放策略的优化。
二、归因方法
1.1. 自归因
当用户激活应用或打开落地页/小程序时,由于已携带渠道来源信息,无需再与广告点击进行匹配。这种广告追踪的方法,我们称之为自归因。
1.2. 方法二:点击归因
通过匹配广告点击与首个转化行为,实现广告追踪的方法,我们称之为点击归因。
点击归因常见于应用推广场景。例如,在推广应用时,由于用户点击广告和打开应用存在不同平台、时间的割裂,需要将二者进行归因匹配,从而识别渠道来源。
1.3. 方法三:曝光归因
通过匹配广告曝光与首个转化行为,实现广告追踪的方法,我们称之为曝光归因。曝光归因由于有数据量极大、支持曝光监测的渠道少等情况,不会使用此项。
三、归因匹配方式
精准匹配
逻辑说明:媒体渠道[巨量,广点通,百度]可读取用户的设备信息,并在用户点击广告时将设备信息发送至广告主平台。广告主平台将SDK获取到的设备信息与媒体渠道发送的设备信息进行匹配,串联广告事件与后续行为事件,最终完成归因。
注意:对于部分渠道,可通过广告唯一标识ID进行精准匹配,如腾讯广告可在网页推广中使用click_id进行精准匹配。
可用于设备信息精准匹配字段的有以下几种:
1、常用设备ID字段:
设备类型 | 设备ID字段 | 含义 | 优先级 |
---|---|---|---|
iOS设备 | IDFA | 设备唯一标识符,苹果官方唯一允许广告获取用户的信息 | IDFA > IDFV |
IDFV | 给Vendor(应用提供商)标识用户用的标识符,每个设备在所属同一个Vender的应用里,都有相同的值 | ||
Android设备 | OAID | OAID全称是Open Anonymous Device Identifier,中文名是匿名设备标识符。 OAID是一种非永久性设备标识符,最长64位,在系统首次启动的时候生成 | OAID > AndroidID > IMEI > GAID |
AndroidID | ANDROID_ID是设备首次启动时由系统随机生成的一串64位的十六进制数字 | ||
IMEI | 国际移动设备识别码(International Mobile Equipment Identity,IMEI),即通常所说的手机序列号、手机“串号”,用于在移动电话网络中识别每一部独立的手机等移动通信设备,相当于移动电话的身份证。 | ||
GAID | Google Play service提供给用户的可以重置的唯一广告id,通常也被用来作为设备的唯一标识,用于数据收集。 | ||
Mac | Mac | 手机的网卡地址 |
2、广告唯一标识:如click_id
模糊匹配
逻辑说明:将用户点击广告时、激活时的IP+UA等设备信息进行相似度匹配,用于模糊匹配的设备信息包括:IP、User_Agent、Model、Os_version等。
常用模糊匹配字段如下:
字段 | 含义 |
---|---|
IP | 分配给用户上网使用的网际协议(全称Internet Protocol, 简称IP)的设备的数字标签 |
User_Agent | 一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等 |
Model | 通常指设备型号,不同厂商设备型号标识各有差异 |
Os_version | 通常指操作系统版本,不同厂商操作系统版本各有差异 |
四、服务架构实现
-
流程图整体说明
领域建模
数据库表设计
click:广告点击表:按天分表
字段 | 类型 | 描述 |
---|---|---|
id | BIGINT(20) | 主键 |
app_id | INT | 应用ID |
channel | VARCHAR(32) | 渠道 |
oaid | VARCHAR(64) | Android Q及更高版本的设备号,32位 |
imei | VARCHAR(64) | 用户代理(User Agent),一个特殊字符串头 |
android_id | VARCHAR(64) | 安卓id原值的md5,32位 |
mac | VARCHAR(64) | 移动设备mac地址,转换成大写字母,去掉“:”,并且取md5摘要后的结果 |
ip | VARCHAR(64) | |
ua | VARCHAR(64) | 用户代理(User Agent),一个特殊字符串头 |
callback | VARCHAR(256) | 直接把调用事件回传接口的url生成出来,广告主可以直接使用 |
data | TEXT | JSON冗余字段 |
create_time | DATETIME | 创建时间 |
ascribe:归因表
字段 | 类型 | 描述 |
---|---|---|
id | BIGINT(20) | 主键 |
app_id | INT | 应用ID |
channel | VARCHAR(32) | 渠道 |
oaid | VARCHAR(64) | Android Q及更高版本的设备号,32位 |
imei | VARCHAR(64) | 用户代理(User Agent),一个特殊字符串头 |
android_id | VARCHAR(64) | 安卓id原值的md5,32位 |
mac | VARCHAR(64) | 移动设备mac地址,转换成大写字母,去掉“:”,并且取md5摘要后的结果 |
ip | VARCHAR(64) | |
ua | VARCHAR(64) | 用户代理(User Agent),一个特殊字符串头 |
callback | VARCHAR(256) | 直接把调用事件回传接口的url生成出来,广告主可以直接使用 |
data | TEXT | JSON冗余字段 |
create_time | DATETIME | 创建时间 |
ascribe_time | DATETIME | 归因时间 |
user_id | bigint(20) | 用户ID |
conversion:转化表
字段 | 类型 | 描述 |
---|---|---|
id | BIGINT(20) | 主键 |
ascribe_id | BIGINT(20) | 归因ID |
user_id | BIGINT(20) | 用户ID |
conversion_type | TINYINT(2) | 转化类型 1:激活 2:注册 3:次留 4:关键行为 |
status | TINYINT(2) | 回传状态 0:未回传 1:已回传 |
create_time | DATETIME | 创建时间 |
转化规则配置表conversion_config
字段 | 类型 | |
id | INT(10) | 主键 |
channel_type | VARCHAR(32) | 渠道 |
product_type | INT(11) | 产品 |
agent | VARCHAR(32) | 代理 |
advertiser_id | VARCHAR(32) | 账号 |
percentage | INT(6) | 百分比 |
conversion_type | VARCHAR(64) | 转换类型 字符串拼接 |
转化规则脚本表conversion_groovy
字段 | 类型 | 描述 |
id | INT(10) | 主键 |
business_id | INT(10) | 业务ID |
business_type | INT(10) | 业务类型 1:用户回传表 2:用户事件回传 |
groovy_code | VARCHAR(64) | 模版code |
condition_json | VARCHAR(1024) | 条件 |
五、转化设计
转化流程图
转化扩展点
动态脚本设计
//循环执行Groovy
for (LaunchScriptDTO scriptDTO : launchScripts) {
Map<String, Object> data = this.buildMap(request, scriptDTO);
String groovyCode = scriptDTO.getGroovyCode();
log.warn("groovy>>>>>template-map={},templateCode={}", JSON.toJSONString(data), groovyCode);
GroovyObject groovyObject = groovyRepository.getByCode(groovyCode);
Invocation invocation = new Invocation(groovyObject, "match", new Object[]{data});
Object result = invocation.proceed();
log.warn("groovy>>>>>templateCode={},result={}", groovyObject, JSON.toJSONString(result));
}
六、创意报表
渠道创意流程图
渠道创意数据抓取类图
代码
ReportGetExtPt:
/**
* 获取日报表
*
* @author yangyanping
* @date 2023-12-25
*/
public interface ReportGetExtPt extends ExtensionPointI {
ReportGetResponse query(ReportGetRequest request);
}
百度渠道扩展点实现类:
/**
* 广点通日创意查询
*
* @author yangyanping
* @date 2023-12-25
*/
@Slf4j
@Extension(bizId = BIZ_ID_REPORT_GET, useCase = "baidu")
public class BaiduReportGetExt implements ReportGetExtPt {
@Override
public ReportGetResponse query(ReportGetRequest request) {
return null;
}
}
巨量扩展点实现类
/**
* 巨量日创意查询
*
* @author yangyanping
* @date 2023-12-25
*/
@Slf4j
@Extension(bizId = BIZ_ID_REPORT_GET, useCase = "tt")
public class OceanengineReportGetExt implements ReportGetExtPt {
@Override
public ReportGetResponse query(ReportGetRequest request) {
return null;
}
}
测试代码:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = WebApplication.class)
public class ExtensionTest {
@Resource
private ExtensionExecutor executor;
@Test
public void test() {
ReportGetRequest request = new ReportGetRequest();
BizScenario bizScenario = BizScenario.valueOf(BizConstant.BIZ_ID_REPORT_GET, "baidu");
ReportGetResponse response = executor.execute(ReportGetExtPt.class, bizScenario, exe ->
exe.query(request)
);
}
}