大数据随笔——Hbase如是说
Hbase
Apache HBase™ 是 Hadoop 数据库,一种分布式、可扩展的大数据存储。
HBase的名字的来源于Hadoop database,即hadoop数据库,不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库,而且它是基于列的而不是基于行的模式。
HBase是一个分布式的、面向列的开源数据库,源于google的一篇论文《bigtable:一个结构化数据的分布式存储系统》。HBase是Google Bigtable的开源实现,它利用Hadoop HDFS作为其文件存储系统,利用Hadoop MapReduce来处理HBase中的海量数据,利用Zookeeper作为协同服务。
hbase提供了一个shell的终端给用户交互。使用命令hbase shell进入命令界面。通过执行 help可以看到命令的帮助信息。
概念
表结构
HBase以表的形式存储数据。表有行和列组成。列划分为若干个列族/列簇(column family),每个列族/列簇下面可以有多个普通列。
表 Table
HBase是用表来存储数据的。
命名空间 namespace
namespace命名空间指对一组表的逻辑分组,类似RDBMS中的database,方便对表在业务上划分。
HBase系统默认定义了两个缺省的namespace:
- hbase:系统内建表,包含namespace和meta表
- default:用户建表时未指定namespace的表都创建在此
行键 Row Key
行键,每一行的主键列,每行的行键要唯一,行键的值为任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在HBase内部,rowKey保存为字节数组byte[]。
行的一次读写是原子操作 (不论一次读写多少列)
区域 Region
Table在行的方向上分割为多个Region。
Region是按大小分割的,每个表开始只有一个region,随着数据的增多,region不断增大,当增大到一个阀值的时候,region就会等分为两个新的region,之后会有越来越多的region。
Region是HBase中分布式存储和负载均衡的最小单元。不同的Region分布到不同的RegionServer上。
Region由一个或者多个Store组成, 每个Store保存一个column family, 每个Store又由一个MemStore(存储在内存中)和0到多个StoreFile(存储在HDFS上)组成
列族 Column Family
列族是每个子列的父级,每个子列都属于一个列族,一个列族包含一个或者多个相关列,创建表的时候需要指定列族,而列不需要必须指定。通过“列族名:列名”来表示某个具体的子列。
HBase中的Schema就是 TableName + Column Family Name
列限定符
就是列族下的每个子列名称,或者称为相关列,或者称为限定符,只是翻译不同。
通过 columnFamily:column 来定位某个子列。
存储单元 Cell
我们外观看到的每个单元格其实都对应着多个存储单元,默认情况下一个单元格对应着一个存储单元,一个存储单元可以存储一份数据,如果一个单元格有多个存储单元就表示一个单元格可以存储多个值。可以通过version来设置存储单元个数。可以通过
rowKey + columnFamily + column + timestamp来唯一确定一个存储单元。cell中的数据是没有类型的,全部是字节码形式存贮。
hbase按照时间戳降序排列各时间版本,其他映射建按照升序排序。
时间戳版本号 Timestamp
每个cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。
为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。
Shell 命令
基本命令
# 打开 shell
$ hbase shell
# 获取帮助
help
# 获取命令的详细帮助
help "create"
# 查看服务器状态
status
# 查看版本信息
version
表操作
# 查看表
list
# 建表
create '表名称', '列族名称 1','列族名称 2','列名称 N'
# 创建一张名为Student的表,包含基本信息(baseInfo)、学校信息(schoolInfo)两个列族
create 'Student','baseInfo','schoolInfo'
# 查看表信息
desc '表名'
# 检查表是否存在
exists '表名'
# 删除表 先禁用再删除
disable '表名'
drop '表名'
增删改
# 添加列族
alter '表名','列族名'
# 删除列族
alter '表名', {NAME => '列族名', METHOD => 'delete'}
# 更改列族存储版本的限制
# 默认情况下,列族只存储一个版本的数据,如果需要存储多个版本的数据,则需要修改列族的属性。修改后可通过 desc 命令查看。
alter 'Student',{NAME=>'baseInfo',VERSIONS=>3}
# 插入数据
# 注意:如果新增数据的行键值、列族名、列名与原有数据完全相同,则相当于更新操作
put '表名', '行键','列族:列','值'
# 删除指定行
delete 'Student','rowkey3'
# 删除指定行中指定列的数据
delete 'Student','rowkey3','baseInfo:name'
查
hbase 中访问数据有两种基本的方式:
-
按指定 rowkey 获取数据:get 方法;
-
按指定条件获取数据:scan 方法。
scan
可以设置 begin 和 end 参数来访问一个范围内所有的数据。get 本质上就是 begin 和 end 相等的一种特殊的 scan。
基本查询
# 获取指定行中所有列的数据信息
get 'Student','rowkey3'
# 获取指定行中指定列族下所有列的数据信息
get 'Student','rowkey3','baseInfo'
# 获取指定行中指定列的数据信息
get 'Student','rowkey3','baseInfo:name'
# 查询整表数据
scan 'Student'
# 正常显示中文
scan "Student", {FORMATTER => 'toString'}
条件查询
# 只查询列族”baseInfo”
scan 'Student',{COLUMNS=>'baseInfo'}
# 只查询列族”baseInfo”下的”birthday”信息
scan 'Student', {COLUMNS=> 'baseInfo:birthday'}
# 限定只显示多少条: scan "表名", {LIMIT => XXX}
# 查询订单数据(只显示3条)
scan "Student", {FORMATTER => 'toString', LIMIT => 3}
# 指定查询某几个列: scan "表名", {LIMIT => XXX, COLUMNS => []}
# 只查询订单状态以及支付方式,并且只展示3条数据
scan "Student", {FORMATTER => 'toString', LIMIT => 3, COLUMNS => ['C1:name', 'C1:age']}
# 根据ROWKEY来查询:scan "表名", {LIMIT => XXX, COLUMNS => [], ROWPREFIXFILTER => 'ROWKEY'}
# 使用scan来根据rowkey查询数据,也是查询指定列的数据
scan "Student", {ROWPREFIXFILTER => '张三',FORMATTER => 'toString', LIMIT => 3, COLUMNS => ['C1:age', 'C1:schoolname']}
HBase 支持 Limit
(限制查询结果行数),STARTROW
(ROWKEY
起始行,会先根据这个 key
定位到 region
,再向后扫描)、STOPROW
(结束行)、TIMERANGE
(限定时间戳范围)、VERSIONS
(版本数)、和 FILTER
(按条件过滤行)等。
如下代表从 rowkey2
这个 rowkey
开始,查找下两个行的最新 3 个版本的 name 列的数据:
scan 'Student', {COLUMNS=> 'baseInfo:name',STARTROW => 'rowkey2',STOPROW => 'wrowkey4',LIMIT=>2, VERSIONS=>3}
条件过滤
Filter 可以设定一系列条件来进行过滤。如我们要查询值等于 24 的所有数据:
scan 'Student', FILTER=>"ValueFilter(=,'binary:24')"
值包含 yale 的所有数据:
scan 'Student', FILTER=>"ValueFilter(=,'substring:yale')"
列名中的前缀为 birth 的:
scan 'Student', FILTER=>"ColumnPrefixFilter('birth')"
FILTER 中支持多个过滤条件通过括号、AND 和 OR 进行组合:
# 列名中的前缀为birth且列值中包含1998的数据
scan 'Student', FILTER=>"ColumnPrefixFilter('birth') AND ValueFilter ValueFilter(=,'substring:1998')"
PrefixFilter
用于对 Rowkey 的前缀进行判断:
scan 'Student', FILTER=>"PrefixFilter('wr')"
过滤器
其实在hbase shell中,执行的ruby脚本,背后还是调用hbase提供的Java API
# 查看内置过滤器
show_filters
# 示例
scan '表名',{Filter => "过滤器(比较运算符, '比较器表达式')"}
# 使用 RowFilter 查询指定订单ID的数据
# 查询订单的ID为:02602f66-adc7-40d4-8485-76b5632b5b53、订单状态以及支付方式
scan "ORDER_INFO", {FILTER => "RowFilter(=,'binary:02602f66-adc7-40d4-8485-76b5632b5b53')", COLUMNS => ['C1:STATUS', 'C1:PAYWAY'], FORMATTER => 'toString'}
# 查询状态为「已付款」的订单
scan "ORDER_INFO",{FILTER => "SingleColumnValueFilter('C1', 'STATUS', = , 'binary:已付款')",COLUMNS => ['C1:STATUS','C1:PAYWAY'],FORMATTER => 'toString'}
# 查询支付方式为1,且金额大于3000的订单
scan "ORDER_INFO",{FILTER => "SingleColumnValueFilter('C1', 'PAYWAY', = , 'binary:1') AND SingleColumnValueFilter('C1', 'PAY_MONEY', > , 'binary:3000')",COLUMNS => ['C1:STATUS','C1:PAYWAY','C1:PAY_MONEY'],FORMATTER => 'toString'}
HBase shell中比较默认都是字符串比较,所以如果是比较数值类型的,会出现不准确的情况
例如:在字符串比较中4000是比100000大的
rowkey 过滤器
RowFilter | 实现行键字符串的比较和过滤 |
---|---|
PrefixFilter | rowkey前缀过滤器 |
KeyOnlyFilter | 只对单元格的键进行过滤和显示,不显示值 |
FirstKeyOnlyFilter | 只扫描显示相同键的第一个单元格,其键值对会显示出来 |
InclusiveStopFilter | 替代 ENDROW 返回终止条件行 |
列过滤器
FamilyFilter | 列簇过滤器 |
---|---|
QualifierFilter | 列标识过滤器,只显示对应列名的数据 |
ColumnPrefixFilter | 对列名称的前缀进行过滤 |
MultipleColumnPrefixFilter | 可以指定多个前缀对列名称过滤 |
ColumnRangeFilter | 过滤列名称的范围 |
值过滤器
ValueFilter | 值过滤器,找到符合值条件的键值对 |
---|---|
SingleColumnValueFilter | 在指定的列蔟和列中进行比较的值过滤器 |
SingleColumnValueExcludeFilter | 排除匹配成功的值 |
其他过滤器
ColumnPaginationFilter | 对一行的所有列分页,只返回 [offset,offset+limit] 范围内的列 |
---|---|
PageFilter | 对显示结果按行进行分页显示 |
TimestampsFilter | 时间戳过滤,支持等值,可以设置多个时间戳 |
ColumnCountGetFilter | 限制每个逻辑行返回键值对的个数,在 get 方法中使用 |
DependentColumnFilter | 允许用户指定一个参考列或引用列来过滤其他列的过滤器 |
比较器
比较器 | 描述 |
---|---|
BinaryComparator | 匹配完整字节数组 |
BinaryPrefixComparator | 匹配字节数组前缀 |
BitComparator | 匹配比特位 |
NullComparator | 匹配空值 |
RegexStringComparator | 匹配正则表达式 |
SubstringComparator | 匹配子字符串 |
比较器表达式
比较器 | 表达式语言缩写 |
---|---|
BinaryComparator | binary:值 |
BinaryPrefixComparator | binaryprefix:值 |
BitComparator | bit:值 |
NullComparator | null |
RegexStringComparator | regexstring:正则表达式 |
SubstringComparator | substring:值 |
常用过滤器
- 行键过滤器
筛选出匹配的所有的行,使用BinaryComparator可以筛选出具有某个行键的行,或者通过改变比较运算符来筛选出符合某一条件的多条数据。例如下面的例子,从表t1中筛选出行键为row1的一行数据:
Table table =conn.getTable(TableName.valueOf("t1"));
Scan scan = new Scan();
Filter filter = new RowFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("row1")));
scan.setFilter(filter);
ResultScanner rs = table.getScanner(scan);
for (Result res : rs) {
System.out.println(res);
}
- 列族过滤器
筛选出符合条件的所有列族数据。例如下面的例子,筛选出列族为f1的所有数据。
Table table =conn.getTable(TableName.valueOf("t1"));
Scan scan = new Scan();
Filter filter = new FamilyFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("f1")));
scan.setFilter(filter);
ResultScanner rs = table.getScanner(scan);
for (Result res : rs) {
System.out.println(res);
}
- 列过滤器
根据列名进行筛选数据。例如下面的例子,筛选出列名为name的所有数据。
Scan scan = new Scan();
Filter filter = new QualifierFilter(CompareOp.EQUAL, new BinaryComparator(Bytes.toBytes("name")));
scan.setFilter(filter);
- 值过滤器
按照具体的值来筛选单元格的过滤器,这会把一行中值不能满足条件的单元格过滤掉。例如下面的例子:
筛选出一行中的值包含"xiaoming"的所有单元格数据。
Scan scan = new Scan();
Filter filter = new ValueFilter(CompareOp.EQUAL, new SubstringComparator("xiaoming"));
scan.setFilter(filter);
- 单列值过滤器
用一列的值是否满足条件来决定该行是否被过滤。在它的具体对象上,可以调用setFilterIfMissing(true)或者setFilterIfMissing(false),默认值是false。其作用是,对于要使用作为条件的列,如果这一列本身就不存在,默认这样的行会包含在结果集中。如果设置为true,这样的行会被过滤掉。
例如下面的例子:筛选出name列不包含zhangsan的所有行数据。
Filter filter = new SingleColumnValueFilter(Bytes.toBytes("f1"), Bytes.toBytes("name"),CompareFilter.CompareOp.NOT_EQUAL, new SubstringComparator("xiaoming"));
////如果某行列name不存在,那么该行将被过滤掉,false则不进行过滤,默认为false。
((SingleColumnValueFilter) filter).setFilterIfMissing(true);
- 点赞
- 收藏
- 关注作者
评论(0)