热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

access去重_Kylin精确去重在用户行为分析中的妙用

作者:史少锋,ApacheKylincommitter&PMC,20191011在上次文章《如何在1秒内做到大数据精准去重》中࿰
1fb3ee2e7f2412042a01bbf263d67a68.png

作者:史少锋,Apache Kylin committer & PMC,2019/10/11

在上次文章《如何在 1 秒内做到大数据精准去重》中,我们介绍了 Apache Kylin 为什么要支持大数据集上的精确去重,以及基于 Bitmap 的精确去重原理等。看到今天的文章标题,你肯定要问,精确去重跟用户行为分析又能有什么关系呢?原来啊,Kylin 采用 Bitmap 完整记录了每个维度组合下的用户集合,利用 Bitmap 提供的或(or)运算方法来高效精准地回答了各种条件下的去重用户数。其实 Bitmap 除了支持或(or)运算外,还支持与(and)运算。因此,稍加扩展,Kylin 就可以基于 Bitmap 的中间结果,轻松实现诸如留存、漏斗等大量使用交集运算的分析,从而非常方便地运用在用户行为、用户画像等领域中。可以说精确去重功能有着一石两鸟的价值,本文将为您介绍如何使用 Kylin 来实现精准的用户行为分析。

示例

先从一个简单的例子说起吧。现在有一个 app 的用户访问记录表 access_log,它包含三个字段:DT (访问日期),User ID(用户标示)和 Page(访问页):

c70165545e429207bce05124171e3436.png

△ 表 1:样例数据原始表

在 Kylin 里创建一个模型,选择 DT 和 Page 做维度,User ID 做度量;

a8ebb51ef9e7b3b32a70cbc743dd3de3.png
7e983630e26f5b94b90bfb63d6c7b867.png

然后创建一个 Cube,使用 DT 和 page 做维度,定义 count (distinct user_id) 度量且使用 Bitmap 为数据类型(关于 Kylin 的使用,参考 Apache Kylin 官网教程)。

17b16eb41a3ef99b1718e04532b338f0.png
f20eebdeb7277b80817a7269452833e8.png

这个 Cube 构建完成后,对于只包含 DT 维度的 Cuboid,它的数据结构如下:

8b4bd50cb128c3b323d7ad68d6a03c1d.png

△ 表 2:样例 Cube 1

注:上面的用户集合“User IDs”用的是易于阅读的数组格式,在实际存储中使用 Bitmap(位图)格式,也就是一组 0 或 1 的 bit 数组,如 [100,101,102] 就在第 100-102 位放 1,其它位放 0 代表。因此,Bitmap 不但非常省空间,而且非常适合计算机做交并集运算。

如果要计算某天或某几天的 UV,SQL 如下:

select dt, count(distinct user_id) from access_log where dt >&#61; &#39;20190101&#39; and dt <&#61; "20190103" group by dt

根据查询 Bitmap 的 Cardinality&#xff08;基数&#xff09;&#xff0c;获取到 UV 值&#xff1a;

5ae6a2e455a60d8c3aa7697ca98afa7a.png

△ 表 3&#xff1a;样例查询结果 1

留存分析

对于 App 的运营者来说&#xff0c;留存分析是一种常见的分析手段&#xff0c;常用于提升用户留存率&#xff0c;它的主要目标是找到影响用户留存的关键因素。因为获取用户是有一定成本的&#xff0c;如果新获取的用户大部分都留不住&#xff0c;那么拉新的投入产出比就会很低。通常会分析日留存、周留存和月留存。

以日留存为例&#xff0c;要计算第一天访问的用户中&#xff0c;有多少在第二天、第三天继续访问了 app。如果使用 HiveQL或 Spark SQL 来计算第一天和第二天的留存用户数&#xff0c;写法大致如下&#xff1a;

