实现HBase增量入库(HBase删除自定义时间戳行数据)
1. 背景描述
目前在做音乐推荐项目,前期做排序模型优化,任务是使用模型对用户的历史音乐进行排序,有6800多万个用户,约40G的用户数据,使用HBase作为数据仓库。
利用HBase可以存储多个版本数据的特性,数据运算完后入库时,将用户id作为rowkey,songInfo:songid的值为歌曲id,使用自定义时间戳,将排序模型输出的歌曲得分(分值越高)作为时间戳。因为HBase数据存储默按照时间戳降序存储,这样只要取出用户的songInfo:songid的所有版本的值就能获取该用户的历史音乐经过模型排序后的顺序。
2. 问题描述
每次数据入库时,使用oozie进行任务调度,先使用truncate命令将原表数据清空,然后根据用户日志进行计算后入库。也就是不管用户的历史音乐数据是否有发生改变,都将HBase中的用户数据删除,根据数据统计,每天的活动用户约为20w占总用户的1/340,换句话说,对339/340的用户进行了没有必要的重复计算,因为他们的历史数据没有发生改变。如果能使用增量入库的方式,只获取活跃用户的日志数据进行计算并入库,可以大大节约资源。
3. 解决方案
3.1 直接删除行数据
最直接的想法是,直接在入库前增加删除语句就行,拿到日志有变化的用户后,删除用户数据,然后入库。所以直接新增了以下语句
Delete delete = new Delete(Bytes.toBytes(StringUtils.trimWhite(userid)));
table.delete(delete);
查看最后的入库结果,入库失败,只入了几百条数据,而且根本不是想要的效果。
3.2 删除自定义时间戳的行数据
Delete对象在删除前没限制删除的列簇和时间戳,就是删除了该rowkey所对应的所有列簇的所有字段,所以删除数据的操作没问题,可是入库的代码没有改动,之前入库没有问题。继续了解HBase删除机制后找到了原因。
其实问题出在了自定义时间戳上。在入库的时间戳是根据模型计算出来的,远小于当前的时间的时间戳,而删除的时候没有指定时间戳,HBase会默认使用服务器生成的当前时间的时间戳。而HBase的删除操作并不是真正的删除,可以看成是含有Delete标记的特殊put,只是先给数据打上标记,时间戳小于这个删除时间的数据在下一次major compaction的时候才被真正的删除。由于删除后入库的数据使用的是自定义时间戳且远小于当前时间的时间戳,所以导致了入库的数据被HBase删除了。
自定义时间戳远小于删除时自动生成的时间戳,按理来说最后入库结果应该一条数据都没有(因为小于删除时间戳的数据都被删除了),但为什么最后还是入了几百条的数据呢? 推测原因是因为在最后数据的put过程中发生了major compaction,HBase进行了真正的删除,删除数据后Delete标记也失效了,所以后面的put操作才会真正生效。
既然问题定位到了时间戳,那就在删除的时候指定时间戳,还是使用自定的时间戳,但是不直接使用模型生成的分值,而是把歌曲按分值升序排序后从1开始编号,将 删除时的时间戳+歌曲编号 作为入库时的时间戳。在删除的时候直接指定删除时间戳为当前的时间戳,这样之前的用户数据就会被删除,而新入库的数据时间戳大于被删除的时间戳,就会被保留。关键代码如下:
long offset = new Date().getTime();
//判断该用户是否存在
Get get = new Get(Bytes.toBytes(StringUtils.trimWhite(userid)));
get.addColumn(Bytes.toBytes(columnFamily),Bytes.toBytes("songID"));
get.setMaxVersions(1);
Result result = table.get(get);
//System.out.println("这是result.rawCells()前的result对象"+result.toString());
if (!result.isEmpty()) {
//KeyValue[] kV = result.raw();
//offset = kV[0].getTimestamp();
//System.out.println("获取的最新时间戳为: "+offset);
//offset = result.rawCells()[0].getTimestamp(); //报错找不到该方法,可能是hbase版本太低
//删除之前的数据
Delete delete = new Delete(Bytes.toBytes(StringUtils.trimWhite(userid)));
delete.deleteFamily(Bytes.toBytes(columnFamily),offset);
table.delete(delete);
}
参考文章:
[1] hbase时间戳修改带来的问题总结
[2] HBase中数据的多版本特性潜在的意外
实现HBase增量入库(HBase删除自定义时间戳行数据)的更多相关文章
- c# js 删除table原行数据
function addtreetotable(obj){ var table1 = document.getElementById("Table1"); var hang = ...
- 一个将当前目录下HEX文件的第一行数据删除的程序
为什么要写这样一个函数 在使用SoftConsole开发M3程序时,生成的hex文件,必须要把第一行数据删除,才能在Libero中使用,所以写了这个小工具,这是2.0版本了,第一版是直接删除第一行数据 ...
- Mac 下用IDEA时maven,ant打包 (mr 入库hbase)
现在非常喜欢IDEA,之前在mac 上用的eclipse 经常出现无缘无故的错误.所以转为IDEA. 不过新工具需要学习成本,手头上的项目就遇到了很多问题,现列举如下: 背景描述 在hadoop 开 ...
- Hbase框架原理及相关的知识点理解、Hbase访问MapReduce、Hbase访问Java API、Hbase shell及Hbase性能优化总结
转自:http://blog.csdn.net/zhongwen7710/article/details/39577431 本blog的内容包含: 第一部分:Hbase框架原理理解 第二部分:Hbas ...
- HBase之六:HBase的RowKey设计
数据模型 我们可以将一个表想象成一个大的映射关系,通过行健.行健+时间戳或行键+列(列族:列修饰符),就可以定位特定数据,Hbase是稀疏存储数据的,因此某些列可以是空白的, Row Key Time ...
- HBase 1、HBase介绍和工作原理
HBase是一个分布式的.面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”.就像Bigtable利用了Google文件 ...
- HBase学习——3.HBase表设计
1.建表高级属性 建表过程中常用的shell命令 1.1 BLOOMFILTER 默认是 NONE 是否使用布隆过虑及使用何种方式,布隆过滤可以每列族单独启用 使用HColumnDescriptor. ...
- 大数据技术之_11_HBase学习_01_HBase 简介+HBase 安装+HBase Shell 操作+HBase 数据结构+HBase 原理
第1章 HBase 简介1.1 什么是 HBase1.2 HBase 特点1.3 HBase 架构1.3 HBase 中的角色1.3.1 HMaster1.3.2 RegionServer1.3.3 ...
- Hbase之三:Hbase Shell使用入门
HBase 为用户提供了一个非常方便的使用方式, 我们称之为“HBase Shell”.HBase Shell 提供了大多数的 HBase 命令, 通过 HBase Shell 用户可以方便地创建.删 ...
随机推荐
- OCX组件
转自:http://blog.sina.com.cn/s/blog_4ca9ceef0100ixzb.html 一.OCX(OLE Control Extensio,OLE Object Linkin ...
- bzoj2843&&1180
题解: lct 和上一题差不多 这一题还要判断是否有链接 其实直接并查集判断就可以了 代码: #pragma GCC optimize(2) #include<bits/stdc++.h> ...
- Android Studio 1.5 注解配置
Project的build.gradle文件配置如下: // Top-level build file where you can add configuration options common t ...
- 谈一谈手机WebApp的fixed属性(手机上的固定栏)【转】
1.iphone/android原生app常见结构 似乎,所有的手机应用,都遵循这样的布局:固定的顶部+固定的底部+可滚动在中间区域.这种“雷同”的模式让人恶心,却不得不承认这是一种很规矩却又很实用的 ...
- redux-thunk中间件源码
浅析redux-thunk中间件源码 大多redux的初学者都会使用redux-thunk中间件来处理异步请求,其理解简单使用方便(具体使用可参考官方文档).我自己其实也一直在用,最近偶然发现其源码只 ...
- ANSI的Escape序列屏幕控制码
http://blog.csdn.net/lano2088/article/details/51985563 https://www.cnblogs.com/pied/p/4175641.html h ...
- CS231n课程笔记翻译7:神经网络笔记 part2
译者注:本文智能单元首发,译自斯坦福CS231n课程笔记Neural Nets notes 2,课程教师Andrej Karpathy授权翻译.本篇教程由杜客翻译完成,堃堃进行校对修改.译文含公式和代 ...
- Winform开发常用控件之TreeView菜单导航和权限用法
TreeView一个很棒的控件,我们在做WEB开发时常常犯困的一个东东.当然这里介绍winform里面的用法唠. 先介绍几个属性吧,CheckBoxes设置为true的话树形节点前面会出现checkb ...
- Python流程控制-逻辑运算-if...else语句
摘录自:http://www.runoob.com/python/python-if-statement.html Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执 ...
- Python ---- list和dict遍历
refer to: http://www.cnblogs.com/icejoywoo/p/3531869.html 对于python3, 可能有不一样之处, refer to: http://do ...