HBase是一个NoSQL数据库,用于处理海量数据。HBase的特点
- 大:一个表可以有上亿行,上百万列。
- 面向列:面向列表(簇)的存储和权限控制,列(簇)独立检索。
- 稀疏:对于为空(NULL)的列,并不占用存储空间,因此,表可以设计的非常稀疏。
- 无模式:每一行都有一个可以排序的主键和任意多的列,列可以根据需要动态增加,同一张表中不同的行可以有截然不同的列。
- 数据多版本:每个单元中的数据可以有多个版本,默认情况下,版本号自动分配,版本号就是单元格插入时的时间戳。
- 数据类型单一:HBase中的数据都是字符串,没有类型。
首先来了解下HBase的表结构。
为了更好的理解HBase表的思路,先看一下关系数据库中表的处理方式。例如有一个用户表user_info,有字段:id、name、tel,那么表名和字段需要在建表时指定:
create table user_info (
id 类型,
name 类型,
tel 类型
)
然后插入数据: insert into user_info values(...)
此时表结构如下:
id | name | tel |
1 | 小明 | 123 |
2 | 小王 | 456 |
后来字段不够用了,新用户需要记录地址,就要新增一个字段:
id | name | tel | addr |
1 | 小明 | 123 | |
2 | 小王 | 456 |
以后再增加需求时,就继续新增字段,或者添加一个扩展表。
下面看一下HBase的处理方式,HBase建表时要指定的是:表名、列族。建表语句 create 'user_info', 'base_info', 'ext_info'
意思是新建一个表,名称是user_info,包含两个列族base_info和ext_info。列族是列的集合,一个列族中包含多个列,这时的表结构:
row key | base_info | ext_info |
… | … | … |
插入一条用户数据:name为‘a’,tel为‘123’,插入语句
put 'user_info', 'row1', 'base_info:name', 'a'
put 'user_info', 'row1', 'base_info:tel', '123'
意思是向user_info表中行键为row1
的base_info
列族中添加一项数据 name:a
,接着又添加一项数据tel:123
。name和tel就是具体字段,属于base_info
这个列族
这时的表结构:
row key | base_info | ext_info |
row1 | name:a, tel:123 |
再插入一条数据:name为‘b’,addr为‘beijing’:
put 'user_info', 'row2', 'base_info:name', 'b'
put 'user_info', 'row2', 'ext_info:addr', 'bj'
这时的表结构:
row key | base_info | ext_info |
row1 | name:a, tel:123 | |
row2 | name:b | addr:bj |
到此大致对HBase的表结构有了个初步的认识。
HBase数据模型中一些名词的概念:
表(Table): HBase会将数据组织进一张张的表里面,但是需要注意的是表名必须是能用在文件路径里的合法名字,因为HBase的表是映射成hdfs上面的文件。
行(Row): 在表里面,每一行代表着一个数据对象,每一行都是以一个行键(Row Key)来进行唯一标识的,行键并没有什么特定的数据类型,以二进制的字节来存储。
列族(Column Family): 在定义HBase表的时候需要提前设置好列族, 表中所有的列都需要组织在列族里面,列族一旦确定后,就不能轻易修改,因为它会影响到HBase真实的物理存储结构,但是列族中的列标识(Column Qualifier)以及其对应的值可以动态增删。表中的每一行都有相同的列族,但是不需要每一行的列族里都有一致的列标识(Column Qualifier)和值,所以说是一种稀疏的表结构,这样可以一定程度上避免数据的冗余。
列标识(Column Qualifier): 列族中的数据通过列标识来进行映射,其实这里可以不用拘泥于“列”这个概念,也可以理解为一个键值对,Column Qualifier就是Key。列标识也没有特定的数据类型,以二进制字节来存储。
单元(Cell): 每一个行键,列族和列标识共同组成一个单元,存储在单元里的数据称为单元数据,单元和单元数据也没有特定的数据类型,以二进制字节来存储。
时间戳(Timestamp): 默认下每一个单元中的数据插入时都会用时间戳来进行版本标识。读取单元数据时,如果时间戳没有被指定,则默认返回最新的数据,写入新的单元数据时,如果没有设置时间戳,默认使用当前时间。每一个列族的单元数据的版本数量都被HBase单独维护,默认情况下HBase保留3个版本数据。
存储类型
TableName 是字符串
RowKey 和 ColumnName 是二进制值(Java 类型 byte[])
Timestamp 是一个 64 位整数(Java 类型 long)
value 是一个字节数组(Java类型 byte[])。
存储结构
可以简单的将HTable的存储结构理解为
SortedMap (
RowKey, List (
SortedMap (
Column, List (
Value, Timestamp
)
)
)
)
即HTable按Row key自动排序,每个Row包含任意数量个Columns,Columns之间按Column key自动排序,每个Column包含任意数量个Values。理解该存储结构将有助于查询结果的迭代。
下图可以帮助理解一下存储结构: