http://jiajun.iteye.com/blog/945358
HBase如何存取多个版本的值?
废话少说,一般情况下使用Put的这个方法保存一个版本:
- /**
- *AddthespecifiedcolumnandvaluetothisPutoperation.
- *@paramfamilyfamilyname
- *@paramqualifiercolumnqualifier
- *@paramvaluecolumnvalue
- */
- publicPutadd(byte[]family,byte[]qualifier,byte[]value){
- returnadd(family,qualifier,this.timestamp,value);
- }
- 然后获取HTable的实例,调用Put方法,更新入库。
这里我要刻意说明一下时间戳 ,可以看到上面的add方面实现里面调用了另外一个方法,增加了个参数:默认时间戳
它的值是:
- privatelongtimestamp=HConstants.LATEST_TIMESTAMP;
- staticfinallongLATEST_TIMESTAMP=Long.MAX_VALUE;
那么获取的时候,获取一个值 也很简单,使用下面的方法:
- 创建一个Put的实例
- /**
- *CreateaGetoperationforthespecifiedrow.
- *<p>
- *Ifnofurtheroperationsaredone,thiswillgetthelatestversionof
- *allcolumnsinallfamiliesofthespecifiedrow.
- *@paramrowrowkey
- */
- publicGet(byte[]row){
- this(row,null);
- }
- 然后获取HTable实例调用方法
- publicResultget(finalGetget)throwsIOException
- 返回的Result对象调用
- publicbyte[]getValue(byte[]family,byte[]qualifier)
- 就可以获取值。
一般的应用可以像上面这样来解决,服务器正常的话不会碰到什么问题,可是要存取多个版本 的话,有可能你会遇到我遇到的问题。 看下面一段代码是否有问题 ?
(里面有如何插入多个版本 ,如何获取多个版本 的方法,顺带说明一个问题)
- /**
- *Testgetvalueofmultiversions
- *
- *@authordev-cjj
- *
- */
- publicclassGetRowVersionsTestextendsTestCase
- {
- privatefinalbyte[]family=Bytes.toBytes("log");
- privatefinalbyte[]qualifier=Bytes.toBytes("q1");
- privatefinalbyte[]qualifier2=Bytes.toBytes("q2");
- privatefinalbyte[]rowKey=Bytes.toBytes(10001);
- privatefinalHTabletable=IDMHBaseConfiguration.getTable("testTable");
- privatefinallongts1=1298529542218L;
- privatefinallongts2=ts1+100;
- privatefinallongts3=ts1+1000;
- privatefinallongts4=ts1+2000;
- privatefinallongts5=ts1+3000;
- privatefinalbyte[]value1=Bytes.toBytes("value1");
- privatefinalbyte[]value2=Bytes.toBytes("value2");
- privatefinalbyte[]value3=Bytes.toBytes("value3");
- privatefinalbyte[]value4=Bytes.toBytes("value4");
- privatefinalbyte[]value5=Bytes.toBytes("value5");
- privatevoidinsert(finallongts,finalbyte[]value)throwsIOException
- {
- //table.setAutoFlush(false);
- finalPutput=newPut(rowKey);
- put.add(family,qualifier,ts,value);
- put.add(family,qualifier2,ts,value);
- table.put(put);
- }
- privatevoidsleep()
- {
- try
- {
- Thread.sleep(1000);
- }
- catch(finalInterruptedExceptione)
- {
- e.printStackTrace();
- }
- }
- @Test
- publicvoidtestGetRowMultipleVersions()throwsException
- {
- insert(ts1,value1);
- sleep();
- insert(ts2,value2);
- sleep();
- insert(ts3,value3);
- sleep();
- insert(ts4,value4);
- sleep();
- insert(ts5,value5);
- sleep();
- //checkgetRowwithmultipleversions
- finalGetget=newGet(rowKey);
- get.setMaxVersions();
- finalResultr=table.get(get);
- //onewaygetvaluesofallversion
- //finalList<KeyValue>list=r.list();
- //for(finalKeyValuekv:list)
- //{
- //System.err.println(Bytes.toString(kv.getKey()));
- //System.err.println(kv.getTimestamp());
- //System.err.println(Bytes.toString(kv.getValue()));
- //}
- //anotherwaygetvaluesofallversion
- finalNavigableMap<byte[],NavigableMap<byte[],NavigableMap<Long,byte[]>>>map=r.getMap();
- finalNavigableMap<byte[],NavigableMap<Long,byte[]>>familyMap=map.get(family);
- finalNavigableMap<Long,byte[]>versionMap=familyMap.get(qualifier);
- for(finalMap.Entry<Long,byte[]>entry:versionMap.entrySet())
- {
- System.err.println(Bytes.toString(qualifier)+"->"+Bytes.toString(entry.getValue()));
- }
- finalNavigableMap<Long,byte[]>versionMap2=familyMap.get(qualifier2);
- for(finalMap.Entry<Long,byte[]>entry:versionMap2.entrySet())
- {
- System.err.println(Bytes.toString(qualifier2)+"->"+Bytes.toString(entry.getValue()));
- }
- //assertTrue(versionMap.size()==5);
- //assertTrue(value1==versionMap.get(ts1));
- //assertTrue(value2==versionMap.get(ts2));
- //assertTrue(value3==versionMap.get(ts3));
- //table.delete(newDelete(rowKey));
- //assertTrue(table.get(get).size()==0);
- //table.close();
- }
- }
这里我只是打印输出结果 ,不用断言, 结果如你所期望的是:
- q1->value5
- q1->value4
- q1->value3
- q1->value2
- q1->value1
- q2->value5
- q2->value4
- q2->value3
- q2->value2
- q2->value1
上面的代码中,我注视掉了一个关键行
如果取消注释,再运行几次你会发现一个大问题! 保存不上了,一个版本都没有。
final Result r = table.get(get); 里面什么都不会有! 很奇怪!
问题原因 (针对上面的代码和问题):
1、插入的时候使用的时间戳都是过去的时间戳。
2、删除的时候没有指定时间戳(如果没有指定则默认一个当前的时间戳)
3、在HBase中删除操作并没有删除对应的文件,只是做一个带有时间戳的删除标记(任何在这个时间戳之前的列值都会被认为是删除的)
那么知道上面三条规则,问题就简单了,新插入的列值的时间戳要在删除标记的时间戳之后,才会被认为是不被删除的列值。
补充一点,创建/添加列族时候默认是三个版本,可以修改为1个版本或者更多个版本,我上面5个版本是因为我指定了5个版本。