http://jiajun.iteye.com/blog/945358

HBase如何存取多个版本的值?




废话少说,一般情况下使用Put的这个方法保存一个版本:



  1. /**
  2. * Add the specified column and value to this Put operation.
  3. * @param family family name
  4. * @param qualifier column qualifier
  5. * @param value column value
  6. */
  7. public Put add(byte [] family, byte [] qualifier, byte [] value) {
  8. return add(family, qualifier, this.timestamp, value);
  9. }
  10. 然后获取HTable的实例,调用Put方法,更新入库。
 

这里我要刻意说明一下时间戳 ,可以看到上面的add方面实现里面调用了另外一个方法,增加了个参数:默认时间戳


  1. this.timestamp

它的值是:


  1. private long timestamp = HConstants.LATEST_TIMESTAMP;
  2. static final long LATEST_TIMESTAMP = Long.MAX_VALUE;
 

那么获取的时候,获取一个值 也很简单,使用下面的方法:


  1. 创建一个Put的实例
  2. /**
  3. * Create a Get operation for the specified row.
  4. * <p>
  5. * If no further operations are done, this will get the latest version of
  6. * all columns in all families of the specified row.
  7. * @param row row key
  8. */
  9. public Get(byte [] row) {
  10. this(row, null);
  11. }
  12. 然后获取HTable实例调用方法
  13. public Result get(final Get get) throws IOException
  14. 返回的Result对象 调用
  15. public byte [] getValue(byte [] family, byte [] qualifier)
  16. 就可以获取值。


一般的应用可以像上面这样来解决,服务器正常的话不会碰到什么问题,可是要存取多个版本 的话,有可能你会遇到我遇到的问题。 看下面一段代码是否有问题



(里面有如何插入多个版本 ,如何获取多个版本 的方法,顺带说明一个问题)



  1. /**
  2. * Test get value of multi versions
  3. *
  4. * @author dev-cjj
  5. *
  6. */
  7. public class GetRowVersionsTest extends TestCase
  8. {
  9. private final byte[] family     = Bytes.toBytes("log");
  10. private final byte[] qualifier  = Bytes.toBytes("q1");
  11. private final byte[] qualifier2 = Bytes.toBytes("q2");
  12. private final byte[] rowKey     = Bytes.toBytes(10001);
  13. private final HTable table      = IDMHBaseConfiguration.getTable("testTable");
  14. private final long   ts1        = 1298529542218L;
  15. private final long   ts2        = ts1 + 100;
  16. private final long   ts3        = ts1 + 1000;
  17. private final long   ts4        = ts1 + 2000;
  18. private final long   ts5        = ts1 + 3000;
  19. private final byte[] value1     = Bytes.toBytes("value1");
  20. private final byte[] value2     = Bytes.toBytes("value2");
  21. private final byte[] value3     = Bytes.toBytes("value3");
  22. private final byte[] value4     = Bytes.toBytes("value4");
  23. private final byte[] value5     = Bytes.toBytes("value5");
  24. private void insert(final long ts, final byte[] value) throws IOException
  25. {
  26. //        table.setAutoFlush(false);
  27. final Put put = new Put(rowKey);
  28. put.add(family, qualifier, ts, value);
  29. put.add(family, qualifier2, ts, value);
  30. table.put(put);
  31. }
  32. private void sleep()
  33. {
  34. try
  35. {
  36. Thread.sleep(1000);
  37. }
  38. catch (final InterruptedException e)
  39. {
  40. e.printStackTrace();
  41. }
  42. }
  43. @Test
  44. public void testGetRowMultipleVersions() throws Exception
  45. {
  46. insert(ts1, value1);
  47. sleep();
  48. insert(ts2, value2);
  49. sleep();
  50. insert(ts3, value3);
  51. sleep();
  52. insert(ts4, value4);
  53. sleep();
  54. insert(ts5, value5);
  55. sleep();
  56. // check getRow with multiple versions
  57. final Get get = new Get(rowKey);
  58. get.setMaxVersions();
  59. final Result r = table.get(get);
  60. // one way get values of all version
  61. //        final List<KeyValue> list = r.list();
  62. //        for (final KeyValue kv : list)
  63. //        {
  64. //            System.err.println(Bytes.toString(kv.getKey()));
  65. //            System.err.println(kv.getTimestamp());
  66. //            System.err.println(Bytes.toString(kv.getValue()));
  67. //        }
  68. // another way get values of all version
  69. final NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = r.getMap();
  70. final NavigableMap<byte[], NavigableMap<Long, byte[]>> familyMap = map.get(family);
  71. final NavigableMap<Long, byte[]> versionMap = familyMap.get(qualifier);
  72. for (final Map.Entry<Long, byte[]> entry : versionMap.entrySet())
  73. {
  74. System.err.println(Bytes.toString(qualifier) + " -> " + Bytes.toString(entry.getValue()));
  75. }
  76. final NavigableMap<Long, byte[]> versionMap2 = familyMap.get(qualifier2);
  77. for (final Map.Entry<Long, byte[]> entry : versionMap2.entrySet())
  78. {
  79. System.err.println(Bytes.toString(qualifier2) + " -> " + Bytes.toString(entry.getValue()));
  80. }
  81. //        assertTrue(versionMap.size() == 5);
  82. //        assertTrue(value1 == versionMap.get(ts1));
  83. //        assertTrue(value2 == versionMap.get(ts2));
  84. //        assertTrue(value3 == versionMap.get(ts3));
  85. //        table.delete(new Delete(rowKey));
  86. //        assertTrue(table.get(get).size() == 0);
  87. //        table.close();
  88. }
  89. }
 

