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. linux 命令-case

    case 命令作用: case语句使用于需要进行多重分支的应用情况 case 命令使用场景 在shell中的case结构与C/C++中的switch结构是相同的. 它允许通过判断来选择代码块中多条路径 ...

  2. Hadoop的概念、版本、发展史

    Hadoop是什么?Hadoop的起源Hadoop发展史Hadoop的四大特性(优点)Hadoop的版本如何选择Hadoop版本 Hadoop是什么? Hadoop: 适合大数据的分布式存储和计算平台 ...

  3. Alpha阶段第2周/共2周 Scrum立会报告+燃尽图 04

    作业要求[https://edu.cnblogs.com/campus/nenu/2018fall/homework/2287] 版本控制:https://git.coding.net/liuyy08 ...

  4. 记一次git fatal: Unable to find remote helper for 'https'问题的解决

    登陆到远程linux服务器上,使用git, clone的时候报“fatal: Unable to find remote helper for 'https'”错,没管,绕过,使用git clone ...

  5. 图论期末大作业编程题(如何判断一个4连通4正则图为无爪、无K4图)

    博士期间估计这可能是唯一一个要编程的作业,搞了半天弄出这个东西,放这里为以后用到的时候查找方便. 说来也是可笑,读博士期间发现大家对上课也都没什么兴趣,老师也是那么回事,都说博士期间学的课程是要有助于 ...

  6. ZetCode PyQt4 tutorial basic painting

    #!/usr/bin/python # -*- coding: utf-8 -*- """ ZetCode PyQt4 tutorial In this example, ...

  7. [QT]QPixmap图片缩放和QLabel 的图片自适应效果对比

    图片大小为600x600 效果图: ui->label->setScaledContents(true);                                         ...

  8. 51Nod 1081:子段求和(前缀和)

    1081 子段求和  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出一个长度为N的数组,进行Q次查询,查询从第i个元素开始长度为l的子段所有元素之和 ...

  9. 堆排序(C语言实现)

    一.堆的概念 所谓堆,它是一个数组,也能够被看成一个近似的全然二叉树.树上每一个结点相应数组的一个元素.二叉堆分为二种:最大堆和最小堆.本文主要介绍最大堆,最小堆类似.最大堆的特点:对于随意某个结点, ...

  10. RK3288 device descriptor read/64, error -32

    CPU:RK3288 系统:Android 5.1 主板有两个USB接口,一个接USB摄像头,一个接身份证模块. 插入摄像头可以正常打开,再插入身份证模块时,摄像头就会卡主,而且身份证模块无法识别,内 ...