SELECT count(distinct first_day.USER_ID) FROM(select distinct USER_ID as USER_ID from access_log where DT &#61; &#39;20190101&#39;) as first_day INNER JOIN(select distinct USER_ID as USER_ID from access_log where DT &#61; &#39;20190102&#39;) as second_day ON first_day.USER_ID &#61; second_day.USER_ID

可以看出&#xff0c;使用 Hive/Spark 计算留存用户&#xff0c;需要先写多个子查询&#xff0c;分别计算出各日的用户集合&#xff0c;然后通过 inner join 的方式实现交集计算&#xff0c;最后在外层再做 count(distinct&#xff09;运算。在数据量很大的时候&#xff0c;这样的多个子查询的join会非常慢且容易内存溢出。

使用 Kylin 计算日&#xff0f;周&#xff0f;月留存

大家可以看到&#xff0c;其实拿这几日访问用户的 bitmap&#xff0c;相互做与&#xff08;and&#xff09;操作&#xff0c;就可以高效地得到留存数字&#xff0c;如“第一天”and“第二天”访问的用户&#xff1b;这样跟第一天的访问用户数做个比较&#xff0c;就可以计算出第二天留存率等。

为了便于在 SQL 中做“与”操作&#xff0c;Kylin 提供了一个自定义函数&#xff1a;“intersect_count”&#xff08;详见文末“参考”文章【2】&#xff09;。顾名思义&#xff0c;就是做交集以后的结果数。该函数用法如下&#xff1a;

intersect_count(columnToCount, columnToFilter, filterValueList)
其中&#xff1a;
&#96;columnToCount&#96; 要做计数的列&#xff0c;也就是bitmap存储的列&#xff0c;这里就是“user_id“
&#96;columnToFilter&#96; 做交集计算的列&#xff0c;如果是把多个不同日期的bitmap来做交集&#xff0c;那么这列就是日期&#xff1b;
&#96;filterValueList&#96; 做交集计算的bitmap的key值&#xff0c;需要是一个数组。

例如下面的 SQL 查询了’20190101′ 与 ‘20190102’这两天的交集用户数&#xff1a;

select intersect_count(user_id, dt, array[&#39;20190101&#39;, &#39;20190102&#39;])
from access_log
where dt in (&#39;20190101&#39;, &#39;20190102&#39;)

可以看出&#xff0c;使用 Kylin&#xff0c;一个 intersect_count 函数就可以完成多日用户集合的交集计算。这里where条件中也进行了日期的筛查&#xff0c;为的是减少从底层存储加载的数据。显然&#xff0c;相比于Hive 和 Spark SQL&#xff0c;Kylin 的用法更加简单明了&#xff0c;而且基于预计算的 Bitmap 做交集&#xff0c;比现场 join 效率高很多&#xff0c;可以做到秒级响应。

通过 Kylin 还可以很方便地在一条 SQL 中查询多日的 UV 及留存&#xff0c;避免反复查询&#xff0c;如&#xff1a;

select city, version,
intersect_count(user_id, dt, array[&#39;20161014&#39;]) as first_day_uv,
intersect_count(user_id, dt, array[&#39;20161015&#39;]) as second_day_uv,
intersect_count(user_id, dt, array[&#39;20161016&#39;]) as third_day_uv,
intersect_count(user_id, dt, array[&#39;20161014&#39;, &#39;20161015&#39;]) as retention_oneday,
intersect_count(user_id, dt, array[&#39;20161014&#39;, &#39;20161016&#39;]) as retention_twoday
from access_log
where dt in (&#39;2016104&#39;, &#39;20161015&#39;, &#39;20161016&#39;)
group by city, version
order by city, version

同理&#xff0c;如果 Cube 中有周、月做维度&#xff0c;那么这里把日期换成周、月就可以很方便地计算周留存、月留存了。

使用 Kylin 进行漏斗分析

漏斗分析&#xff0c;又叫转化漏斗&#xff0c;就是将一个特定过程的多个步骤间的转化情况&#xff0c;以漏斗的形式展示出来&#xff0c;通过图形直观地发现流失最严重的环节&#xff0c;从而有针对性地去进行优化。

d6dbeb3521c3ed92f7f9aa0496f12963.png

△ 表1&#xff1a;漏斗分析

可以看出&#xff0c;漏斗分析中也要用到交集运算&#xff0c;例如&#xff1a;有多少访问了首页的用户&#xff0c;进入到了产品详细页&#xff1f;看了产品详情页的&#xff0c;有多少用户将它加入到了购物车&#xff1f;产品运营人员非常关心这些指标&#xff0c;因为它代表了用户在使用中每一步的转化关系&#xff1b;如果某一个路径上的转化率较低&#xff0c;意味着潜在的问题和风险&#xff0c;需要及时介入。

以前面的示例数据为例&#xff0c;如果我们将 Page 作为一个维度&#xff0c;User ID 做 count distinct 度量&#xff0c;构建成 Cube 后得到这样的用户访问统计&#xff08;示例&#xff09;:

1a0e6b03ee1c1df9ca7f528287753377.png

△ 表4&#xff1a;样例 Cube 2

这样通过切换 Page 的值来做交集&#xff0c;我们就可以很容易地计算出它们之间的漏斗转化率&#xff0c;如&#xff1a;

select
intersect_count(user_id, page, array[&#39;index.html&#39;]) as first_step_uv,
intersect_count(user_id, page, array[&#39;search.html&#39;]) as second_step_uv,
intersect_count(user_id, page, array[&#39;detail.html&#39;]) as third_step_uv,
intersect_count(user_id, page, array[&#39;index.html&#39;, &#39;search.html&#39;]) as retention_one_two,
intersect_count(user_id, page, array[&#39;search.html&#39;,&#39;detail.html&#39;]) as retention_two_three
from access_log
where dt in (&#39;2016104&#39;, &#39;20161015&#39;, &#39;20161016&#39;)

结果&#xff1a;

5&#xff0c; 3&#xff0c; 2&#xff0c; 3&#xff0c; 2

如此行为漏斗的转化率也就很容易得到了&#xff1a;

cb61d9c9e3c86bb1a7f2876790036f33.png

△ 表 5&#xff1a;样例行为漏斗结果

当然这是一个很简单的例子&#xff0c;实际会复杂很多&#xff1b;这里的 Page&#xff08;页面&#xff09;可以换成埋点值或其它维度&#xff0c;从而更加细致地分析各种行为之间的关联关系。

多维度滑动的留存分析

前面的例子中都是单个维度值变化时&#xff0c;使用Kylin的交集函数进行留存和漏斗转化的计算&#xff0c;是比较容易理解的。现实中有时候需要在多个维度上同时进行滑动分析&#xff0c;例如运营可能会问&#xff1a;第一天访问“商品明细页”的用户&#xff0c;有多少在第二天访问了“付款页”&#xff1f;那么 Kylin 是否可以做到呢&#xff1f;

答案是肯定的&#xff0c;虽然 intersect_count 交集函数只接受一个维度值的变化&#xff0c;但我们可以巧妙利用 where 做其它维度的筛选&#xff0c;最后的结果交给 SQL 执行器来计算。如&#xff1a;

select
intersect_count(user_id, dt, array[‘20190101’])&#xff0c;#第一天的UV
intersect_count(user_id, dt, array[‘20190101’, ‘20190102’]) #第一天和第二天交集
from access_log
where (dt&#61;&#39;20190101’ and page&#61;‘detail.html’) #筛选第一天&访问明细页的用户or
(dt&#61;‘20190102’ and page&#61;‘payment.html’) #筛选第二天&访问付款页的用户

这样的条件是只需要把 page 和 dt 都做为维度就可以了&#xff0c;是不是很简单&#xff1f;

先或再与操作

有时候业务人员在分析问题的时候&#xff0c;会动态调整分析的组合&#xff0c;把一些条件先进行或(or)操作&#xff0c;然后再跟其它条件做与(and)运算。例如&#xff0c;访问了“搜索页”和“详情页”中任何一个的用户&#xff0c;有多少访问了“付款页”&#xff1f;前两者是一个或的关系&#xff0c;它们的结果需要跟第三个进行与操作。

为了支持这种特殊的计算&#xff0c;我们可以扩展 intersect_count 函数&#xff0c;让它可以理解或运算符。下面是一个示例&#xff08;这里默认使用了“|”作为或条件的分隔符&#xff0c;如果维度值中可能包含“|”&#xff0c;需通过配置修改成其它符号&#xff09;&#xff1a;

select
intersect_count(user_id, page, array[&#39;search.html|detail.html’, &#39;payment.html&#39;])
from access_log

在 app 埋点分析中&#xff0c;这也是一个常见的场景。app 开发者为了日后分析的灵活性&#xff0c;会有意埋了很多不同的点&#xff1a;同样的行为在不同客户端、版本中的埋点值可能不同&#xff08;称为“物理埋点”&#xff09;&#xff1b;但业务人员在分析的时候&#xff0c;需要将这些物理埋点根据需要装配成“逻辑埋点”。例如&#xff0c;“安卓端登录”、“苹果端登录”和“网页登录”这三个埋点值都代表了“登录”这个行为&#xff0c;它们或的集合去跟“登录失败”做与操作&#xff0c;可以算出 app 整体登录失败率。

过去为了满足业务的这种灵活分析需求&#xff0c;开发者往往需要调整他们的ETL脚本来改变运算逻辑&#xff0c;周期长、效率低并且很容易出错&#xff1b;使用 Kylin 后就没有这些烦恼&#xff0c;用户可以灵活组装查询条件&#xff0c;剩下的事情交给 Kylin 就可以了。

注&#xff1a;此功能目前还处于内部预览阶段&#xff0c;还未在社区版正式发布。

用户画像分析

用户画像分析中需要通过标签进行用户的筛选&#xff1b;作为存储数字集合的最紧凑数据结构&#xff0c;Bitmap 常常被用在用户画像分析中。Kylin 引入 Bitmap 后&#xff0c;也可以用在用户画像的分析。

使用 Kylin 做用户筛查时&#xff0c;通常需要将标签从列转行&#xff0c;将“标签类型”和“标签值”作为维度&#xff0c;将 User ID 作为 Bitmap 度量进行构建&#xff0c;构建后的 Cube 如下&#xff1a;

43065f515ddb3638a6c1d1290f13402f.png

△ 表 6&#xff1a;样例用户画像 Cube

例如现在要分析&#xff0c;性别是男的、年龄是 90 后的、收入在 10-20 万区间的人有多少&#xff1b;通过 Kylin 这样查询即可&#xff1a;

select
intersect_count(user_id, tag_value, array[&#39;男&#39;, &#39;90后&#39;, &#39;10-20万&#39;])
from user_profile
where (tag_type&#61;&#39;性别&#39; and tag_value&#61;&#39;男&#39;) or (tag_type&#61;&#39;年龄&#39; and tag_value&#61;&#39;90后&#39;) or (tag_type&#61;&#39;收入&#39; and tag_value&#61;&#39;10-20万&#39;)

结果&#xff1a;

2

如果当前标签筛选后的结果集依然很大&#xff0c;用户可以继续添加更多标签&#xff0c;直到将用户数控制到合适的范围&#xff08;例如打算定向发放一万张优惠券&#xff09;。

用户明细分析

在用标签筛查后业务人员可能问&#xff0c;能否导出满足这些标签的用户集合明细呢&#xff0c;这样好对他们发券啊&#xff1f;Kylin 是否能在回答用户数的同时&#xff0c;告诉我们具体是哪些 User_ID 呢&#xff1f;

答案是肯定的&#xff0c;因为 Bitmap 忠实地保存了每个 User_ID 值&#xff08;例如使用第 100 个 bit 位代表 ID 为 100 的用户是否出现&#xff09;&#xff0c;因此它可以在需要的时候告诉我们明细数据。

为了支持此类查询&#xff0c;我们可以参照 intersect_count 函数&#xff0c;开发另一个能返回 Bitmap 明细的函数&#xff0c;这里我们暂且称它为 intersect_value 函数&#xff0c;用法跟 intersect_count 一样&#xff0c;只是它的返回类型是一个整数数组&#xff1a;

select
intersect_value(user_id, tag_value, array[&#39;男&#39;, &#39;90后&#39;, &#39;10-20万&#39;])
from user_profile
where (tag_type&#61;&#39;性别&#39; and tag_value&#61;&#39;男&#39;) or (tag_type&#61;&#39;年龄&#39; and tag_value&#61;&#39;90后&#39;) or (tag_type&#61;&#39;收入&#39; and tag_value&#61;&#39;10-20万&#39;)

结果&#xff1a;

[101,103]

有了明细结果&#xff0c;下一步就可以结合其它数据源如用户明细表、CRM 系统等做进一步的分析了&#xff0c;这里就不展开了。

注&#xff1a;此功能目前还处于内部预览阶段&#xff0c;还未在社区版正式发布。

成功案例

Kylin 的精确去重功能和交集函数最初是由美团点评大数据团队根据自身场景和需求开发并贡献到开源社区的&#xff0c;并在美团内部得到大量使用。现在&#xff0c;这些功能正在被越来越多的用户所使用&#xff0c;有的基于 Kylin 再开发一些前端展现&#xff0c;就实现了能满足业务绝大部分需求的一站式用户行为分析平台。

例如满帮集团&#xff0c;它是原运满满和货车帮合并后的集团&#xff0c;有 8 个手机 app&#xff0c;4 类埋点、上千个埋点值&#xff0c;收集了超过千亿条的用户行为日志。过去他们自己开发的分析平台各方面都不能满足业务需求&#xff0c;束缚了业务的发展&#xff1b;后来满帮集团迁移到了基于 Kylin 的分析平台&#xff0c;借助于 Kylin 的丰富功能&#xff0c;自研了名为 APPDATA 的一站式分析平台&#xff0c;极大地满足了业务对于数据分析的需求。

a8baf4ad9e3d4d4ead0a9e55ecebd405.png

△ 图2&#xff1a;满帮 APPDATA 数据流程图

这是他们基于 Kylin 的日&#xff0f;周&#xff0f;月留存分析报表&#xff0c;对于留存率异常情况&#xff0c;会通过颜色高亮显示&#xff1a;

5d4a76a487ffa7a4ff6e98c20b36ac40.png

△ 图 3&#xff1a;满帮 APPDATA 日留存样例

这是他们开发的、让业务人员可以自定义行为的功能&#xff0c;业务人员可以自由地组合各类埋点&#xff0c;将它们定义称一个“行为”&#xff08;逻辑埋点&#xff09;&#xff1a;

620507faf7a000ae59e92861610d205a.png

△ 表 4&#xff1a;满帮 APPDATA 自定义用户行为

随后&#xff0c;业务人员可以将一些行为串成一个行为漏斗&#xff0c;然后查看漏斗转化率&#xff0c;背后就是用的 Kylin 交集函数&#xff1a;

8dc4b3e69d99ed7bab73784a5a4fd580.png

△ 表5&#xff1a;满帮 APPDATA 自定义行为漏斗

在这张图上&#xff0c;业务人员可以很方便地查看每一步的留存&#xff0f;流失率&#xff0c;对于异常情况&#xff0c;可以进一步下钻到明细做进一步的筛查。关于满帮使用Kylin的更多信息&#xff0c;请参考文末的“参考”文章【3】。

总结

Kylin 为实现秒级精确去重引入了 Bitmap 做为用户集合的存储结构&#xff0c;通过扩展 SQL 聚合函数&#xff0c;Kylin 还支持对 Bitmap 的交集、先或再与以及查询明细等操作&#xff0c;可以非常巧妙地运用在用户行为和用户画像分析领域&#xff0c;相比于自己开发具有多种优势&#xff1a;

  • 图形化建模操作&#xff0c;无需编程开发&#xff1b;
  • 存储和计算基于 Hadoop&#xff0c;能支撑海量用户数据的加工和存储&#xff1b;
  • 易于使用&#xff0c;查询全部使用 SQL&#xff1b;
  • 高性能高并发&#xff0c;大部分查询在秒级完成&#xff1b;
  • 结果精确&#xff1b;
  • 稳定可靠&#xff0c;已在许多互联网用户如美团、滴滴、eBay 生产系统使用多年。

想体验 Kylin 秒级精确去重&#xff1f;

Kylin 官网文档中有操作指南哦&#xff1a;https://kylin.apache.org/docs/tutorial/create_cube.html

参考

【1】史少锋《如何在 1 秒内做到大数据精准去重》 https://kyligence.io/zh/blog/apache-kylin-count-distinct/

【2】孙业锐 《Retention Or Conversion Rate Analyze in Apache Kylin》https://kylin.apache.org/blog/2016/11/28/intersect-count/

【3】陈雅婕《Kylin 在满帮集团千亿级用户访问行为分析中的应用》https://kyligence.io/zh/resources/kylin_at_manbang_group/

了解更多大数据资讯&#xff0c;点击进入Kyligence官网​kyligence.io

2019年11月16日Apache Kylin Meetup北京站正在火热报名&#xff01;邀请到滴滴、微众银行、一点资讯以及Kyligence的技术专家为大家呈现精彩应用案例与实践&#xff1a;

【2019年第5期】Apache Kylin Meetup 北京站​www.huodongxing.com
9b08cabe32e3152304e521dcf1991216.png



推荐阅读
  • 本文介绍了如何通过安装和配置php_uploadprogress扩展来实现文件上传时的进度条显示功能。通过一个简单的示例,详细解释了从安装扩展到编写具体代码的全过程。 ... [详细]
  • 使用 ModelAttribute 实现页面数据自动填充
    本文介绍了如何利用 Spring MVC 中的 ModelAttribute 注解,在页面跳转后自动填充表单数据。主要探讨了两种实现方法及其背后的原理。 ... [详细]
  • 本文详细介绍了Socket在Linux内核中的实现机制,包括基本的Socket结构、协议操作集以及不同协议下的具体实现。通过这些内容,读者可以更好地理解Socket的工作原理。 ... [详细]
  • 本文详细介绍了如何在PHP中使用Memcached进行数据缓存,包括服务器连接、数据操作、高级功能等。 ... [详细]
  • 在使用mybatis进行mapper.xml测试的时候发生必须为元素类型“mapper”声明属性“namespace”的错误项目目录结构UserMapper和UserMappe ... [详细]
  • 本文由chszs撰写,详细介绍了Apache Mina框架的核心开发流程及自定义协议处理方法。文章涵盖从创建IoService实例到协议编解码的具体步骤,适合希望深入了解Mina框架应用的开发者。 ... [详细]
  • 【MySQL】frm文件解析
    官网说明:http:dev.mysql.comdocinternalsenfrm-file-format.htmlfrm是MySQL表结构定义文件,通常frm文件是不会损坏的,但是如果 ... [详细]
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 本文深入探讨了MySQL中的高级特性,包括索引机制、锁的使用及管理、以及如何利用慢查询日志优化性能。适合有一定MySQL基础的读者进一步提升技能。 ... [详细]
  • 本文探讨了如何在SQL Server Reporting Services (SSRS)中利用TOP N功能来筛选和展示数据集中的前N条记录。通过正确的配置图表属性中的筛选器设置,可以轻松实现这一目标。 ... [详细]
  • 一、使用Microsoft.Office.Interop.Excel.DLL需要安装Office代码如下:2publicstaticboolExportExcel(S ... [详细]
  • LeetCode 102 - 二叉树层次遍历详解
    本文详细解析了LeetCode第102题——二叉树的层次遍历问题,提供了C++语言的实现代码,并对算法的核心思想和具体步骤进行了深入讲解。 ... [详细]
  • 视觉Transformer综述
    本文综述了视觉Transformer在计算机视觉领域的应用,从原始Transformer出发,详细介绍了其在图像分类、目标检测和图像分割等任务中的最新进展。文章不仅涵盖了基础的Transformer架构,还深入探讨了各类增强版Transformer模型的设计思路和技术细节。 ... [详细]
  • Asynchronous JavaScript and XML (AJAX) 的流行很大程度上得益于 Google 在其产品如 Google Suggest 和 Google Maps 中的应用。本文将深入探讨 AJAX 在 .NET 环境下的工作原理及其实现方法。 ... [详细]
  • Hibernate全自动全映射ORM框架,旨在消除sql,是一个持久层的ORM框架1)、基础概念DAO(DataAccessorOb ... [详细]
author-avatar
岁月静好198838
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有