天天看点

《HBase权威指南》一3.2 CRUD操作

本节书摘来异步社区《hbase权威指南》一书中的第3章,第3.2节,作者: 【美】lars george 译者: 代志远 , 刘佳 , 蒋杰 责编: 杨海玲,更多章节内容可以访问云栖社区“异步社区”公众号查看。

数据库的初始基本操作通常被称为crud(create,read,update,delete),具体指增、查、改、删。hbase中有与之相对应的一组操作,随后我们会依次介绍。这些方法都由htable类提供,本章后面将直接引用这个类的方法,不再特别提到这个包含类。

接下来介绍的操作大多都能不言自明,但本书有一些细节需要大家注意。这意味着,对于书中出现的一些重复的模式,我们不会多次赘述。

读者一开始会在一些程序的开头看到import语句,但为了简洁,后续将会省略import语句。同时,一些与主题不太相关的代码部分也会被省略。如有疑问,请到上面的地址中查阅完整源代码。

下面介绍的这组操作可以被分为两类:一类操作用于单行,另一类操作用于多行。鉴于后面有一些内容比较复杂,我们会分开介绍这两类操作。同时,我们还会介绍一些衍生的客户端api特性。

1.单行put

也许你现在最想了解的就是如何向hbase中存储数据,下面就是实现这个功能的调用:

这个方法以单个put或存储在列表中的一组put对象作为输入参数,其中put对象是由以下几个构造函数创建的:

创建put实例时用户需要提供一个行键row,在hbase中每行数据都有唯一的行键(row key)作为标识,跟hbase的大多数数据类型一样,它是一个java的byte[]数组。用户可以按自己的需求来指定每行的行键,且可以参考第9章,其中专门有一节详细讨论了行键的设计(见9.1节)。现在我们假设用户可以随意设置行键,通常情况下,行键的含义与真实场景相关,例如,它的含义可以是一个用户名或者订单号,它的内容可以是简单的数字,也可以是较复杂的uuid②等。

hbase非常友好地为用户提供了一个包含很多静态方法的辅助类,这个类可以把许多java数据类型转换为byte[]数组。例3.1提供了方法的部分清单。

例3.1 bytes类所提供的方法

...

创建put实例之后,就可以向该实例添加数据了,添加数据的方法如下:

每一次调用add()都可以特定地添加一列数据,如果再加一个时间戳选项,就能形成一个数据单元格。注意,当不指定时间戳调用add()方法时,put实例会使用来自构造函数的可选时间戳参数(也称作ts),如果用户在构造put实例时也没有指定时间戳,则时间戳将会由region服务器设定。

系统为一些高级用户提供了keyvalue实例的变种,这里所说的高级用户是指知道怎样检索或创建这个内部类的用户。keyvalue实例代表了一个唯一的数据单元格,类似于一个协调系统,该系统使用行键、列族、列限定符、时间戳指向一个单元格的值,像一个三维立方体系统(其中,时间成为了第三维度)。

获取put实例内部添加的keyvalue实例需要调用与add()相反的方法get():

以上两个方法可以查询用户之前添加的内容,同时将特定单元格的信息转换成keyvalue实例。用户可以选择获取整个列族(column family)的全部数据单元,一个列族中的特定列或是全部数据。后面的getfamilymap()方法可以遍历put实例中每一个可用的keyvalue实例,检查其中包含的详细信息。

图像说明文字每一个keyvalue实例包含其完整地址(行键、列族、列限定符及时间戳)和实际数据。keyvalue是hbase在存储架构中最底层的类。8.2节将会详细介绍相关内容。对于客户端api所用到的keyvalue类中的方法参见3.2.1节。

用户可以采用以下这些方法检查是否存在特定的单元格,而不需要遍历整个集合:

随着以上方法所使用参数的逐步细化,获得的信息也越详细,当找到匹配的列时返回true。第一个方法仅检查一个列是否存在,其他的方法则增加了检查时间戳、限定值的选项。

