作者:闲鱼技术-云听
背景
在之前的文章中,我们介绍了纳米镜的功能和背后的分析算法,而闲鱼目前业务线多且复杂,怎么构建一个可扩展性强的系统,使每个业务线都能够便捷地接入,成为首要关注的问题。
思路分析
标准数据集
纳米镜的分析算法,输入输出是固定的,要求输入是一个固定的标准ODPS数据集,字段包含userid/分桶id/人群切面1/人群切面2/指标1/指标2等,但实际业务场景中,每个业务关注的人群切面与数据指标都是大相径庭的,为了在约束中寻找灵活性,我们必须对纳米镜的标准数据集做些改造。
由于纳米镜存在数据集依赖,比如说预测算法和切面显著性算法,就需要依赖具体的某张表去做二次计算,比较好的解决方案是让业务方按照数据集规范往标准数据集的中间表里面插数据。
数据集自动生成
只要让每个业务将自己的数据按照标准数据集的规范插入到纳米镜中间表中,就能开始使用纳米镜的功能。但实际场景中,业务产出数据集的开发成本很大,并且这种方式对使用方的开放权限很大,假如使用方不按照规范插入数据,会对源数据造成污染,使其变得不可控。那是否能做到数据集自动生成,让使用方不需要关注数据采集流程呢?
可以看看,在平常的业务开发流程中,生成ODPS数据源的工作流程是:
这整个过程下来,一般都会花费至少2天(1天埋点梳理与开发、1天写SQL生成报表)的时间,并且很多时候会出现埋点遗漏的问题,又需要重新走一遍开发和发布流程,造成很多人力上的浪费。
方案设计
标准数据源制定
数据集中的数据类型是固定的,数据类型下字段名称和值可以是灵活的。
在数据集上,我设计这种一种数据格式,参考:
userid: 用户userid
bucket_id:bucket_A
indexes: index_visit=1,index_ipv=2
tags: tag_sex=F,tag_age=19
业务数据集自动生成
行业成熟方案及缺点
数据自动生成,意味着上面提到的常规数据开发流程直接抹除,不需要关注埋点开发、也不需要跨专业领域去写SQL,页面只要一上线,活动数据就会自动存储到纳米镜的标准数据源中。要做到无埋点,业界有类似的方案,也叫做“全埋点”,自动采集坑位曝光点击,但这个方案的缺点很明显:
1、上传数据是dom节点位置信息,清洗麻烦,并且摆脱不了写SQL的工作
2、增加带宽、服务器压力(每个坑位的曝光点击,无论是否需要都会上传)
3、业务侵入太强(weex下要监听坑位曝光事件,模块开发时需引入定制组件)
4、携带不了trackparam信息(实际业务场景还会关注更多业务信息 eg.商品id/分桶/红包金额)
提取用户行为的最大公约数
本质上,业务关注的是用户行为。我对历史埋点开发的数据做了统计,梳理出业务关注的用户行为类型,包含点击跳转页面、红包曝光、红包领取、红包金额、分桶id、渠道等。并且发现,所有这些用户行为,底层都经过了页面跳转
/HTTP接口请求
/url传参
这几个API调用,如果API调用的输入输出是可固化的,那理解用户行为的业务语义并采集上报,就具备可能性!
最终方案
要做一个适用所有业务(闲鱼/手淘/天猫)的用户行为采集方案,技术实现上不可能,原因是每个业务自己的工程实现方案完全不同,也无法保持一致。不过对闲鱼来说,工程基建基本成熟稳定,具有业务语义的用户行为的API输入输出已固化,使实现一套只适用于闲鱼的用户行为自动采集技术方案具有了可能性。总体技术方案如下:
图中下半部分的虚线部分:产品展现侧本文不做太多扩展,本文主要讲上半部分的,从端侧用户行为采集到生成纳米镜标准数据源。
相比全埋点,它的特点是:
1、灵活配置
2、减少带宽、服务器计算压力
3、业务无侵入
4、可携带trackparam信息
落地
hook API
闲鱼前端封装了一个util,页面跳转(navigator)、http请求(mtop)都由它暴露出来给开发使用,具体调用方式是navigator.push()
、mtop.request()
。使用Proxy代理对这两个API进行hook。这里以navigator为例。
navigator['push'] = new Proxy(navigator['push'], {
get(target, propKey) {
return target[propKey];
},
set(target, propKey, value) {
target[propKey] = value;
return target[propKey];
},
apply(target, thisArg, args) {
// 先执行原逻辑
const result = target.apply(this, args);
// 是否指定忽略纳米镜分析
const ignoreNanoAnaly = args && args[0] && args[0].api && args[0].ignoreNanoAnaly;
if (ignoreNanoAnaly) {
return result;
}
if (result instanceof Promise && result.then) {
result.then(d => {
// 这里写入监听逻辑
// ...
return Promise.resolve(d);
}).catch(e => {
// 这里写入监听逻辑
// ...
return Promise.reject(e);
});
}
return result;
}
});
用户行为采集通用配置与可定制化配置
闲鱼目前已沉淀下成熟的一套用户行为采集通用配置,满足业务方数据分析时的各种数据指标诉求,并且,我们还支持定向扩展,可对具体的页面spmId定制自己个性化的用户行为指标,具体的配置参数与含义参考以下demo。
{
"spms": [{
"spm": "common", // 用户行为通用配置 会对所有页面产生的用户行为进行匹配
"tasks": [{
"indexType": 0, // 0代表指标 1代表bucket_id 2代表infos 3代表扩展信息 默认0 这里主要是需要与纳米镜的标准数据源建立映射关系
"index": "index__ipv", // 指标名称 IPV
"behavior": [
{
"type": 0, // 用户行为类型 0代表navigator 1代表mtop 2代表location.href
"condition": "fleamarket://item", // 正则匹配是否目标行为 type=navigator匹配下跳url;type=mtop匹配接口返回值 不校验填true
"valueType": "1" // 指标数值类型 0代表boolean 1代表count 字符串属性链代表对应取对应值
}
]
}]
}, {
"spm": "spma.spmb",
"match_uv": true, // 是否采集页面uv 默认指标名称是 index__visit
"tasks": [{
"indexType": 0,
"index": "index__gold_copper", // 金宝箱是否打开
"behavior": [{
"type": 1, // mtop接口请求的行为类型
"api": "mtop.api.lottery.draw", // 抽奖接口api名称
"condition": "d.data.status===5", // mtop返回值符合该正则匹配 则认为符合采集记录条件 status==5代表用户成功打开了金宝箱
"valueType": "0" // 是否领取成功 0/1
}]
}]
}]
}
行为聚合与上报
为了减少带宽和服务器计算压力,每次采集到的用户行为不会立即上报,而是把整个页面实例生命周期的用户行为做聚合,直到页面被销毁或者应用从前台切到后台15秒后做统一上报。
上面提到的demo,假设用户在spmId为spma.spmb
的页面点击跳转了10次商品详情页,并打开了金宝箱,最终上报到服务器日志的数据长这样:
{
"page": "spma.spmb",
"indexes": "index__visit=1,index__ipv=10,index__gold_copper=1"
}
效果
目前,已经有多个业务通过这种方式灵活轻便地接入纳米镜,eg. 边逛边赚钱、侃侃刀、报价单、322闲鱼大促等等,从原本要花费至少2人日的开发量,到只要活动上线,即可上手纳米镜查看活动智能分析结论,整体纳米镜使用体验和使用效率都获取了极大的提升。
未来
目前纳米镜设计的业务接入模式,已能够满足业务0成本接入,如果有更多定制化数据指标诉求,也支持低成本地动态配置。
未来,纳米镜会在数据科学的道路上深入钻研,现阶段我们更多在理解人,也在尝试从浩如烟海的历史活动中抽象沉淀知识库,并且开始尝试理解货,理解人与货之间的喜好关系,并建立人与货之间的匹配关系。
想了解更多细节,就请继续关注闲鱼公众号吧。