Hbase之数据模型与操作

0 前言

Hbase是apache社区维护的KV、列式存储的NoSQL数据库,类似于goolgle的Bigtable,可以依附于不同的文件系统,如HDFS,S5,就如bigtable一样依附于GFS文件系统一样。

1 Data Model(数据模型)

1.1 NameSpace

namespace就类似于传统数据库中的database,主要是用来对不同的表进行分类与管理,Hbase默认已经定义好的namespace有2个:default、hbase。

常用的namespace的操作如下。

# 创建一个namespace : my_ns
create_namespace 'my_ns'

# 在my_ns命名空间中创建一个表,hbase中的column family由于动态创建代价太大,一般都是预定义,其中my_table是表名,其中fam是该表中的预先定义的column family
create 'my_ns:my_table', 'fam'

# 删除一个命名空间
drop_namespace 'my_ns'

# 修改一个命名空间的属性
alter_namespace 'my_ns', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}

1.2 Table

table在Hbase中的概念就如传统数据库中的table,只是该table支持稀疏存储,支持动态的数据类型,可以存储任何数据,可以存储海量数据,常用的Table DDL操作如下。

create 'mytable','cf1'
#删除一个table的时候,必须先禁用该表的操作
disatble 'mytable'
drop 'mytable'

# 此外我们还可给table进行alter添加或者修改默认配置项

1.3 Row

在Hbase中,逻辑上是按照不同的row进行组织的,每个rowkey对应一条数据,同时rowkey是按照字典顺序进行排序的,所以rowkey的设计非常重要,rowkey在物理存储的层面是按照字节数组进行存储的,空的字节数组代表命名空间的开始和结束。

1.4 Column

因为在hbase中,物理上所有的数据都是按照列式存储的,所以在hbase中是有列的概念,实际上column是由多个 column family下的多个column qualifier组成的。

1.5 Column Family

Hbase的Table实际上是由Row和Column Family组成,其中Column Family的中文释义是列簇,不同的列簇一般存放不同的数据,列簇可以由不同的Column Qualifier组成,在Hbase中简单的一行案例如下。

  • Column Family一般是在创建table的时候预先定义好的,修改列簇。
create 'tableA','f1','f2'
#往tableA的f1列簇下添加name属性以及值,Hbase更像一个KV存储
put 'tableA','f1:name','hello'

1.6 Column Qualifier

Hbase的Column Family是固定的,但是一个Column Family下面理论上可以有不设限的Column Qualifier的数量,Column Family与Column Qualifier之间使用:进行分割。

columnfamily1:name #其中name就是一个属性的修饰

1.7 Cell

因为Hbase是列式存储,每个Row与Column的交接点就是一个Cell或者多个cell,一般通过一个{row,column,version}确定一个Cell,每个Cell实际上是不设限的字节,这也就保证了hbase可以存储所有类型的数据。

1.8 version

Hbase通过一个{row,column,version}确定一个Cell,所以在row与column的交界处可能会有无数个cells,rowkey和columnfamily:columnqualifier描述都相同,但是只有version这个维度是不同的,Hbase的所有数据都按照byte数组进行存储,除了version,它按照long类型存储,通常是当前日期的时间戳,你可以在插入数据的时候手动指定该long类型的version值。

  • 如果对相同的数据有着相同的version,那么最后一次写入的version是可获取的数据。
  • 写入数据的时候可以不按照升序的方式进行写入。

1.8.1 如何指定存储的最大version数量

hbase存储的最大的版本数量是列模式的一部分,version可以在创建表的时候创建 ,也可以通过alter命令行的方式修改HColumnDescriptor.DEFAULT_VERSIONS.

  • 在Hbase0.96之前,保留的默认的最大版本数为3
  • 在Hbase0.96及以后,保留的默认的最大版本数为1

简单的示例如下,通过hbase shell保留f1列簇中的所有列的最多5个版本。

hbase> alter't1',NAME =>'f1',VERSIONS => 5

我们还可以通过Hbase的JavaAPI使用HColumnDescriptor来进行版本的指定与修改。

在Hbase0.98.2开始,我们可以通过hbase.column.max.version在hbase-site.xml中指定该参数的默认值。

1.8.2 如何指定存储的最小version数量

hbase> alter't1',NAME =>'f1',MIN_VERSIONS => 2

2 Data Model Operations

2.1 get

get操作是在Table的基础上进行操作的,可以按照1个或者多个rowkey的信息fetch到对应的数据,get是以rowkey为粒度的,通过Table.get进行操作。

table = conn.getTable()
  
table.get(new Get())
table.get(List<Get> gets)

2.2 put

put操作是往Hbase的table中写入数据,也是以rowkey为粒度。

table = conn.getTable()

table.put(new Put().add...)

2.3 scan

scan操作允许扫描table获取多个Rows的数据,可以对rowkey作限定,比如说一下案例,只扫描以“row”开头的行的数据

public static final byte[] CF = "cf".getBytes();
public static final byte[] ATTR = "attr".getBytes();
...

Table table = ...      // instantiate a Table instance

Scan scan = new Scan();
scan.addColumn(CF, ATTR);
scan.setRowPrefixFilter(Bytes.toBytes("row"));
ResultScanner rs = table.getScanner(scan);
try {
  for (Result r = rs.next(); r != null; r = rs.next()) {
    // process result...
  }
} finally {
  rs.close();  // always close the ResultScanner!
}

!请注意,为扫描指定特定停止点的最简单方法是使用InclusiveStopFilter类。

2.4 delete

delete,从表中删除一行,通过table.delete执行,Hbase在物理层面不会立刻删除数据,而是通过创建标记的形式来判别数据是否删除,等到major compaction的时候再将flag=删除的数据进行清理操作。

table.delete(new Delete()...)