Hbase入门(三)——数据模型
hbase最核心但也是最难理解的就是数据模型,由于与传统的关系型数据库不同,虽然hbase也有表(table),也有行(row)和列(column),但是与关系型数据库不同的是hbase有一个列族(column family)的概念,它将一列或者多列组织在一起,hbase必须属于某一个列族。
行和列交叉点称为单元格(cell),单元格时版本化的。单元格的内容,也就是列的值是不可分割的字节数组。
hbase没有数据类型,任何列值都被转换成字节数组进行存储。
hbase表中的行是通过行键(rowkey)进行区分的。行键也是用来唯一确定一行的标识。
hbase中的行按rowkey排序,排序方式采用字典顺序。
这些都是hbase的逻辑结果,他的物理结构也和传统关系型数据库有很大不同。
逻辑模型
hbase的逻辑模型源自google的bigtable模型。可以理解为一个稀疏的,长期存储的,多维度的和排序的映射表。
以下示例是 bigtable 论文第 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等相关技术博文,欢迎关注实时流式计算
上一篇: Linux计划任务
下一篇: LayaAir从入门到放弃