登录 |  注册 |  繁體中文


Hbase 存储用户行为记录

分类: hbase 颜色:橙色 默认  字号: 阅读(3065) | 评论(0)

使用HBase存储此类数据时,有以下两种常用的方案:

1、多行单列

表结构设计

Row Key:用户标识ID + (Long.MAX_VALUE - timestamp)

Column Family:’cf’

Column Qualifier:’’

Value:宝贝、URL等

其中,使用(Long.MAX_VALUE – timestamp)作为Row Key的后半部分是为了便于获取最近插入的数据,一个用户标识ID下的数据存储在多个Row Key下,每个Row Key下仅有一个Column Qualifier,表示该用户的一次时间相关的访问数据(访问宝贝、URL等)。

查询方式

1)查询某个特定timestamp下的记录,则使用用户标识ID + (Long.MAX_VALUE - timestamp)进行Get查找;

2)查询某个用户标识ID下所有的记录,则通过Scan.setStartRow(uid)和Scan.setStopRow(uid+1)进行Scan查找;

3)查询某个用户标识ID下最近时间内的N条记录,则通过Scan.setStartRow(uid)和 Scan.setStopRow(uid+1)进行Scan查找,但是为了只获取N条记录,可以设置Scan.setCaching(N)优化查询,同时 做一次ResultScanner.next(N)得到结果。

2、单行多列

表结构设计

Row Key:用户标识ID

Column Family:’cf’

Column Qualifier:(Long.MAX_VALUE - timestamp)

Value:宝贝、URL等

其中,使用(Long.MAX_VALUE – timestamp)作为Column Qualifier是为了便于获取最近插入的数据,一个用户标识ID下的数据存储在一个Row Key下,每个Row Key下会有多个Column Qualifier,表示该用户的所有时间相关的访问数据(访问宝贝、URL等)。

查询方式

1)查询某个特定timestamp下的记录,则使用用户标识ID进行Get查找,同时通过Get.addColumn(‘cf’, (Long.MAX_VALUE – timestamp))方法限定要查询的Column Qualifier;

2)查询某个用户标识ID下所有的记录,则直接使用用户标识ID进行Get查找,通过Get.addFamily(‘cf’)方法添加整个Column Family;

3)查询某个用户标识ID下最近时间内的N条记录,则直接使用用户标识ID进行Get查找,通过Get.addFamily(‘cf’)方法添加整个Column Family,通过ColumnCountGetFilter(int N)限制最多要查询返回N条记录。

3、总结

两种方式都能满足以上基本的查询需求,但由于目前HBase在单行多列的场景下,读写性能都有一定的衰减(具体情况请关注博客,后续会对这块给出详 细的性能测试),因此,个人建议采取第一种方案,如果确定Column Qualifier个数很少(例如2~10个),或者有其他特殊需求的话,也可采取第二种方案。

 

4、实例

 

4.1 多行单列实例

1.背景:之前公司客服部门有个查看游戏用户行为记录的需求,开始我给他们做了个hive的接口,可以暂时满足需求,但是查询速度太慢,得一分钟出结果。
后来我在想能不能用hbase快速查询出用户路径。
查询条件有通行证账号、行为类型、时间范围。
2.设计方案:用hbase的scan接口,hbase的key设计成 通行证账号_行为类型_时间
用如下方式查询:scan 'hbase_gameCenter_log',{COLUMNS =>['oneline:guid','oneline:report'],LIMIT =>10, STARTROW => 'u52fa532aae9dc_login_2013-04-01 00:00:00', STOPROW=>'u52fa532aae9dc_login_2016-04-01 00:00:00'}
3.缺点:能满足的查询场景有限。
4.优点:在这个查询需求场景下海量日志查询是1秒以下查询出结果。   

4.2 列实例

背景同上,即把 rowkey 改为 u52fa532aae9dc_2013-04-01 00:00:00'  login,作为column 




姓 名: *
邮 箱:
内 容: *
验证码: 点击刷新 *   

回到顶部