这里我只是打印输出结果 ,不用断言, 结果如你所期望的是:


  1. q1 -> value5
  2. q1 -> value4
  3. q1 -> value3
  4. q1 -> value2
  5. q1 -> value1
  6. q2 -> value5
  7. q2 -> value4
  8. q2 -> value3
  9. q2 -> value2
  10. q2 -> value1
 

上面的代码中,我注视掉了一个关键行



  1. //        table.delete(new Delete(rowKey));

如果取消注释,再运行几次你会发现一个大问题! 保存不上了,一个版本都没有。



final Result r = table.get(get); 里面什么都不会有! 很奇怪!



问题原因 (针对上面的代码和问题):



1、插入的时候使用的时间戳都是过去的时间戳。


2、删除的时候没有指定时间戳(如果没有指定则默认一个当前的时间戳)


3、在HBase中删除操作并没有删除对应的文件,只是做一个带有时间戳的删除标记(任何在这个时间戳之前的列值都会被认为是删除的)



那么知道上面三条规则,问题就简单了,新插入的列值的时间戳要在删除标记的时间戳之后,才会被认为是不被删除的列值。



补充一点,创建/添加列族时候默认是三个版本,可以修改为1个版本或者更多个版本,我上面5个版本是因为我指定了5个版本。


  1. {NAME => 'testTable', FAMILIES => [{NAME => 'log', COMPRESSION => 'NON true
  2. E', VERSIONS => '5', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEM
  3. ORY => 'false', BLOCKCACHE => 'true'}]}
 

