Hbase 笔记(3) 客户端API基础

来源:互联网 发布:数控车床锥度编程实例 编辑:程序博客网 时间:2024/03/29 20:11

1、概述

(1)、HBase 所有修改数据的操作保证行级别的原子性。

(2)、用户应该尽量使用批处理(batch)更新,减少单独操作同一行数据的次数。

(3)、创建表有代价,所以只创建一个HTable,一般在应用程序开始时创建

(4)、使用HTablePool,复用多个实例,例子

        int maxSize = 20;        HTablePool pool = new HTablePool(conf,maxSize);                HTableInterface tableInterface = pool.getTable(strTableName);        Put put = new Put(Bytes.toBytes("row-11"));        put.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-a"));        put.add(Bytes.toBytes("cf2"), Bytes.toBytes("b"), Bytes.toBytes("value-b"));        tableInterface.put(put);

2、PUT操作

(1) .  多个版本

查看多版本:scan  'testtable',  { VERSIONS => 3 }

(2). KeyValue 类,元数据内容

row-key / family:qualifier / version / type / value-length

(3). 客户端的写缓冲区

每一个put操作都是一个RPC操作,启用写缓冲区可将多个put一次RPC送往服务器:

table.setAutoFlush(false);

若需要将缓冲区数据强制写入服务端:

table.flushCommits()

设置写缓冲区大小

table.setWriteBufferSize(long writeBufferSize)  // 默认为 2 M

也可以设置hbase-site.xml 中的 hbase.client.write.buffer

(4). 错误处理

 如果Put 一个列表,里面有一个错误的(使用了不存在的列族);

        Put put1 = new Put(Bytes.toBytes("11111"), System.currentTimeMillis());        put1.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x11"));                 Put put2 = new Put(Bytes.toBytes("22222"), System.currentTimeMillis());         put2.add(Bytes.toBytes("noExist"), Bytes.toBytes("a"), Bytes.toBytes("value-y22"));                Put put3 = new Put(Bytes.toBytes("33333"), System.currentTimeMillis());        put3.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x33"));                 list.add(put1);        list.add(put2);        list.add(put3);        tableInterface.put(list);
抛出以下异常:

org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException: Failed 1 action: org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException: Column family noExist does not exist in region testtable

但是其余两个Put成功

hbase(main):005:0> scan 'testtable'
ROW                   COLUMN+CELL                                                 
 11111                column=cf1:a, timestamp=1416194410866, value=value-x11      
 33333                column=cf1:a, timestamp=1416194410866, value=value-x33 


 如果Put 一个列表,里面有一个为空  ;

        Put put1 = new Put(Bytes.toBytes("11111"), System.currentTimeMillis());        put1.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x11"));        Put put2 = new Put(Bytes.toBytes("22222"), System.currentTimeMillis());        put2.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-y22"));        Put put3 = new Put(Bytes.toBytes("33333"), System.currentTimeMillis());        put3.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x33"));        Put put4 = new Put(Bytes.toBytes("44444"), System.currentTimeMillis());        list.add(put1);        list.add(put2);        list.add(put3);        list.add(put4);        tableInterface.put(list);
将抛出异常:Exception in thread "main" java.lang.IllegalArgumentException: No columns to insert

因为这个错误由客户端检查发现,因此将没有内容写入到数据库。

(5). Put 写入List, 不保证写入的顺序。

(6). 原子操作

Put put1 = new Put(Bytes.toBytes("11111"), System.currentTimeMillis());put1.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x11"));tableInterface.checkAndPut(Bytes.toBytes("11111"),                Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x33"), put1);

3. Get 操作

