HBase总结(1)-- 数据插入与Put对象

来源:互联网 发布:淘宝上哪家日代靠谱 编辑:程序博客网 时间:2024/05/17 14:18

一、介绍

HBase的客户端包中集中了CURD操作,用户可以通过其中不同种类的API尽心CURD操作。HBase数据插入使用Put对象,Put对象在进行数据插入时,首先会想Hbase集群发送一个RPC请求,得到响应后将Put类中的数据通过序列化的方式传给HBase集群,集群节点拿到数据后进行添加功能。

二、数据插入详解

HBase客户端拥有多重方式进行数据插入,通过调整不同的属性从而实现不同插入方式。

1、单行插入:put(Put p)

单行插入即每一次插入一行数据

public void put(String tableName,String rowKey,String family,String column,String value){Configuration conf=init();try {HTable table=new HTable(conf,TableName.valueOf(tableName));HBaseAdmin admin=new HBaseAdmin(conf);//判断表是否存在,如果不存在进行创建if(!admin.tableExists(Bytes.toBytes(tableName))){HTableDescriptor tableDescriptor=new HTableDescriptor(Bytes.toBytes(tableName));HColumnDescriptor columnDescriptor=new HColumnDescriptor(Bytes.toBytes(family));tableDescriptor.addFamily(columnDescriptor);admin.createTable(tableDescriptor);}table.setAutoFlush(true);//进行数据插入Put put=new Put(Bytes.toBytes(rowKey));put.add(Bytes.toBytes(family),Bytes.toBytes(column),Bytes.toBytes(value));table.put(put);table.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}

HTable.put(Put p)方法想表中添加一行数据。在此过程中会发送一次RPC操作进行请求,并将Put中的数据序列化以后传送给相应的服务器进行数据插入。

2、批量插入:put(List<Put> list)

批量插入中生成一个List容器,然后将多行数据全部转载到该容器中,然后通过客户端的代码一次将多行数据进行提交

public void putList(String tableName,String[] rowKeys,String[] families,String[] columns,String[] values){Configuration conf=init();try {HBaseAdmin admin=new HBaseAdmin(conf);HTable table=new HTable(conf,tableName.valueOf(tableName));int length=rowKeys.length;List<Put> putList=new ArrayList<>();if(!admin.tableExists(Bytes.toBytes(tableName))){System.err.println("the "+tableName+" is not exist");System.exit(1);}for(int i=0;i<length;i++){Put put=new Put(Bytes.toBytes(rowKeys[i]));put.add(Bytes.toBytes(families[i]),Bytes.toBytes(columns[i]),Bytes.toBytes(values[i]));putList.add(put);}table.put(putList);table.close();} catch (Exception e) {// TODO: handle exception}}
多行插入的本质就是对List容器中的所有对象进行迭代,然后通过 HTable.put(Put p)方法进行多次插入操作。这样的批量操作将会发送多次PRC请求。

3、检查并写入:checkAndPut(byte[] row, byte[] family, byte[] qualifier, byte[] value,Put put)

该方法提供了一种原子性操作,即该操作如果失败,则操作中的所有更改都失效。该函数在多个客户端对同一个数据进行修改时将会提供较高的效率。

public void checkAndPut(String tableName,String row,String family,String column,String value){Configuration conf=init();try {HBaseAdmin admin=new HBaseAdmin(conf);if(!admin.tableExists(Bytes.toBytes(tableName))){System.err.println("the table "+tableName+" is not exist");System.exit(1);}HTable table=new HTable(conf, TableName.valueOf(tableName));Put put=new Put(Bytes.toBytes(row));put.addColumn(Bytes.toBytes(family),Bytes.toBytes(column),Bytes.toBytes(value));table.checkAndPut(Bytes.toBytes(row),Bytes.toBytes(family),Bytes.toBytes(column),null, put);table.flushCommits();} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}}
上述代码实现了只有在写入位置的值为Null的时候将才会将数据写入到数据库中。

注意:需要注意的时,checkAndPut方法以及类似的方法(统称为compact and set(CAS)操作)都只能对一行进行原子性操作。当checkAndPut函数中的参数row和参数put中的row不相同时,即该操作已经不再同一行中时,则会抛出异常。

org.apache.hadoop.hbase.DoNotRetryIOException: org.apache.hadoop.hbase.DoNotRetryIOException: Action's getRow must match the passed rowat org.apache.hadoop.hbase.regionserver.HRegion.checkAndMutate(HRegion.java:3276)at org.apache.hadoop.hbase.regionserver.RSRpcServices.mutate(RSRpcServices.java:2102)at org.apache.hadoop.hbase.protobuf.generated.ClientProtos$ClientService$2.callBlockingMethod(ClientProtos.java:32203)at org.apache.hadoop.hbase.ipc.RpcServer.call(RpcServer.java:2114)at org.apache.hadoop.hbase.ipc.CallRunner.run(CallRunner.java:101)at org.apache.hadoop.hbase.ipc.RpcExecutor.consumerLoop(RpcExecutor.java:130)at org.apache.hadoop.hbase.ipc.RpcExecutor$1.run(RpcExecutor.java:107)at java.lang.Thread.run(Thread.java:745)

4、缓存块操作

2方法虽然提供了批量操作,但实际的RPC请求次数没有任何的减少,因此put(List)和多次put(Put p)方法理论上的速率是相同的。而Put对象提供了一种可以打开Put缓存区的方式来提高数据提交的速率。该方式在客户端的内存中提供一块缓存区域,客户端并设置其大小,然后在用户每次进行提交时并不立刻将数据提交给Hbase集群中,而是当所有该缓存区已经满溢的时候将缓存区中的数据通过一次RPC操作,一次提交到HBase集群中去。所以缓存块在进行大量put请求,且数据量较小时将会明显提高效率。

public void startBufferAndInsert(String tableName,String[] rows,String[] families,String[] columns,String[] values)    {        Configuration conf=init();        try {            //检查制定的表是否村存在            HBaseAdmin admin=new HBaseAdmin(conf);            if(!admin.tableExists(Bytes.toBytes(tableName)))            {                System.err.println("the table "+tableName+" is not exist");                System.exit(1);            }            admin.close();            //创建表连接            HTable table=new HTable(conf,TableName.valueOf(tableName));            //将数据自动提交功能关闭            table.setAutoFlush(false);            //设置数据缓存区域            table.setWriteBufferSize(64*1024*1024);             //然后开始写入数据            int length=rows.length;            for(int i=0;i<length;i++)            {                Put put=new Put(Bytes.toBytes(rows[i]));                put.addColumn(Bytes.toBytes(families[i]),Bytes.toBytes(columns[i]),Bytes.toBytes(values[i]));                table.put(put);            }            //刷新缓存区            table.flushCommits();            //关闭表连接            table.close();        } catch (Exception e) {            // TODO: handle exception            e.printStackTrace();        }    }
使用缓存插入方式时,要注意将table的自动填充属性进行关闭,并且在数据插入完成后进行一次手动的提交操作。将缓存区中的数据手动的提交到HBase服务器中。

三、Put类详解

1、主要属性:KeyValue对象数组

Put类中主要含有一个KeyValue对象数组,KeyValue对象是HBase底层存储的一个重要类,代表了数据在底层存储时的状态。KeyValue对象代表了一个Hbase表中的一个数据单元,即含有行值(row)、列簇(family)、列(column)、时间戳(timestamp)和值(value),从这些信息能够在表中唯一确定一个数据单元。在KeyValue对象中,Key(键)包含了一个value值的row、family、column和timestamp信息,而value则是该表单元格的数据。

当插入一条数据时,其实就是讲KeyValue进行序列化后,然后传递后Hbase集群,集群在根据KeyValue的值进行相应的操作。

2、主要方法

(1)Put(byte[] row) / Put(byte[] row,RowLock lock)

初始化函数,一个Put对象值代表一行数据,但是因为其内部含有多个KeyValue键值对,Put对象可以填充多个列簇(family)、列(qualifier),甚至是多时间戳(timestampe)数据。第二个函数中有行锁(RowLock)参数,用户可以通过设定该参数指定一个行锁。一般来说系统在进行Put时会对put所在的行添加一个行锁。系统并不提倡用户自己定义行锁,因为可能在多个用户指定多个行锁时会造成死锁的情况,导致系统资源在两个客户端断开连接之前一直被占用。

(2)add(Cell kv) / add(byte[] family, byte[] qualifier, long ts, byte[] value) /addColumn(byte[] family, ByteBuffer qualifier, long ts, ByteBuffer value)  / addImmutable(byte[] family, byte[] qualifier, long ts, byte[] value, org.apache.hadoop.hbase.Tag[] tag)

这四种方法都是想Put对象中添加单元数据,即增加一个KeyValue对象。

A、添加Cell对象,Cell类可以引用KeyVakue的对象,因此此处也可以插入KeyValue对象,因此即可将该函数理解为插入一个完整的KeyValue对象即可

B、添加列簇、列、时间戳、值,Put对象会在接收这些数据后将其初始化成一个KeyValue对象,不过该方法已经废弃,不建议使用

C、该方法和第二方法作用相同

D、添加恒定数据,通过该方法添加一个恒定的KeyValue对象值,具体效果没有试验过

(3)has(byte[] family, byte[] qualifier, byte[] value)

判断Put对象中是否含有制定的value值/列/列簇,返回值为Boolean值

(4)setWriteToWAL(boolean write)

是否将数据写入到预写日志(Write-Ahead-Log)中,预写日志是一种数据保护措施,如果当HBase某一个节点故障时,可以通过预写日志中的记录的数据操作进行数据恢复。该选项如果打开,数据会被写入到预写日志中,安全性增加,但是会损耗一定性能,如果不打开,则损耗变小,安全性降低

(5)setTTL(long ttl)

ttl毫秒数。该函数对该行中的所有的KeyValue对象设置TTL,TTL(Time-To-Live)的作用是从数据产生起,经过TTL时间后就会被作为废弃数据而被删除掉。

(6)setDurability(Durability d)

该函数对写入WAL模式进行设定。可填充的值为:Durability.ASYNC_WAL(异步进行数据写入)、Durability.SYNC_WAL(同步进行写入)、Durabiliry.SKIP_WAL(不进行WAL填写)、Durability.FSYNC_WAL(强制同步进行WAL写入)、Durability.USE_DEFAULT(默认选项,为SYNC_WAL选项)

(7)其他方法

A、getRow()  获取创建Put实例时的行健

B、getRowLock()   获取创建Put实例时的行锁

C、getLockId()    返回使用rowlock参数传递给构造函数的可选的锁ID,当违背制定时放回-1L

D、getTimeStamp()   获取相应Put实例的时间戳,改制在构造函数中有ts参数传入,如果没有指定的话则返回 Long.MAX_VALUE

E、isEmpty()   返回该Put实例中是否含有KeyValue实例

F、numFamilies()   返回该Put实例中的列簇数量

G、size()   返回本次Put对象添加的KeyValue实例的数量

四、总结

通过Put的设计,我们能够体会到一些HBase底层的设计结构,因此需要好好理解KeyValue对象。上面便是笔者对Hbase Put进行输入插入的裂解,如果有什么错误的地方请指出,希望共同进步



1 0