hbase 取多个版本数据的更多相关文章

  1. HBase跨版本数据迁移总结

    某客户大数据测试场景为:Solr类似画像的数据查出用户标签--通过这些标签在HBase查询详细信息.以上测试功能以及性能. 其中HBase的数据量为500G,Solr约5T.数据均需要从对方的集群人工 ...

  2. 【hbase】——bulk load导入数据时value=\x00\x00\x00\x01问题解析

    一.存入数据类型 Hbase里面,rowkey是按照字典序进行排序.存储的value值,当用filter进行数据筛选的时候,所用的比较算法也是字典序的. 1.当存储的value值是float类型的时候 ...

  3. Python小爬虫——抓取豆瓣电影Top250数据

    python抓取豆瓣电影Top250数据 1.豆瓣地址:https://movie.douban.com/top250?start=25&filter= 2.主要流程是抓取该网址下的Top25 ...

  4. 实现HBase增量入库(HBase删除自定义时间戳行数据)

    目录 1. 背景描述 2. 问题描述 3. 解决方案 1. 背景描述 目前在做音乐推荐项目,前期做排序模型优化,任务是使用模型对用户的历史音乐进行排序,有6800多万个用户,约40G的用户数据,使用H ...

  5. Python 3.6 抓取微博m站数据

    Python 3.6 抓取微博m站数据 2019.05.01 更新内容 containerid 可以通过 "107603" + user_id 组装得到,无需请求个人信息获取: 优 ...

  6. 使用python抓取婚恋网用户数据并用决策树生成自己择偶观

    最近在看<机器学习实战>的时候萌生了一个想法,自己去网上爬一些数据按照书上的方法处理一下,不仅可以加深自己对书本的理解,顺便还可以在github拉拉人气.刚好在看决策树这一章,书里面的理论 ...

  7. 使用 Python 抓取欧洲足球联赛数据

    Web Scraping在大数据时代,一切都要用数据来说话,大数据处理的过程一般需要经过以下的几个步骤    数据的采集和获取    数据的清洗,抽取,变形和装载    数据的分析,探索和预测    ...

  8. 抓取Js动态生成数据且以滚动页面方式分页的网页

    代码也可以从我的开源项目HtmlExtractor中获取. 当我们在进行数据抓取的时候,如果目标网站是以Js的方式动态生成数据且以滚动页面的方式进行分页,那么我们该如何抓取呢? 如类似今日头条这样的网 ...

  9. 如何用python抓取js生成的数据 - SegmentFault

    如何用python抓取js生成的数据 - SegmentFault 如何用python抓取js生成的数据 1赞 踩 收藏 想写一个爬虫,但是需要抓去的的数据是js生成的,在源代码里看不到,要怎么才能抓 ...

随机推荐

  1. Linux学习之路:shell变量(二)环境变量

    1.env (environment 的缩写)和export显示所有环境变量 2. 环境变量说明 环境变量 意义 HOME 用户主文件夹相当于“~” SHELL Linux默认为/bin/bash H ...

  2. java.util.regex.PatternSyntaxException: Unexpected internal error near index 1 \ ^

    1 String a = "1991\12\16"; 2 String[] split = a.split("\\"); 3 System.out.printl ...

  3. /lib /usr/lib /usr/local/lib 的区别

    /lib是内核级的,/usr/lib是系统级的,/usr/local/lib是用户级的. /lib/ — 包含许多被 /bin/ 和 /sbin/ 中的程序使用的库文件.目录 /usr/lib/ 中含 ...

  4. 基于Selenium2+Java的UI自动化(2) - 启动浏览器

    一.准备工作 我们常用的浏览器主要有三个:chrome.Firefox.IE:其中chrome 和 IE 需要下载驱动程序,才能启动浏览器,注意驱动程序有32位和64位两种. 另外:如何查看本机的浏览 ...

  5. jquery animate() 防止多次执行

    参考:关于jquery 怎样让 animate不多次执行呢 当click方法里面,执行animate时,然后点击的比较频繁,那么animate()的动画也会比较多次滚动. 如: function sc ...

  6. List集合即其遍历

    1. 首先List<E>集合继承与Collection<E>,是一个接口. ①  Collection (集合框架是JDK1.2版本出现的) ②   list:是有序的,元素可 ...

  7. HW—可怕的阶乘n!__注意大数据函数的使用BigInteger

    java.math.BigInteger系列教程(四)BigInteger的诞生原因 为什么java里面要出现BigInteger类型呢?相信很多人有这个疑问,其实原因很简单,它可以表达更大范围的数值 ...

  8. HTML——表格table标签,tr或者td

    表格定义和用法 <tr> 标签定义 HTML 表格中的行. tr 元素包含一个或多个 th 或 td 元素. HTML 与 XHTML 之间的差异 在 HTML 4.01 中,tr 元素的 ...

  9. oracle中存储过程的使用

    存储过程 刚开始我接触到数据库的时候,感觉存储过程是很难的,但是当你看完我给你列举的例子,你就能够轻松的掌握存储过程的创建和使用了. 存储过程是在大型数据库系统中存储过程在数据库中经过第一次编译后就不 ...

  10. ReactiveCocoa入门教程——第二部分(转)

    ReactiveCocoa是一个框架,它能让你在iOS应用中使用函数响应式编程(FRP)技术.在本系列教程的第一部分中,你学到了如何将标准的动作与事件处理逻辑替换为发送事件流的信号.你还学到了如何转换 ...