本文主要介绍HBase数据模型概括与数据坐标
有时间版本的数据
HBase 除了是无模式数据库以外,还是有时间版本概念(versioned)的数据库。例如,你可以按照时间回溯最初的密码:
List<KeyValue> password = r.getColumn(Bytes.toBytes(“info”), Bytes.toBytes(“password”));
b = password.get(0).getvalue();
String currentPasswd = Bytes.toString(b);
b = password.get(1).getvalue();
String prevPasswd = Bytes.toString(b);
每次你在单元上执行操作,HBase 都隐式地存储一个新时间版本。单元的新建、修改和删除都会同样处理,它们都会留下新时间版本。Get 请求根据提供的参数调出相应的版本。时间版本是访问特定单元时的最后一个坐标。当没有设定时间版本时,HBase以毫秒为单位使用当前时间,所以版本数字用长整型long 表示。HBase 默认只存储3个版本,这可以基于列族来设置。单元里数据的每个版本提交一个KeyValue 实例给Result。你可以使用方法getTimestamp()来获取KeyValue 实例的版本信息:
long version = password.get(0).getTimestamp();
如果一个单元的版本超过了最大数量,多出的记录在下一次大合并时会扔掉。
除了删除整个单元,你也可以删除一个或几个特定的版本。之前提到的方法deleteColumns()(带s)处理小于指定时间版本的所有KeyValue。不指定时间版本时,默认使用当前时间now。方法deleteColumn()只删除一个指定版本。小心你调用的方法,它们的调用方式相似,含义略有不同。
数据模型概括
表(table)—HBase 用表来组织数据。表名是字符串(String),由可以在文件系统路径里使用的字符组成。
行(row)—在表里,数据按行存储。行由行键(rowkey)唯一标识。行键没有数据类型,总是视为字节数组byte[]。
列族(column family)—行里的数据按照列族分组,列族也影响到HBase 数据的物理存放。因此,它们必须事前定义并且不轻易修改。表中每行拥有相同列族,尽管行不需要在每个列族里存储数据。列族名字是字符串(String),由可以在文件系统路径里使用的字符组成。
列限定符(column qualifier)—列族里的数据通过列限定符或列来定位。列限定符不必事前定义。列限定符不必在不同行之间保持一致。就像行键一样,列限定符没有数据类型,总是视为字节数组byte[]。
单元(cell)—行键、列族和列限定符一起确定一个单元。存储在单元里的数据称为单元值(value)。值也没有数据类型,总是视为字节数组byte[]。
时间版本(version)—单元值有时间版本。时间版本用时间戳标识,是一个long。没有指定时间版本时,当前时间戳作为操作的基础。HBase 保留单元值时间版本的数量基于列族进行配置。默认数量是3 个。
上述6 个概念构成HBase 的基础。用户最终看到的是通过API 展现的上述6 个基本概念的逻辑视图,它们是对HBase 物理存放在硬盘上数据进行管理的基石。
HBase 的每个数据值使用坐标来访问。一个值的完整坐标包括行键、列族、列限定符和时间版本。
数据坐标
在逻辑数据模型里,时间版本的数字也是数据的坐标之一。你可以想象,在关系型数据库里存储数据使用的是二维坐标系统,先是行后是列。照此类推,HBase 在表里存储数据使用的是四维坐标系统。
HBase 使用的坐标依次是行键、列族、列限定符和时间版本。users 表的坐标如图所示
把所有坐标视为一个整体,HBase 可以看做是一个键值(keyvalue)数据库。抽象看逻辑数据模型,你可以把这组坐标看做键,把单元数据看做值
当使用HBase API 检索数据时,你不需要提供全部坐标。如果你在Get 命令中省略了时间版本,HBase 返回数据值多个时间版本的映射集合。HBase 允许你在一次操作中得到多个数据,它们按照坐标的降序排列。那么你可以把HBase 看做是这样一种键值数据库,它的数据值是映射集合或者映射集合的集合。该思想如图所示:
实战一下:
让我们在一个实际例子中练习已经学到的东西。首先为User 实例定义一个简单模型对象:
public abstract class User { public String user; public String name; public String email; public String password; public long tweetCount; @Override public String toString() { return String.format( "<User: %s, %s, %s, %s>", user, name, email, tweetCount); } }
然后在一个类中封装所有HBase 访问操作。先声明普遍使用的字节数组byte[]常量,然后定义封装操作命令的方法,接下来是User 模型的公有接口和私有实现
具体代码参见:
https://github.com/hbaseinaction/twitbase/blob/master/src/main/java/HBaseIA/TwitBase/hbase/UsersDAO.java
最后一部分是main()方法。让我们新建UsersTool 来简化HBase 里users 表的访问,访问users 表的命令行接口,UsersTool
具体代码参见:https://github.com/hbaseinaction/twitbase/blob/master/src/main/java/HBaseIA/TwitBase/UsersTool.java
wu@ubuntu:~/opt$ git clone git://github.com/hbaseinaction/twitbase.git
wu@ubuntu:~/opt/twitbase$ mvn package
这会在target目录下生成文件 twitbase-1.0.0.jar
用UsersTool 往users 表中增加用户Mark 的信息很容易:
wu@ubuntu:~/opt/twitbase$ java -cp target/twitbase-1.0.0.jar \
HBaseIA.TwitBase.UsersTool \
add \
TheRealMT \
“Mark Twain” samul@clemens.org \
abc123
Successfully added user <User: TheRealMT, Mark Twain, samul@clemens.org, 0>
也可以列出表的内容:
wu@ubuntu:~/opt/twitbase$ java -cp target/twitbase-1.0.0.jar HBaseIA.TwitBase.UsersTool list
<User: TheRealMT, Mark Twain, samul@clemens.org, 0>
Comments