Hbase学习
HBase 是一种非关系型数据库,它不要求数据之间有严格的关系,同时它允许在同一列不同行中存储不同类型的数据。
HBase 采用列式存储或者说是面向列的数据库,在表中它由行排序。HBase 是根据列族来存储数据的。列族下面可以有非常多的列,列族在创建表的时候就必须指定。一个表有多个列族,每一个列族可以有任意数量的列。后续列的值连续存储在磁盘上。表中的每个单元格值都具有时间戳。
总之,在一个 HBase 中:
- 表是行的集合;
- 行是列族的集合;
- 列族是列的集合;
- 列是键值对的集合。
传统数据库像是一个有着严格格式的 Excel 表格,而HBase 更像是一个巨大、稀疏、多维的“键值对(Key-Value)”字典。
概念理解
HBase 的表(Table)由许多行组成,每一行都有一个全局唯一的行键(RowKey)。HBase 最大的特点之一是数据按 RowKey 的字典顺序自动排序。
比如我们有三个用户,就是三行,行键分别是user_001,user_002,user_003。这三行数据构成了这张表,然后按照字典顺序排序user_001,user_002,user_003在底层存储时,user_001紧挨着user_002。
表
| 行键 (RowKey) | 列族:BaseInfo (基础信息) |
|---|---|
user_001 | |
user_002 | |
user_003 |
具体到某一行(比如user_001),它里面包含的并不是直接的列,而是列族。比如user_001这一行里,包含了BaseInfo和ActionLog这两个列族,分别代表基本信息和日志
然后一个列族包含多个列,同一列族数据在硬盘中连续存储,每一列是一个键值对,并通过时间戳保留多个版本,比如表中的T1,T2
| 行键 (RowKey) | 列族:BaseInfo (基础信息) | 列族:ActionLog (行为日志) |
|---|---|---|
user_001 | name= “张三” (T1)age= “27” (T3)age= “26” (T2) | login_time= “2026-03-26” (T1)click_item= “手机” (T2) |
综合来看就是这样:
| 行键 (RowKey) | 列族:BaseInfo (基础信息) | 列族:ActionLog (行为日志) |
|---|---|---|
user_001 | name= “张三” (T1)age= “27” (T2)age= “26” (T1) | login_time= “2026-03-26” (T1)click_item= “手机” (T2) |
user_002 | name= “李四” (T1)email= “lisi@test.com” (T1) | (空,不占用额外存储空间) |
user_003 | nickname= “王五” (T1) | search_word= “HBase教程” (T1) |
你也许注意到了,对于这三个用户,其列族的列可以是完全不同的,这和我们常见的关系型数据库是最大的不同点,比如mysql,一个用户是一行,那么不同用户属性值的集合应当完全一样,一张表的每个列所有用户都有,但是对于列族数据库来说,一张表的不同用户完全可以有不同的属性值。
我们再来拿常见的商品表并结合操作代码来讲解一下Hbase,不同的商品会有不同的属性,比如食品有保质期,手机有颜色型号等,非常适合用列族数据库存储。
商品库
使用**商品库(Product)**的例子,建表时有两个列族:BaseInfo(基础信息)和Attr(动态属性),商品的行键(RowKey)是SKU_1001。
在操作数据前,我们需要先建表和列族。在 HBase 控制台里,建表只需要指定表名和列族名即可,不需要定义具体的列。
hbase(main):001:0> create 'Product', 'BaseInfo', 'Attr' 0 row(s) in 1.2340 seconds即创建一个Product表,有BaseInfo和Attr两个列族
增:上架新商品 (Put)
场景:录入SKU_1001的名称、品牌和首发价格。
操作时刻:T1
在 Shell 中,put命令的语法是:put '表名', 'RowKey', '列族:列名', '值'
Shell 命令:
hbase(main):002:0> put 'Product', 'SKU_1001', 'BaseInfo:name', 'iPhone 15 Pro' hbase(main):003:0> put 'Product', 'SKU_1001', 'BaseInfo:brand', 'Apple' hbase(main):004:0> put 'Product', 'SKU_1001', 'Attr:price', '7999'执行后,HBase 底层的逻辑视图:
| 行键 (RowKey) | 列族:BaseInfo (基础信息) | 列族:Attr (动态属性) |
|---|---|---|
SKU_1001 | name= “iPhone 15 Pro” (T1)brand= “Apple” (T1) | price= “7999” (T1) |
改:降价与动态增加属性 (Put)
场景:双十一降价,并且新增“颜色”和“赠品”属性。
操作时刻:T2
HBase 没有update命令,修改和新增字段都是继续使用put进行追加。
Shell 命令:
# 覆盖旧价格(追加新版本) hbase(main):005:0> put 'Product', 'SKU_1001', 'Attr:price', '7499' # 动态新增原本不存在的列 hbase(main):006:0> put 'Product', 'SKU_1001', 'Attr:color', 'Titanium Blue' hbase(main):007:0> put 'Product', 'SKU_1001', 'Attr:gift', 'AirPods'执行后,HBase 底层的逻辑视图变为了:
| 行键 (RowKey) | 列族:BaseInfo (基础信息) | 列族:Attr (动态属性) |
|---|---|---|
SKU_1001 | name= “iPhone 15 Pro” (T1)brand= “Apple” (T1) | price= “7499” (T2)color= “Titanium Blue” (T2)gift= “AirPods” (T2)price= “7999” (T1) |
查:读取商品信息 (Get)
场景:查看SKU_1001这个商品的最新全部信息。
操作时刻:随时
使用get命令可以获取指定 RowKey 的数据。默认情况下,Shell 会打印出该行所有列的最新版本数据。
Shell 命令:
hbase(main):008:0> get 'Product', 'SKU_1001' COLUMN CELL Attr:color timestamp=1711540000000, value=Titanium Blue Attr:gift timestamp=1711540000000, value=AirPods Attr:price timestamp=1711540000000, value=7499 BaseInfo:brand timestamp=1711530000000, value=Apple BaseInfo:name timestamp=1711530000000, value=iPhone 15 Pro(注意看控制台的输出,HBase 自动按列名的字典顺序排好了,并且展示了每条数据的实际数字时间戳。这里返回的价格是 7499,旧的 7999 被隐藏了。)
删:活动结束,移除赠品属性 (Delete)
场景:撤掉“赠品”这个属性。
操作时刻:T3
语法是:delete '表名', 'RowKey', '列族:列名'。(如果想删除整行数据,可以使用deleteall '表名', 'RowKey')。
Shell 命令:
hbase(main):009:0> delete 'Product', 'SKU_1001', 'Attr:gift'执行 Delete 操作后,HBase 底层的逻辑视图:
| 行键 (RowKey) | 列族:BaseInfo (基础信息) | 列族:Attr (动态属性) |
|---|---|---|
SKU_1001 | name= “iPhone 15 Pro” (T1)brand= “Apple” (T1) | gift= [Tombstone 墓碑标记] (T3)price= “7499” (T2)color= “Titanium Blue” (T2)gift= “AirPods” (T2)price= “7999” (T1) |
此时如果你再次执行get 'Product', 'SKU_1001',你会发现输出的结果中,Attr:gift这一行彻底消失了。
