大数据随笔——Hbase如是说

举报
顾槐九 发表于 2022/06/15 15:29:28 2022/06/15
【摘要】 Apache HBase™ 是 Hadoop 数据库,一种分布式、可扩展的大数据存储。

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(限制查询结果行数),STARTROWROWKEY 起始行,会先根据这个 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

官方文档:https://hbase.apache.org/devapidocs/index.html

# 查看内置过滤器
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);
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。