只获取一个

        Get get = new Get(Bytes.toBytes("row-11"));        get.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        get.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        Result result = table.get(get);                byte[] value1 = result.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        byte[] value2 = result.getValue(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        System.out.println("cf1:a=" + Bytes.toString(value1));        System.out.println("cf2:b=" + Bytes.toString(value2));

获取多个

        Get get1 = new Get(Bytes.toBytes("row-11"));        get1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        get1.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        Get get2 = new Get(Bytes.toBytes("row-22"));        get2.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        get2.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        List<Get> listGet = new ArrayList<Get>();        listGet.add(get1);        listGet.add(get2);                Result[] resutls = table.get(listGet);                for (Result result : resutls) {            byte[] row = result.getRow();            byte[] value1 = result.getValue(Bytes.toBytes("cf1"), Bytes.toBytes("a"));            byte[] value2 = result.getValue(Bytes.toBytes("cf2"), Bytes.toBytes("b"));            System.out.println("rowkey="  + Bytes.toString(row)+", cf1:a=" + Bytes.toString(value1));            System.out.println("rowkey=" +  Bytes.toString(row)+", cf2:b=" + Bytes.toString(value2));        }

如果  table.get(listGet) 操作中, listGet 之中有一个错误,则整个操作终止并抛出异常。


查找某行或者某行之前的一行:

        Result rowOrBefore = table.getRowOrBefore(Bytes.toBytes("row-22"), Bytes.toBytes("cf1"));


4、DELETE 操作

同样也可以delete某1行或者多行,删除特定版本或者多个版本,整个列族或者某个列

也有原子操作: 

        Delete delete = new Delete(Bytes.toBytes("row-11"));        table.checkAndDelete(Bytes.toBytes("row-11"),Bytes.toBytes("cf1"),                 Bytes.toBytes("a"), Bytes.toBytes("value-x33"), delete);

5、批量处理 Batch

可以同时进行Put、Get、Delete 操作

        List<Row> list = new ArrayList<Row>();        Put put1 = new Put(Bytes.toBytes("11111"), System.currentTimeMillis());        put1.add(Bytes.toBytes("cf1"), Bytes.toBytes("a"), Bytes.toBytes("value-x11"));        put1.add(Bytes.toBytes("cf2"), Bytes.toBytes("b"), Bytes.toBytes("value-y11"));        Get get1 = new Get(Bytes.toBytes("11111"));        get1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));            Get get2 = new Get(Bytes.toBytes("33333"));        get1.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));            list.add(put1);        list.add(get1);         list.add(get2);         Object[] results = new Object[list.size()];        try {            tableInterface.batch(list, results);        } catch (InterruptedException ex) {            Logger.getLogger(BatchTest.class.getName()).log(Level.SEVERE, null, ex);        }        for(Object result:results)        {            System.out.println(result);        }

输出:

keyvalues=NONE
keyvalues={11111/cf1:a/1416199179786/Put/vlen=9/mvcc=0}
keyvalues={33333/cf1:a/1416194410866/Put/vlen=9/mvcc=0}

Object[]  results = new Object[list.size()];
tableInterface.batch(list, results);                      // 如果出错,此方法可以访问部分结果        
Object[]  results2 = tableInterface.batch(list);   // 如果出错,此方法不会有任何结果


6、行锁

设置 hbase.regionserver.lease.period 可修改锁超时时间。

在行上创建一个锁,该锁阻塞索引的并发读取。


7、扫描scan

设置 hbase.regionserver.lease.period 可修改扫描器超时时间。

Scan 例子: 

        Scan scan = new Scan();         scan.setStartRow(Bytes.toBytes("11111"));        scan.setStopRow(Bytes.toBytes("333333"));        scan.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        scan.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        ResultScanner scanner = htable.getScanner(scan);                for(Result result : scanner)        {             System.out.println(result);        }        scanner.close();


以上的Scan方法,获取每一个Result 都会生成一个单独的RPC 请求,性能将不会很高。

可用两种方法打开扫描器缓存:

(1). 修改 hbase.client.scanner.caching

(2).  代码中设置 

        Scan scan = new Scan();        scan.setCaching(10);        scan.setStartRow(Bytes.toBytes("11111"));        scan.setStopRow(Bytes.toBytes("333333"));        scan.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        scan.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        ResultScanner scanner = htable.getScanner(scan);                for(Result result : scanner)        {             System.out.println(result);        }        scanner.close();
注意:当数据量非常大的行,这些行有可能超过客户算进程的内存容量,可以如下控制批量获取:

        Scan scan = new Scan();        scan.setCaching(10);        scan.setBatch(5);        scan.setStartRow(Bytes.toBytes("11111"));        scan.setStopRow(Bytes.toBytes("333333"));        scan.addColumn(Bytes.toBytes("cf1"), Bytes.toBytes("a"));        scan.addColumn(Bytes.toBytes("cf2"), Bytes.toBytes("b"));        ResultScanner scanner = htable.getScanner(scan);                for(Result result : scanner)        {             System.out.println(result);        }        scanner.close();
 


setCaching(10): 每次服务器端向客户端传输 10 行 Result 

setBatch(5):每次返回的 Result  包含5 个列


0 0
原创粉丝点击