实现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 用户可以方便地创建.删 ...
随机推荐
- centos7 搭建svn服务器&客户端的访问&备份迁移
当今用于版本控制的软件程序主要的有svn和git,其它软件咱不熟悉,今天记录下搭建svn服务器和svn客户端使用: 使用环境:虚拟机为centos7系统,svn服务器安装在centos7系统平台上,s ...
- <NET CLR via c# 第4版>笔记 第5章 基元类型、引用类型和值类型
5.1 编程语言的基元类型 c#不管在什么操作系统上运行,int始终映射到System.Int32; long始终映射到System.Int64 可以通过checked/unchecked操作符/语句 ...
- java的初始化(编程思想)
6.成员初始化 java尽量保证:所有变量在使用前都能得到恰当的初始化.对于方法的局部变量,java以编译错误的形式来贯彻这种保证. 如果类的成员变量时基本类型,那么没有初始化给默认值 在类里定义一个 ...
- L185 Ocean Shock
This is part of "Ocean Shock," a Reuters series exploring climate change's impact on sea c ...
- tensorflow中tensor的静态维度和动态维度
tf中使用张量(tensor)这种数据结构来表示所有的数据,可以把张量看成是一个具有n个维度的数组或列表,张量会在各个节点之间流动,参与计算. 张量具有静态维度和动态维度. 在图构建过程中定义的张量拥 ...
- 简单桶排序算法-python实现
#-*- coding: UTF-8 -*- import numpy as np def BucketSort(a, n): barrel = np.zeros((1, n), dtype = 'i ...
- Apache Commons Codec 与消息摘要算法(hash算法)
首先我们要明白 Codec 是什么含义.它是 Coder + decoder = Codec,也就是编码器解码器.即是编码器,也是解码器. 官网地址:http://commons.apache.org ...
- 调用WebAPI接口地址返回序列化的JSON对象中的属性都加了个k__BackingField关键字的解决办法
1.问题现象: 2.造成此问题的原因是返回的结果对象实体上面加了个可序列号特效 [Serializable].去掉就可以了. 3.解决后的效果:
- jmeter 目录内容分布
/bin 目录(常用文件介绍) examples:目录下包含Jmeter使用实例 ApacheJMeter.jar:JMeter源码包 jmeter.bat:windows下启动文件 jmeter.s ...
- Oracle VM VirtualBox虚拟机安装Ubuntu Server
安装过程如下:原文转自:http://www.linuxidc.com/Linux/2012-04/59368p8.htm