1. 背景描述

目前在做音乐推荐项目,前期做排序模型优化,任务是使用模型对用户的历史音乐进行排序,有6800多万个用户,约40G的用户数据,使用HBase作为数据仓库。

利用HBase可以存储多个版本数据的特性,数据运算完后入库时,将用户id作为rowkeysongInfo: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删除自定义时间戳行数据)的更多相关文章

  1. c# js 删除table原行数据

    function addtreetotable(obj){ var table1 =  document.getElementById("Table1"); var hang =  ...

  2. 一个将当前目录下HEX文件的第一行数据删除的程序

    为什么要写这样一个函数 在使用SoftConsole开发M3程序时,生成的hex文件,必须要把第一行数据删除,才能在Libero中使用,所以写了这个小工具,这是2.0版本了,第一版是直接删除第一行数据 ...

  3. Mac 下用IDEA时maven,ant打包 (mr 入库hbase)

    现在非常喜欢IDEA,之前在mac 上用的eclipse 经常出现无缘无故的错误.所以转为IDEA.  不过新工具需要学习成本,手头上的项目就遇到了很多问题,现列举如下: 背景描述 在hadoop 开 ...

  4. Hbase框架原理及相关的知识点理解、Hbase访问MapReduce、Hbase访问Java API、Hbase shell及Hbase性能优化总结

    转自:http://blog.csdn.net/zhongwen7710/article/details/39577431 本blog的内容包含: 第一部分:Hbase框架原理理解 第二部分:Hbas ...

  5. HBase之六:HBase的RowKey设计

    数据模型 我们可以将一个表想象成一个大的映射关系,通过行健.行健+时间戳或行键+列(列族:列修饰符),就可以定位特定数据,Hbase是稀疏存储数据的,因此某些列可以是空白的, Row Key Time ...

  6. HBase 1、HBase介绍和工作原理

    HBase是一个分布式的.面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”.就像Bigtable利用了Google文件 ...

  7. HBase学习——3.HBase表设计

    1.建表高级属性 建表过程中常用的shell命令 1.1 BLOOMFILTER 默认是 NONE 是否使用布隆过虑及使用何种方式,布隆过滤可以每列族单独启用 使用HColumnDescriptor. ...

  8. 大数据技术之_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 ...

  9. Hbase之三:Hbase Shell使用入门

    HBase 为用户提供了一个非常方便的使用方式, 我们称之为“HBase Shell”.HBase Shell 提供了大多数的 HBase 命令, 通过 HBase Shell 用户可以方便地创建.删 ...

随机推荐

  1. SharePoint Development - Custom Field using Visual Studio 2010 based SharePoint 2010

    博客地址 http://blog.csdn.net/foxdave 自定义列表的时候有时候需要自定义一些字段来更好地实现列表的功能,本文讲述自定义字段的一般步骤 打开Visual Studio,我们还 ...

  2. 2018.12.25 SOW

    1. Understanding Customer Requirements 11.1. Project Overview 21.2. System Requirements 21.3. Indust ...

  3. fiddler模拟限速实战

    原理:Fiddler的模拟限速是在客户端请求前来自定义限速的逻辑,此逻辑是通过延迟发送数据或接收的数据的时间来限制网络的下载速度和上传速度,从而达到限速的效果. 算法:那么我们的算法就是 1000/下 ...

  4. python 机器学习库 —— featuretools(自动特征工程)

    文档:https://docs.featuretools.com/#minute-quick-start 所谓自动特征工程,即是将人工特征工程的过程自动化.以 featuretools 为代表的自动特 ...

  5. iOS-----简易地CocoaAsyncSocket使用

    CocoaAsyncSocket使用 代理的.h文件 //GCDAsyncSocketDelegate执行代理对象 #import <Foundation/Foundation.h> #i ...

  6. python中的运算符优先级(其它语言也试用)

  7. javascript window.onload 加载多个函数的方法

    用法如下: function func(){alert("this is window onload event!");return;} window.onload=func; 或 ...

  8. CH1807 Necklace

    题意 背景 有一天,袁☆同学绵了一条价值连城宝石项链,但是,一个严重的问题是,他竟然忘记了项链的主人是谁!在得知此事后,很多人向☆同学发来了很多邮件,都说项链是自己的,要求他归还(显然其中最多只有一个 ...

  9. hadoop之 Hadoop1.x和Hadoop2.x构成对比

      Hadoop1.x构成: HDFS.MapReduce(资源管理和任务调度):运行时环境为JobTracker和TaskTracker: Hadoop2.0构成:HDFS.MapReduce/其他 ...

  10. Linux进程间通信——使用信号量(转)

    这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...