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


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


 


 


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


 




Java代码  hbase 取多个版本数据_服务器


  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.   
  11. 然后获取HTable的实例,调用Put方法,更新入库。  


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




Java代码  hbase 取多个版本数据_服务器


  1. this.timestamp  


它的值是:




Java代码  hbase 取多个版本数据_服务器


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


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




Java代码  hbase 取多个版本数据_服务器


  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.   
  13. 然后获取HTable实例调用方法   
  14. public Result get(final Get get) throws IOException  
  15.   
  16. 返回的Result对象 调用   
  17.  public byte [] getValue(byte [] family, byte [] qualifier)  
  18.   
  19. 就可以获取值。  


 


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


 


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


 




Java代码  hbase 取多个版本数据_服务器


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


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




Java代码  hbase 取多个版本数据_服务器


  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  


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


 




Java代码  hbase 取多个版本数据_服务器


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


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


 


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


 


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


 


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


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


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


 


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


 


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




Java代码  hbase 取多个版本数据_服务器


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