HBase的表结构
HBase以表的形式存储数据。表有行和列组成。列划分为若干个列族/列簇(column family)。
Row Key |
column-family1 |
column-family2 |
column-family3 |
|||
column1 |
column2 |
column1 |
column2 |
column3 |
column1 |
|
key1 |
t1:abc t2:gdxdf |
t4:dfads t3:hello t2:world |
||||
key2 |
t3:abc t1:gdxdf |
t4:dfads t3:hello |
t2:dfdsfa t3:dfdf |
|||
key3 |
t2:dfadfasd t1:dfdasddsf |
t2:dfxxdfasd t1:taobao.com |
如上图所看到的,key1,key2,key3是三条记录的唯 一的row key值,column-family1,column-family2,column-family3是三个列族,每一个列族下又包含几列。比方 column-family1这个列族下包含两列,名字是column1和column2,t1:abc,t2:gdxdf是由row key1和column-family1-column1唯一确定的一个单元cell。这个cell中有两个数据,abc和gdxdf。两个值的时间戳不 一样,各自是t1,t2, hbase会返回最新时间的值给请求者。
这些名词的详细含义例如以下:
(1) Row Key
与nosql数据库们一样,row key是用来检索记录的主键。訪问hbase table中的行,仅仅有三种方式:
(1.1) 通过单个row key訪问
(1.2) 通过row key的range
(1.3) 全表扫描
Row key行键 (Row key)能够是随意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在hbase内部,row key保存为字节数组。
存储时,数据依照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将常常一起读取的行存储放到一起。(位置相关性)
注意:
字典序对int排序的结果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保持整形的自然序,行键必须用0作左填充。
行的一次读写是原子操作 (不论一次读写多少列)。这个设计决策可以使用户非常easy的理解程序在对同一个行进行并发更新操作时的行为。
(2) 列族 column family
hbase表中的每一个列,都归属与某个列族。列族是表的chema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。比如courses:history , courses:math 都属于 courses 这个列族。
訪问控制、磁盘和内存的使用统计都是在列族层面进行的。实际应 用中,列族上的控制权限能帮助我们管理不同类型的应用:我们同意一些应用能够加入新的基本数 据、一些应用能够读取基本数据并创建继承的列族、一些应用则仅仅同意浏览数据(甚至可能由于隐私的原因不能浏览全部数据)。
(3) 单元 Cell
HBase中通过row 和columns确定的为一个存贮单元称为cell。由{row key, column( = +
(4) 时间戳 timestamp
每一个cell都保存着同一份数据的多个版本号。版本号通过时 间戳来索引。时间戳的类型是 64位整型。时间戳能够由hbase(在数据写入时自己主动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也能够由客户显式赋值。假设应用程序要避免数据版本号冲突,就必须自己生成具有唯一性的时间戳。每 一个cell中,不同版本号的数据依照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本号造成的的管理 (包含存贮和索引)负担,hbase提供了两种数据版本号回收方式。一是保存数据的最后n个版本号,二是保存近期一段时间内的版本号(比方近期七天)。用户能够针对每一个列族进行设置。
测试实例如下
1 首先,先创建一张表,然后添加两条记录
- hbase(main):079:0> create 'scores','course'
- 0 row(s) in 0.9590 seconds
- hbase(main):080:0> put 'scores','Tom','course:math',97
- 0 row(s) in 0.0100 seconds
- hbase(main):081:0> scan 'scores'
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097631387, value=97
- 1 row(s) in 0.0190 seconds
- hbase(main):082:0> put 'scores','Tom','course:math',100
- 0 row(s) in 0.0080 seconds
- hbase(main):026:0> scan 'scores'
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097651029, value=100
- 1 row(s) in 0.0110 seconds
- hbase(main):027:0> scan 'scores',{TIMERANGE=>[1394097631387,1394097651029]}
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097631387, value=97
- 1 row(s) in 0.0210 seconds
- hbase(main):028:0> scan 'scores',{TIMERANGE=>[1394097631387,1394097651030]}
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097651029, value=100
- 1 row(s) in 0.0100 seconds
从上面可以看到,HBASE默认scan出来的结果是最后一条时间戳的记录,那么如何把这两条都scan出来呢,
这时候可以加入VERSIONS这个约束条件:
- hbase(main):032:0> scan 'scores',{VERSIONS=>2}
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097651029, value=100
- Tom column=course:math, timestamp=1394097631387, value=97
- 1 row(s) in 0.0130 seconds
上面的命令,已经把这条记录都scan出来了。
再看下面的例子:
- scan scores,{TIMERANGE=>[1394097631386,1394097651029],VERSIONS=>2}
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097631387, value=97
- 1 row(s) in 0.0130 seconds
从上面的结果只scan出一条记录。可知,TIMERANGE表示的是”>=开始时间 and <结束时间“的。再看:
- hbase(main):003:0> scan scores,{TIMERANGE=>[1394097631386,1394097651030],VERSIONS=>2}
- ROW COLUMN+CELL
- Tom column=course:math, timestamp=1394097651029, value=100
- Tom column=course:math, timestamp=1394097631387, value=97
- 1 row(s) in 0.0100 seconds
OK,这样就明白了。
不过上面的加了VERSIONS=>2,就可以查到历史的数据了,但是必须再创建表的时候加上VERSIONS,否则无效,看下面的例子:
- hbase(main):082:0> create member,address,info
- 0 row(s) in 0.4140 seconds
- => Hbase::Table - member
- hbase(main):093:0> put member,wanglei,info:age,24
- 0 row(s) in 0.0730 seconds
- hbase(main):093:1>get member,wanglei,{COLUMN=>info:age}
- COLUMN CELL
- info:age timestamp=1394438746187, value=24
- hbase(main):093:7> put member,wanglei,info:age,100
- 0 row(s) in 0.0730 seconds
- hbase(main):093:18> get member,wanglei,{COLUMN=>info:age}
- COLUMN CELL
- info:age timestamp=1394439539837, value=100
- hbase(main):022:0> get member,wanglei,{COLUMN=>info:age,TIMERANGE=>[1394438746187,1394439539838],VERSIONS=>2}
- COLUMN CELL
- info:age imestamp=1394439539837, value=100
- 1 row(s) in 0.0050 seconds
可以看到,虽然加了VERSIONS,但get的结果是1条;这就是因为建表时默认的VERSION是1.
修改VERSIONS:
- hbase(main):029:0> alter member,{NAME=>info,VERSIONS=>2}
- Updating all regions with the new schema...
- 0/1 regions updated.
- 1/1 regions updated.
- Done.
- 0 row(s) in 2.1680 seconds
- hbase(main):046:0> put member,wanglei,info:age,101
- 0 row(s) in 0.0590 seconds
- hbase(main):047:0> get member,wanglei,{COLUMN=>info:age}
- COLUMN CELL
- info:age timestamp=1394441161595, value=101
- 1 row(s) in 0.0120 seconds
那么现在就可以把倆条记录get出来了,如下:
- hbase(main):049:0> get member,wanglei,{COLUMN=>info:age,TIMERANGE=>[1394439539837,1394441161596],VERSIONS=>2}
- COLUMN CELL
- info:age timestamp=1394441161595, value=101
- info:age timestamp=1394439539837, value=100
- 2 row(s) in 0.0080 seconds