put类还提供了很多的其他方法,在表3-1中进行了概括。

《HBase权威指南》一3.2 CRUD操作
文字注意,表3-1所列的put类中的那些getter函数仅能够获取用户预先设定的内容,实际应用中很少用到它们,仅当用户在代码的私有方法中准备实现一个put实例,并在其他地方检查其内容时,才会用到它们。

例3.2展示了如何在一个简单的程序里使用上述方法。

文字本章的示例使用了一个非常有限的精确数据集。当读者查看整个源代码时,会注意到源代码使用了一个名叫hbasehelper的内部类。该内部类会创建一个有特定行和列数量的数据测试表。这让我们更容易对比处理前后的差异。

读者可以将代码直接放到本地主机上的独立hbase实例中来测试,也可以放到hbase集群上测试。前言中的“编译示例程序”一节解释了如何编译这些例子。读者可以大胆地修改这部分代码,以便更好地体会各部分功能。

为了清除前一步示例程序执行时产生的数据,示例代码通常会删除前一步执行时所创建的表。如果你在生产集群上运行示例,请先确保表名无冲突。通常示例代码创建的表为testtable,这个名称容易让人联想到表的用途。

例3.2 向hbase插入数据的示例应用

创建所需的配置。

实例化一个新的客户端。

指定一行来创建一个put。

向put中添加一个名为“colfam1:qual1”的列。

向put中添加另一个名为“colfam1:qual2”的列。

将这一行存储到hbase表中。

这个示例代码(几乎)十分完整,并且每一行都进行了解释。以后的示例会逐渐减少样板代码,以便读者能将注意力集中到重要的部分。

通过客户端代码访问配置文件

2.6.7节介绍了hbase客户端应用程序使用的配置文件。应用程序需要通过默认位置(classpath)下的hbase-site.xml文件来获知如何访问集群,此外也可以在代码里指定集群的地址。

无论哪种方式,都需要在代码中使用一个hbaseconfiguration类来处理配置的属性。可以使用该类提供的以下静态方法构建configuration实例:

例3.2中使用了create()来获得configuration实例。第二个方法允许你使用一个已存在的配置,该配置会融合并覆盖hbase默认配置。

