(一) 数据结构
首先做一个简要的总结:HBase最基本的单位是列。一列或者多列形成行数据,并由唯一的rowkey确定;HBase的主要数据结构包括:表、行、列和单元格;其中列是可动态增加的;这是一个典型的hbase的应用,在搜索系统中保存网页页面的content、anchor等相关属性信息,下面根据这个表应用来详细介绍这个数据结构中的相关概念;
1. RowKey
RowKey是用来检索HBase数据记录的主要字段,类似于其他数据库中的PrimaryKey一样,是访问HBase数据库的关键;目前访问HBase数据库中的行记录只有三种方式:
a. 通过单个RowKey进行访问;
b. 通过RowKey的范围进行scan;
c. 全表扫描(不推荐);
行键总是唯一指定的,只出现一次的,一般来说HBase表只支持对rowkey的单一索引,只能过rowkey来定位相关的记录,但是有扩展版的HBase支持了辅助索引的功能;行键可以是任意的字节数组,不一定是人直接可读的;
2. 列族
一行是由若干列组成的,若干列又构成一个列族,一个列族的所有列都存储在同一个底层的存储文件里,这个存储文件叫做HFile。
列族需要在表创建的时候就定义好,目前HBase对于多列族的支持不是特别好,一般列族的数量只限于几十,实际情况可能还小的多。列族名必须由可打印字符组成。
hbase表中的每个列,都归属与某个列族。列族是表的schema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如courses:history,courses:math都属于courses 这个列族。
访问控制、磁盘和内存的使用统计都是在列族层面进行的。实际应用中,列族上的控制权限能帮助我们管理不同类型的应用:我们允许一些应用可以添加新的基本数据、一些应用可以读取基本数据并创建继承的列族、一些应用则只允许浏览数据(甚至可能因为隐私的原因不能浏览所有数据)。
3. 时间戳
HBase表中通过rowkey和列名确定的一个存储单元成为Cell单元格,每个Cell都可以保存同一字段数据的多个版本,版本通过时间戳来索引。时间戳可以在HBase写入时由客户端显式赋值,也可以由服务端默认赋值。每个Cell中,不同版本的数据按照时间倒序排序,保证最新的数据排在前面。
为了避免数据存在过多的版本造成的管理(包括存储和索引)负担,HBase提供了两种数据版本回收方式:一种是保存数据的最后N个版本,第二种是保存最近一段时间内的版本(比如最近七天)。回收方式可以针对每个列族进行设置。用户可以指定每个值所能保存的最大版本数。
4. Cell单元格
Cell单元格是由{rowkey,column(=family+label),timestamp}唯一确定的单元,单元格中的内容全部是字节码形式存储的。
(二) 基本命令
1.shell交互
HBase可以通过HBase shell对HBase集群进行命令行交互,HBase shell同时提供了客户端和管理功能的操作。
语法规则:
下面介绍基本的HBase shell基本操作:
1、进入 hbase shell 命令行
[root@hadoop05 ~]# hbase shell
hbase(main):001:0> help
hbase(main):004:0> help 'ddl'
hbase(main):004:0> help 'get'
着重讲 general,ddl,dml
3、general:普通命令组
status 查看集群状态
whoami 角色信息
table_help 关于表操作的另外一种方式的帮助文档
version 集群的版本信息
4、ddl:定义组
list 列出所有表
create 创建表
还可以这样创建,好处就是可以方便我们给表的每个列簇设置一些属性,如果按照上面的方式创建,那就表示所有的列簇的属性都是取默认值
hbase(main):012:0> create 'table_test1',{NAME => 'cf1', VERSIONS => 3}, {NAME => 'cf2',
VERSIONS => 2}
describe(desc)查看表的详细信息
alter修改表的定义
先看增加一列:
还可以这样使用:
hbase(main):016:0> alter 'table_test', {NAME => 'another_family', VERSIONS => 4}
依然是表名后面的参数都是列簇的定义
接下来看删除一列:
hbase(main):018:0> alter 'table_test', {NAME => 'another_family', METHOD => 'delete'}
hbase(main):019:0> alter 'table_test', 'delete' => 'add_family'
最后再一查,果然两列簇都被删除了
exists 查看表存在不存在
disable 使表失效
enable 启用表
is_disabled 判断表是否是失效状态
is_enabled 判断表是否是启用状态
drop删除表
hbase(main):028:0> dro 'tabletest'
5、dml:管理组
在对表做数据的操作的时候,先准备一张表,如下图
hbase(main):030:0> create 'table_test',{NAME => 'cf1', VERSIONS => 3}, {NAME => 'cf2', VERSIONS => 2}
hbase(main):001:0> put 'table_test','rk01','cf1:name','huangbo'
hbase(main):003:0> put 'table_test','rk01','cf1:age',20,1482077777777
时间戳是可以自己指定的,如若不指定,则会自动获取系统的当前时间的时间戳
现在我再重新插入一下 cf1:name,方便下面的查询:
hbase(main):005:0> put 'table_test','rk01','cf1:name','wangbaoqiang'
get 获取数据
hbase(main):006:0> get 'table_test','rk01'
hbase(main):007:0> get 'table_test','rk01','cf1:name'
hbase(main):008:0> get 'table_test','rk01',{COLUMNS => 'cf1:name', VERSIONS => 3}
①:从 table_test 表中查 rowkey 为 rk01 的所有列簇的所有数据
②:从 table_test 表中查 rowkey 为 rk01 的列为 cf1:name 的最新数据
③:从 table_test 表中查 rowkey 为 rk01 的列为 cf1:name 的所有版本数据,3 个版本
scan查看某表的所有数据
hbase(main):010:0> scan 'table_test'
hbase(main):011:0> scan 'table_test',{COLUMNS => 'cf1:name'}
hbase(main):012:0> scan 'table_test',{COLUMNS => 'cf1:name', TIMESTAMP => 1482018424571}
Scan 的用法很多,参数,过滤条件可以很多,各种组合,意查询扫描符合要求的全部数据
delete 删除数据
hbase(main):014:0> delete 'table_test','rk01','cf1:name'
hbase(main):016:0> truncate 'table_test'
2. Filter的使用
HBase中两种主要的读取方式是scan和get,他们都是通过rowkey进行数据访问,在此基础上可以添加更多的限制条件来减少查询中传输的数据量。get和scan函数都是支持过滤器的,过滤器基本的接口叫Filter,HBase已经有一些现成的Filter类来满足相关的过滤需求,用户还可以通过集成Filter类来定制自己的限制条件;
Filter的使用流程:用户定义一个所需要的过滤器实例,然后将定义好的过滤器实例传递给Get或者Scan实例:Get.setFilter(filter);实例化过滤器的时候用户可以提供一些参数来设定过滤器的过滤条件;
**注意:**过滤器只能减少在查询中服务端返回客户端的数据量,并不能减少查询中的索引次数,对于全表进行scan,然后依赖rowkey过滤器进行过滤相应的记录,这样并不能提高查询效率,正确的查询应当依赖rowkey来确定对应的记录!