Hbase 最核心但也是最难理解的就是数据模型, 由于与传统的关系型数据库不同, 虽然 Hbase 也有表 (Table), 也有行(Row) 和列 (Column), 但是与关系型数据库不同的是 Hbase 有一个列族(Column Family) 的概念, 它将一列或者多列组织在一起, HBase 必须属于某一个列族.
行和列交叉点称为单元格(Cell), 单元格时版本化的. 单元格的内容, 也就是列的值是不可分割的字节数组.
HBase 没有数据类型, 任何列值都被转换成字节数组进行存储.
HBase 表中的行是通过行键 (Rowkey) 进行区分的. 行键也是用来唯一确定一行的标识.
HBase 中的行按 Rowkey 排序, 排序方式采用字典顺序.
这些都是 HBase 的逻辑结果, 他的物理结构也和传统关系型数据库有很大不同.
逻辑模型
HBase 的逻辑模型源自 Google 的 BigTable 模型. 可以理解为一个稀疏的, 长期存储的, 多维度的和排序的映射表.
以下示例是 BigTable http://research.google.com/archive/bigtable.html 论文第 2 页上的一个略微修改的形式. 有一个名为 webtable 的表包含两行 (com.cnn.www 和 com.example.www) 和三个列族, 名为 contents,anchor 和 people.
在此示例中, 对于第一行(com.cnn.www),anchor 包含两列(anchor:CSSnsi.com,anchor:my.look.ca),contents 包含一列(contents:HTML). 此示例包含具有行键 com.cnn.www 的行的 5 个版本, 以及具有行键 com.example.www 的行的一个版本. contents:HTML 列限定符包含给定网站的整个 HTML. anchor 列族的限定符每个都包含指向该行所代表的站点的外部站点的链接, 以及它在其链接的 anchor 中使用的文本. people 列系列表示与该站点关联的人员.
此表中看起来为空的单元格在 HBase 中不占用空间, 或实际上不存在. 这就是 HBase"稀疏" 的原因. 表格视图不是查看 HBase 中数据的唯一方法, 甚至也不是最准确的方法. 以下表示与多维映射相同的信息. 这只是一个出于演示目的的模型, 可能并不完全准确.
- {
- "com.cnn.www": {
- contents: {
- t6: contents:HTML: "<html>..."
- t5: contents:HTML: "<html>..."
- t3: contents:HTML: "<html>..."
- }
- anchor: {
- t9: anchor:cnnsi.com = "CNN"
- t8: anchor:my.look.ca = "CNN.com"
- }
- people: {}
- }
- "com.example.www": {
- contents: {
- t5: contents:HTML: "<html>..."
- }
- anchor: {}
- people: {
- t5: people:author: "John Doe"
- }
- }
- }
物理模型
虽然 Hbase 表可以看作一组稀疏的行, 但在物理意义上它们是按照列族存储的. 所以列是可以随时添加的.
Hbase 是面向列的, 存放行的不同列的物理文件, 一个列族存放在多个 HFile 中, 最重要的是一个列族的数据会被同一个 Region 管理.
空单元格不占据物理存储空间. 因此, 在时间戳 t8 处对 contents:HTML 列的值的请求将不返回任何值. 类似地, 在时间戳 t9 处对 anchor:my.look.ca 值的请求将不返回任何值. 但是, 如果未提供时间戳, 则将返回特定列的最新值. 给定多个版本, 最新版本也是第一个版本, 因为时间戳按降序存储. 因此, 如果没有指定时间戳, 则对行 com.cnn.www 中所有列的值的请求将是: 来自时间戳 t6 的 contents:HTML 的值, 来自时间戳 t9 的 anchor:cnnsi.com 的值, 来自时间戳 t8 的 anchor:my.look.ca.
数据模型操作
四个主要的数据模型操作是 Get,Put,Scan 和 Delete. 通过实例化 Table 进行操作.
版本问题: Rowkey,Column(列族和列),Version 组合在一起称为 Hbase 中的一个单元格.
Rowkey 和 Column 的值是用字节数组表示的, Version 则是用一个长整型表示的.
Get
操作返回指定行的属性, Get 是在 Scan 基础上实现的. 在默认情况下, 如果没有指定版本, 一旦使用 Get 操作, 会返回最近版本的 Cell.
要返回多个版本, 需要设置 Get.setMaxVersions()
要返回最新版本以外的其他版本, 请参见 Get.setTimeRange()
默认版本 Get 示例
- public static final byte[] CF = "cf".getBytes();
- public static final byte[] ATTR = "attr".getBytes();
- ...
- Get get = new Get(Bytes.toBytes("row1"));
- Result r = table.get(get);
- byte[] b = r.getValue(CF, ATTR); // returns current version of value
给定版本的 Get 示例
- public static final byte[] CF = "cf".getBytes();
- public static final byte[] ATTR = "attr".getBytes();
- ...
- Get get = new Get(Bytes.toBytes("row1"));
- get.setMaxVersions(3); // will return last 3 versions of row
- Result r = table.get(get);
- byte[] b = r.getValue(CF, ATTR); // returns current version of value
- List<KeyValue> kv = r.getColumn(CF, ATTR); // returns all versions of this column
- PUT
执行 put 总是在某个时间戳创建 cell 的新版本. 默认情况下, 系统使用服务器的 currentTimeMillis, 但您可以在针对每一列指定版本(= 长整数). 这意味着您可以在过去或将来指定时间, 或者将 long 值用于非时间目的.
隐式版本示例
HBase 将使用当前时间隐式地对以下 Put 进行版本控制.
- public static final byte[] CF = "cf".getBytes();
- public static final byte[] ATTR = "attr".getBytes();
- ...
- Put put = new Put(Bytes.toBytes(row));
- put.add(CF, ATTR, Bytes.toBytes( data));
- table.put(put);
显式版本示例
- public static final byte[] CF = "cf".getBytes();
- public static final byte[] ATTR = "attr".getBytes();
- ...
- Put put = new Put( Bytes.toBytes(row));
- long explicitTimeInMs = 555; // just an example
- put.add(CF, ATTR, explicitTimeInMs, Bytes.toBytes(data));
- table.put(put);
- DELETE
删除通过 Table.delete]执行.
有三种不同类型的内部删除标记.
删除: 对于特定版本的列.
删除列: 适用于列的所有版本.
删除系列: 适用于特定 ColumnFamily 的所有列
SCAN
扫描表
下面是对表进行扫描的示例. 假设一个表填充了具有键 "row1","row2","row3" 的行, 然后另一组是具有键 "abc1","abc2" 和 "abc3" 的行. 以下示例将展示如何设置 Scan 实例以返回以 "row" 开头的行.
- public static final byte[] CF = "cf".getBytes();
- public static final byte[] ATTR = "attr".getBytes();
- ...
- Table table = ... // instantiate a Table instance
- Scan scan = new Scan();
- scan.addColumn(CF, ATTR);
- scan.setRowPrefixFilter(Bytes.toBytes("row"));
- ResultScanner rs = table.getScanner(scan);
- try {
- for (Result r = rs.next(); r != null; r = rs.next()) {
- // process result...
- }
- } finally {
- rs.close(); // always close the ResultScanner!
- }
更多实时计算, Hbase,Flink,Kafka 等相关技术博文, 欢迎关注实时流式计算
来源: https://www.cnblogs.com/tree1123/p/11611062.html