当你调用任何一个静态create()方法时,代码会尝试使用当前的java classpath来载入两个配置文件:h<code>`</code>javascript

base-default.xml和hbase-site.xml。

hbase(main):001:0&gt;list

table

testtable

1 row(s) in 0.0400 seconds

hbase(main):002:0&gt;scan 'testtable'

row         column+cell

row1        column=colfam1:qual1,timestamp=1294065304642,value=val1

1 row(s) in 0.2050 seconds

hbase(main):001:0&gt; create 'test','cf1

0 row(s) in 0.9810 seconds

hbase(main):002:0&gt; put 'test','row1','cf1','val1'

0 row(s)in 0.0720 seconds

hbase(main):003:0&gt; put 'test','row1','cf1','val2'

0 row(s) in 0.0520 seconds

hbase(main):004:0&gt; scan 'test'

row         column+cell

row1        column=cf1:,timestamp=1297853125623,value=val2

1 row(s) in 0.0790 seconds

hbase(main):005:0&gt; scan 'test',{ versions =&gt; 3 }

row1        column=cf1:,timestamp=1297853122412,value=val1

1 row(s) in 0.0640 seconds

keyvalue(byte[] row, int roffset, int rlength,

  byte[] family, int foffset, int flength, byte[] qualifier, int qoffset,

  int qlength, long timestamp, type type, byte[] value, int voffset,

  int vlength)

byte[] getbuffer()

int getoffset()

int getlength()

byte [] getrow()

byte [] getkey()

treeset&lt; keyvalue&gt; set =

  new treeset&lt; keyvalue&gt;(keyvalue.comparator)

string tostring()

&lt; row-key&gt;/&lt; family&gt;:&lt; qualifier&gt;/&lt; version&gt;/&lt; type&gt;/&lt; value-length&gt;

void setautoflush(boolean autoflush)

boolean isautoflush()

table.setautoflush(false)

void flushcommits() throws ioexception

long getwritebuffersize()

void setwritebuffersize(long writebuffersize) throws ioexception

&lt; property&gt;

  &lt; name&gt;hbase.client.write.buffer&lt; /name&gt;

  &lt; value&gt;20971520&lt; /value&gt;

&lt; /property&gt;

htable table = new htable(conf,"testtable");

system.out.println("auto flush: " + table.isautoflush());

table.setautoflush(false);

put put1 = new put(bytes.tobytes("row1"));

put1.add(bytes.tobytes("colfam1"),bytes.tobytes("qual1"),

  bytes.tobytes("val1"));

table.put(put1);

put put2 = new put(bytes.tobytes("row2"));

put2.add(bytes.tobytes("colfam1"),bytes.tobytes("qual1"),

  bytes.tobytes("val2"));

table.put(put2);

put put3 = new put(bytes.tobytes("row3"));

put3.add(bytes.tobytes("colfam1"),bytes.tobytes("qual1"),

  bytes.tobytes("val3"));

table.put(put3);

get get = new get(bytes.tobytes("row1"));

result res1 = table.get(get);

system.out.println("result: " + res1);

table.flushcommits();

result res2 = table.get(get);

system.out.println("result: " + res2);

auto flush: true

result: keyvalues=none

result: keyvalues={row1/colfam1:qual1/1300267114099/put/vlen=4}

void put(list puts)throws ioexception

list&lt; put&gt; puts = new arraylist&lt; put&gt;();

puts.add(put1);

puts.add(put2);

put put3 = new put(bytes.tobytes("row2"));

put3.add(bytes.tobytes("colfam1"),bytes.tobytes("qual2"),

puts.add(put3);

table.put(puts);

hbase(main):001:0&gt;scan 'testtable'

row       column+cell

 row1      column=colfam1:qual1,timestamp=1300108258094,value=val1

 row2      column=colfam1:qual1,timestamp=1300108258094,value=val2

 row2      column=colfam1:qual2,timestamp=1300108258098,value=val3

2 row(s)in 0.1590 seconds

put2.add(bytes.tobytes("bogus"),bytes.tobytes("qual1"),

org.apache.hadoop.hbase.client.retriesexhaustedwithdetailsexception:

failed 1 action: nosuchcolumnfamilyexception: 1 time,

servers with issues: 10.0.0.57:51640,

 row1        column=colfam1:qual1,timestamp=1300108925848,value=val1

 row2        column=colfam1:qual2,timestamp=1300108925848,value=val3

2 row(s) in 0.0640 seconds

put put4 = new put(bytes.tobytes("row2"));

puts.add(put4);

try {

  table.put(puts);

}  catch(exception e){

system.err.println("error: " + e);

}

error: java.lang.illegalargumentexception: no columns to insert

exception in thread "main"

table.flushcommits()

boolean checkandput(byte[] row,byte[] family,byte[] qualifier,

  byte[] value,put put) throws ioexception

boolean res1 = table.checkandput(bytes.tobytes("row1"),

bytes.tobytes("colfam1"),bytes.tobytes("qual1"),null,put1);

system.out.println("put applied: " + res1);

boolean res2 = table.checkandput(bytes.tobytes("row1"),

system.out.println("put applied: " + res2);

put put2 = new put(bytes.tobytes("row1"));

put2.add(bytes.tobytes("colfam1"),bytes.tobytes("qual2"),

   bytes.tobytes("val2"));

boolean res3 = table.checkandput(bytes.tobytes("row1"),

bytes.tobytes("colfam1"),bytes.tobytes("qual1"),

  bytes.tobytes("val1"),put2);

system.out.println("put applied: " + res3);

 bytes.tobytes("val3"));

boolean res4 = table.checkandput(bytes.tobytes("row1"),

  bytes.tobytes("val1"),put3);

system.out.println("put applied: " + res4);⓫

exception in thread "main" org.apache.hadoop.hbase.donotretryioexception:

action's getrow must match the passed row

result get(get get) throws ioexception

get(byte[] row)

get(byte[] row,rowlock rowlock)

get addfamily(byte[] family)

get addcolumn(byte[] family,byte[] qualifier)

get settimerange(long minstamp,long maxstamp) throws ioexception

get settimestamp(long timestamp)

get setmaxversions()

get setmaxversions(int maxversions) throws ioexception

static string tostring(byte[] b)

static boolean toboolean(byte[] b)

static long tolong(byte[] bytes)

static float tofloat(byte[] bytes)

static int toint(byte[] bytes)

configuration conf = hbaseconfiguration.create();

get.addcolumn(bytes.tobytes("colfam1"),bytes.tobytes("qual1"));

result result = table.get(get);

byte[] val = result.getvalue(bytes.tobytes("colfam1"),

  bytes.tobytes("qual1"));

system.out.println("value: " + bytes.tostring(val));

value: val1

byte[] getvalue(byte[] family,byte[] qualifier)

byte[] value()

byte[] getrow()

int size()

boolean isempty()

keyvalue[] raw()

list list()

list getcolumn(byte[] family,byte[] qualifier)

keyvalue getcolumnlatest(byte[] family,byte[] qualifier)

boolean containscolumn(byte[] family,byte[] qualifier)

navigablemap&lt; byte[],navigablemap&lt; byte[],

 navigablemap&lt; long,byte[]&gt;&gt;&gt; getmap()

navigablemap&lt; byte[],

 navigablemap&lt; byte[],byte[]&gt;&gt; getnoversionmap()

navigablemap&lt; byte[],byte[]&gt; getfamilymap(byte[] family)

keyvalues={row-2/colfam1:col-5/1300802024293/put/vlen=7,

      row-2/colfam2:col-33/1300802024325/put/vlen=8}

keyvalues=none

result[] get(list&lt; get&gt; gets) throws ioexception

byte[] cf1 = bytes.tobytes("colfam1");

byte[] qf1 = bytes.tobytes("qual1");

byte[] qf2 = bytes.tobytes("qual2");

byte[] row1 = bytes.tobytes("row1");

byte[] row2 = bytes.tobytes("row2");

list&lt; get&gt; gets = new arraylist&lt; get&gt;();

get get1 = new get(row1);

get1.addcolumn(cf1,qf1);

gets.add(get1);

get get2 = new get(row2);

get2.addcolumn(cf1,qf1);

gets.add(get2);

get get3 = new get(row2);

get3.addcolumn(cf1,qf2);

gets.add(get3);

result[] results = table.get(gets);

system.out.println("first iteration...");

for(result result : results){

  string row = bytes.tostring(result.getrow());

  system.out.print("row: " + row + " ");

  byte[] val = null;

  if(result.containscolumn(cf1,qf1)){

   val = result.getvalue(cf1,qf1);

    system.out.println("value: " + bytes.tostring(val));

  }

  if(result.containscolumn(cf1,qf2)){

   val = result.getvalue(cf1,qf2);

   system.out.println("value: " + bytes.tostring(val));

system.out.println("second iteration...");

  for(keyvalue kv : result.raw()){

   system.out.println("row: " + bytes.tostring(kv.getrow())+

   " value: " + bytes.tostring(kv.getvalue()));

 }

first iteration...

row: row1 value: val1

row: row2 value: val2

row: row2 value: val3

second iteration...

get get4 = new get(row2);

get4.addcolumn(bytes.tobytes("bogus"),qf2);

gets.add(get4);

system.out.println("result count: " + results.length);

 failed 1 action: nosuchcolumnfamilyexception: 1 time,

 servers with issues: 10.0.0.57:51640,

boolean exists(get get)throws ioexception

result getroworbefore(byte[] row,byte[] family) throws ioexception

result result1 = table.getroworbefore(bytes.tobytes("row1"),

  bytes.tobytes("colfam1"));

system.out.println("found: " + bytes.tostring(result1.getrow()));

result result2 = table.getroworbefore(bytes.tobytes("row99"),

system.out.println("found: " + bytes.tostring(result2.getrow()));

for(keyvalue kv : result2.raw()){

  system.out.println(" col: " + bytes.tostring(kv.getfamily())+

   "/" + bytes.tostring(kv.getqualifier())+

   ",value: " + bytes.tostring(kv.getvalue()));

result result3 = table.getroworbefore(bytes.tobytes("abc"),

system.out.println("found: " + result3);

found: row1

found: row2

  col: colfam1/qual1,value: val2

  col: colfam1/qual2,value: val3

found: null

delete(byte[] row)

delete(byte[] row,long timestamp,rowlock rowlock)

delete deletefamily(byte[] family)

delete deletefamily(byte[] family,long timestamp)

delete deletecolumns(byte[] family,byte[] qualifier)

delete deletecolumns(byte[] family,byte[] qualifier,long timestamp)

delete deletecolumn(byte[] family,byte[] qualifier)

delete deletecolumn(byte[] family,byte[] qualifier,long timestamp)

void settimestamp(long timestamp)

delete delete = new delete(bytes.tobytes("row1"));

delete.settimestamp(1);

delete.deletecolumn(bytes.tobytes("colfam1"),bytes.tobytes("qual1"),1);

delete.deletecolumns(bytes.tobytes("colfam2"),bytes.tobytes("qual1"));

delete.deletecolumns(bytes.tobytes("colfam2"),bytes.tobytes("qual3"),15);

delete.deletefamily(bytes.tobytes("colfam3"));

delete.deletefamily(bytes.tobytes("colfam3"),3);

table.delete(delete);

table.close();

void delete(list deletes) throws ioexception

list&lt; delete&gt; deletes = new arraylist&lt; delete&gt;();

delete delete1 = new delete(bytes.tobytes("row1"));

delete1.settimestamp(4);

deletes.add(delete1);

delete delete2 = new delete(bytes.tobytes("row2"));

delete2.deletecolumn(bytes.tobytes("colfam1"),bytes.tobytes("qual1"));

delete2.deletecolumns(bytes.tobytes("colfam2"),bytes.tobytes("qual3"),5);

deletes.add(delete2);

delete delete3 = new delete(bytes.tobytes("row3"));

delete3.deletefamily(bytes.tobytes("colfam1"));

delete3.deletefamily(bytes.tobytes("colfam2"),3);

deletes.add(delete3);

table.delete(deletes);

before delete call...

kv: row1/colfam1:qual1/2/put/vlen=4,value: val2

kv: row1/colfam1:qual1/1/put/vlen=4,value: val1

kv: row1/colfam1:qual2/4/put/vlen=4,value: val4

kv: row1/colfam1:qual2/3/put/vlen=4,value: val3

kv: row1/colfam1:qual3/6/put/vlen=4,value: val6

kv: row1/colfam1:qual3/5/put/vlen=4,value: val5

kv: row1/colfam2:qual1/2/put/vlen=4,value: val2

kv: row1/colfam2:qual1/1/put/vlen=4,value: val1

kv: row1/colfam2:qual2/4/put/vlen=4,value: val4

kv: row1/colfam2:qual2/3/put/vlen=4,value: val3

kv: row1/colfam2:qual3/6/put/vlen=4,value: val6

kv: row1/colfam2:qual3/5/put/vlen=4,value: val5

kv: row2/colfam1:qual1/2/put/vlen=4,value: val2

kv: row2/colfam1:qual1/1/put/vlen=4,value: val1

kv: row2/colfam1:qual2/4/put/vlen=4,value: val4

kv: row2/colfam1:qual2/3/put/vlen=4,value: val3

kv: row2/colfam1:qual3/6/put/vlen=4,value: val6

kv: row2/colfam1:qual3/5/put/vlen=4,value: val5

kv: row2/colfam2:qual1/2/put/vlen=4,value: val2

kv: row2/colfam2:qual1/1/put/vlen=4,value: val1

kv: row2/colfam2:qual2/4/put/vlen=4,value: val4

kv: row2/colfam2:qual2/3/put/vlen=4,value: val3

kv: row2/colfam2:qual3/6/put/vlen=4,value: val6

kv: row2/colfam2:qual3/5/put/vlen=4,value: val5

kv: row3/colfam1:qual1/2/put/vlen=4,value: val2

kv: row3/colfam1:qual1/1/put/vlen=4,value: val1

kv: row3/colfam1:qual2/4/put/vlen=4,value: val4

kv: row3/colfam1:qual2/3/put/vlen=4,value: val3

kv: row3/colfam1:qual3/6/put/vlen=4,value: val6

kv: row3/colfam1:qual3/5/put/vlen=4,value: val5

kv: row3/colfam2:qual1/2/put/vlen=4,value: val2

kv: row3/colfam2:qual1/1/put/vlen=4,value: val1

kv: row3/colfam2:qual2/4/put/vlen=4,value: val4

kv: row3/colfam2:qual2/3/put/vlen=4,value: val3

kv: row3/colfam2:qual3/6/put/vlen=4,value: val6

kv: row3/colfam2:qual3/5/put/vlen=4,value: val5

after delete call...

system.out.println("kv: " + kv.tostring() +

      ",value: " + bytes.tostring(kv.getvalue()))

delete delete4 = new delete(bytes.tobytes("row2"));

delete4.deletecolumn(bytes.tobytes("bogus"),bytes.tobytes("qual1"));

deletes.add(delete4);

  table.delete(deletes);

} catch(exception e){

  system.err.println("error: " + e);

system.out.println("deletes length: " + deletes.size());

for(delete delete : deletes){

  system.out.println(delete);

error: org.apache.hadoop.hbase.client.retriesexhaustedwithdetailsexception:

  servers with issues: 10.0.0.43:59057,

deletes length: 1

row=row2, ts=9223372036854775807,families={(family=bogus,keyvalues=\

 (row2/bogus:qual1/9223372036854775807/delete/vlen=0)}

boolean checkanddelete(byte[] row,byte[] family,byte[] qualifier,

  byte[] value,delete delete) throws ioexception

delete1.deletecolumns(bytes.tobytes("colfam1"),bytes.tobytes("qual3"));

boolean res1 = table.checkanddelete(bytes.tobytes("row1"),

 bytes.tobytes("colfam2"),bytes.tobytes("qual3"),null,delete1);

system.out.println("delete successful: " + res1);

delete delete2 = new delete(bytes.tobytes("row1"));

delete2.deletecolumns(bytes.tobytes("colfam2"),bytes.tobytes("qual3"));

table.delete(delete2);

boolean res2 = table.checkanddelete(bytes.tobytes("row1"),

system.out.println("delete successful: " + res2);

delete delete3 = new delete(bytes.tobytes("row2"));

try{

  boolean res4 = table.checkanddelete(bytes.tobytes("row1"),

    bytes.tobytes("colfam1"),bytes.tobytes("qual1"),

    bytes.tobytes("val1"),delete3);

 system.out.println("delete successful: " + res4);

delete successful: false

delete successful: true

error: org.apache.hadoop.hbase.donotretryioexception:

 org.apache.hadoop.hbase.donotretryioexception:

  action's getrow must match the passed row