HBase如何存取多个版本的值

阅读更多

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

 

 

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

 

/**
   * Add the specified column and value to this Put operation.
   * @param family family name
   * @param qualifier column qualifier
   * @param value column value
   */
  public Put add(byte [] family, byte [] qualifier, byte [] value) {
    return add(family, qualifier, this.timestamp, value);
  }

然后获取HTable的实例,调用Put方法,更新入库。
 

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

this.timestamp

它的值是:

  private long timestamp = HConstants.LATEST_TIMESTAMP;

  static final long LATEST_TIMESTAMP = Long.MAX_VALUE;
 

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

创建一个Put的实例
/**
   * Create a Get operation for the specified row.
   * 

* If no further operations are done, this will get the latest version of * all columns in all families of the specified row. * @param row row key */ public Get(byte [] row) { this(row, null); } 然后获取HTable实例调用方法 public Result get(final Get get) throws IOException 返回的Result对象 调用 public byte [] getValue(byte [] family, byte [] qualifier) 就可以获取值。

 

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

 

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

 

/**
 * Test get value of multi versions
 * 
 * @author dev-cjj
 * 
 */
public class GetRowVersionsTest extends TestCase
{
    private final byte[] family     = Bytes.toBytes("log");

    private final byte[] qualifier  = Bytes.toBytes("q1");

    private final byte[] qualifier2 = Bytes.toBytes("q2");

    private final byte[] rowKey     = Bytes.toBytes(10001);

    private final HTable table      = IDMHBaseConfiguration.getTable("testTable");

    private final long   ts1        = 1298529542218L;

    private final long   ts2        = ts1 + 100;

    private final long   ts3        = ts1 + 1000;

    private final long   ts4        = ts1 + 2000;

    private final long   ts5        = ts1 + 3000;

    private final byte[] value1     = Bytes.toBytes("value1");

    private final byte[] value2     = Bytes.toBytes("value2");

    private final byte[] value3     = Bytes.toBytes("value3");

    private final byte[] value4     = Bytes.toBytes("value4");

    private final byte[] value5     = Bytes.toBytes("value5");

    private void insert(final long ts, final byte[] value) throws IOException
    {
        //        table.setAutoFlush(false);
        final Put put = new Put(rowKey);
        put.add(family, qualifier, ts, value);
        put.add(family, qualifier2, ts, value);
        table.put(put);
    }

    private void sleep()
    {
        try
        {
            Thread.sleep(1000);
        }
        catch (final InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    @Test
    public void testGetRowMultipleVersions() throws Exception
    {
        insert(ts1, value1);
        sleep();
        insert(ts2, value2);
        sleep();
        insert(ts3, value3);
        sleep();
        insert(ts4, value4);
        sleep();
        insert(ts5, value5);
        sleep();

        // check getRow with multiple versions
        final Get get = new Get(rowKey);
        get.setMaxVersions();
        final Result r = table.get(get);

        // one way get values of all version
        //        final List list = r.list();
        //        for (final KeyValue kv : list)
        //        {
        //            System.err.println(Bytes.toString(kv.getKey()));
        //            System.err.println(kv.getTimestamp());
        //            System.err.println(Bytes.toString(kv.getValue()));
        //        }

        // another way get values of all version
        final NavigableMap>> map = r.getMap();
        final NavigableMap> familyMap = map.get(family);
        final NavigableMap versionMap = familyMap.get(qualifier);
        for (final Map.Entry entry : versionMap.entrySet())
        {
            System.err.println(Bytes.toString(qualifier) + " -> " + Bytes.toString(entry.getValue()));
        }

        final NavigableMap versionMap2 = familyMap.get(qualifier2);
        for (final Map.Entry 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(new Delete(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
 

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

 

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

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

 

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

 

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

 

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

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

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

 

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

 

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

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

 

 

 

你可能感兴趣的:(HBase,应用服务器,thread)