HBase插入数据 #
一、PUT语法 #
1.1 基本语法 #
ruby
# 基本语法
put '表名', '行键', '列族:列限定符', '值'
# 示例
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user001', 'info:age', '25'
put 'user', 'user001', 'info:email', 'zhangsan@example.com'
1.2 完整语法 #
ruby
# 完整语法
put '表名', '行键', '列族:列限定符', '值', 时间戳
# 示例
put 'user', 'user001', 'info:name', '张三', 1704067200000
1.3 参数说明 #
| 参数 | 说明 | 示例 |
|---|---|---|
| 表名 | 目标表名称 | ‘user’ |
| 行键 | RowKey | ‘user001’ |
| 列族:列限定符 | 列标识 | ‘info:name’ |
| 值 | 数据值 | ‘张三’ |
| 时间戳 | 版本时间戳(可选) | 1704067200000 |
二、基本插入操作 #
2.1 插入单列数据 #
ruby
# 插入单列数据
put 'user', 'user001', 'info:name', '张三'
# 插入多列数据(需要多次put)
put 'user', 'user001', 'info:age', '25'
put 'user', 'user001', 'info:email', 'zhangsan@example.com'
put 'user', 'user001', 'info:phone', '13812345678'
2.2 插入多列族数据 #
ruby
# 插入info列族数据
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user001', 'info:age', '25'
# 插入settings列族数据
put 'user', 'user001', 'settings:theme', 'dark'
put 'user', 'user001', 'settings:language', 'zh-CN'
# 插入history列族数据
put 'user', 'user001', 'history:login', '2024-01-01 10:00:00'
2.3 插入命名空间中的表 #
ruby
# 在命名空间中插入数据
put 'myapp:user', 'user001', 'info:name', '张三'
三、版本控制 #
3.1 自动时间戳 #
ruby
# 不指定时间戳,系统自动生成
put 'user', 'user001', 'info:name', '张三'
# 系统自动使用当前时间戳
3.2 手动指定时间戳 #
ruby
# 指定时间戳插入
put 'user', 'user001', 'info:name', '张三', 1704067200000
put 'user', 'user001', 'info:name', '张三丰', 1704067260000
# 查询所有版本
get 'user', 'user001', {COLUMN => 'info:name', VERSIONS => 3}
3.3 版本覆盖 #
ruby
# 相同时间戳会覆盖
put 'user', 'user001', 'info:name', '张三', 1704067200000
put 'user', 'user001', 'info:name', '李四', 1704067200000
# 结果:只有李四的值(张三被覆盖)
3.4 版本数限制 #
ruby
# 创建表时指定版本数
create 'user', {NAME => 'info', VERSIONS => 3}
# 插入多个版本
put 'user', 'user001', 'info:name', '版本1'
put 'user', 'user001', 'info:name', '版本2'
put 'user', 'user001', 'info:name', '版本3'
put 'user', 'user001', 'info:name', '版本4'
# 只保留最新3个版本
get 'user', 'user001', {COLUMN => 'info:name', VERSIONS => 10}
四、批量插入 #
4.1 使用Shell脚本 #
ruby
# 创建批量插入脚本 batch_put.rb
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.hbase.client.Put
import org.apache.hadoop.hbase.TableName
table = connection.getTable(TableName.valueOf('user'))
puts_list = []
(1..1000).each do |i|
rowkey = "user%04d" % i
put = Put.new(Bytes.toBytes(rowkey))
put.addColumn(Bytes.toBytes('info'), Bytes.toBytes('name'), Bytes.toBytes("用户#{i}"))
put.addColumn(Bytes.toBytes('info'), Bytes.toBytes('age'), Bytes.toBytes((18 + i % 50).to_s))
puts_list << put
end
table.put(puts_list)
puts "Inserted #{puts_list.size} rows"
4.2 执行脚本 #
bash
# 在Shell中执行
hbase shell batch_put.rb
# 或在Shell内执行
exec 'batch_put.rb'
4.3 使用Java API批量插入 #
java
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.util.ArrayList;
import java.util.List;
public class BatchPut {
public static void main(String[] args) throws Exception {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("user"));
List<Put> puts = new ArrayList<>();
for (int i = 1; i <= 1000; i++) {
Put put = new Put(Bytes.toBytes("user" + String.format("%04d", i)));
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"),
Bytes.toBytes("用户" + i));
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("age"),
Bytes.toBytes(String.valueOf(18 + i % 50)));
puts.add(put);
}
table.put(puts);
System.out.println("Inserted " + puts.size() + " rows");
table.close();
connection.close();
}
}
五、原子操作 #
5.1 检查并插入(CAS) #
ruby
# 检查并插入
# 语法:checkAndPut '表名', '行键', '列族:列', '期望值', Put对象
# 示例:只有当age为25时才更新name
put 'user', 'user001', 'info:age', '25'
checkAndPut 'user', 'user001', 'info:age', '25', 'info:name', '张三丰'
5.2 追加操作 #
ruby
# 追加数据到现有值
append 'user', 'user001', 'info:tags', ',vip'
# 示例
put 'user', 'user001', 'info:tags', 'normal'
append 'user', 'user001', 'info:tags', ',vip'
# 结果:normal,vip
5.3 增量操作 #
ruby
# 计数器增量
incr 'user', 'user001', 'info:login_count'
# 指定增量值
incr 'user', 'user001', 'info:login_count', 5
# 获取计数器值
get_counter 'user', 'user001', 'info:login_count'
六、数据类型处理 #
6.1 字符串 #
ruby
# 字符串直接插入
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user001', 'info:email', 'zhangsan@example.com'
6.2 数值 #
ruby
# 数值以字符串形式存储
put 'user', 'user001', 'info:age', '25'
put 'user', 'user001', 'info:score', '95.5'
# 使用计数器存储数值
incr 'user', 'user001', 'info:login_count'
6.3 布尔值 #
ruby
# 布尔值以字符串存储
put 'user', 'user001', 'info:active', 'true'
put 'user', 'user001', 'info:verified', 'false'
6.4 日期时间 #
ruby
# 日期时间以字符串存储
put 'user', 'user001', 'info:created_at', '2024-01-01 10:00:00'
put 'user', 'user001', 'info:updated_at', '2024-01-02 15:30:00'
# 或使用时间戳
put 'user', 'user001', 'info:created_ts', '1704067200000'
6.5 JSON数据 #
ruby
# JSON数据以字符串存储
put 'user', 'user001', 'info:address', '{"city":"北京","district":"朝阳"}'
put 'user', 'user001', 'info:preferences', '{"theme":"dark","language":"zh-CN"}'
七、插入示例 #
7.1 用户信息插入 #
ruby
# 创建表
create 'user', {NAME => 'info', VERSIONS => 1}
# 插入用户信息
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user001', 'info:age', '25'
put 'user', 'user001', 'info:email', 'zhangsan@example.com'
put 'user', 'user001', 'info:phone', '13812345678'
put 'user', 'user001', 'info:created_at', '2024-01-01 10:00:00'
# 验证插入
get 'user', 'user001'
7.2 订单信息插入 #
ruby
# 创建表
create 'order', {NAME => 'detail', VERSIONS => 1}
# 插入订单信息
put 'order', 'order001', 'detail:user_id', 'user001'
put 'order', 'order001', 'detail:amount', '100.00'
put 'order', 'order001', 'detail:status', 'paid'
put 'order', 'order001', 'detail:created_at', '2024-01-01 10:00:00'
# 验证插入
get 'order', 'order001'
7.3 时序数据插入 #
ruby
# 创建表
create 'sensor', {NAME => 'data', VERSIONS => 1, COMPRESSION => 'SNAPPY'}
# 插入传感器数据
put 'sensor', 'device001_1704067200', 'data:temp', '25.5'
put 'sensor', 'device001_1704067200', 'data:humidity', '60'
put 'sensor', 'device001_1704067200', 'data:pressure', '1013'
# 验证插入
get 'sensor', 'device001_1704067200'
八、性能优化 #
8.1 批量插入 #
text
批量插入优化
├── 使用批量Put减少网络开销
├── 合理设置批量大小(100-1000)
├── 关闭WAL(牺牲安全性)
└── 预分区避免热点
8.2 写入优化配置 #
xml
<!-- hbase-site.xml -->
<!-- 增大MemStore -->
<property>
<name>hbase.hregion.memstore.flush.size</name>
<value>268435456</value> <!-- 256MB -->
</property>
<!-- 增加Handler数量 -->
<property>
<name>hbase.regionserver.handler.count</name>
<value>50</value>
</property>
8.3 关闭WAL(谨慎使用) #
java
// Java API关闭WAL
Put put = new Put(Bytes.toBytes("user001"));
put.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"), Bytes.toBytes("张三"));
put.setDurability(Durability.SKIP_WAL); // 关闭WAL
table.put(put);
九、常见问题 #
9.1 数据类型问题 #
ruby
# 问题:数值比较不正确
put 'user', 'user001', 'info:score', '100'
put 'user', 'user001', 'info:score', '9'
# 查询时按字典序排序
# 结果:100 < 9(字典序)
# 解决:使用固定长度或补零
put 'user', 'user001', 'info:score', '100'
put 'user', 'user001', 'info:score', '009'
9.2 热点问题 #
ruby
# 问题:顺序写入导致热点
put 'user', 'user001', 'info:name', '张三'
put 'user', 'user002', 'info:name', '李四'
put 'user', 'user003', 'info:name', '王五'
# 解决:使用散列RowKey
put 'user', 'a1b2_user001', 'info:name', '张三'
put 'user', 'c3d4_user002', 'info:name', '李四'
put 'user', 'e5f6_user003', 'info:name', '王五'
9.3 版本数限制 #
ruby
# 问题:版本数超过限制
create 'user', {NAME => 'info', VERSIONS => 3}
put 'user', 'user001', 'info:name', 'v1'
put 'user', 'user001', 'info:name', 'v2'
put 'user', 'user001', 'info:name', 'v3'
put 'user', 'user001', 'info:name', 'v4'
# 结果:只保留最新3个版本(v2, v3, v4)
十、最佳实践 #
10.1 数据设计 #
text
数据设计建议
├── 合理设计RowKey避免热点
├── 列名简短减少存储
├── 使用压缩减少存储空间
└── 设置合理的版本数和TTL
10.2 写入优化 #
text
写入优化建议
├── 使用批量插入
├── 预分区避免热点
├── 合理设置MemStore大小
└── 低峰期大量写入
10.3 数据一致性 #
text
数据一致性建议
├── 使用CAS操作保证原子性
├── 重要数据开启WAL
├── 合理设计版本策略
└── 定期备份重要数据
十一、总结 #
本节介绍了HBase插入数据:
| 操作 | 语法 |
|---|---|
| 基本插入 | put ‘表’, ‘row’, ‘cf:col’, ‘value’ |
| 指定时间戳 | put ‘表’, ‘row’, ‘cf:col’, ‘value’, ts |
| 批量插入 | table.put(puts_list) |
| 原子插入 | checkAndPut |
| 追加 | append ‘表’, ‘row’, ‘cf:col’, ‘value’ |
| 计数器 | incr ‘表’, ‘row’, ‘cf:col’ |
下一步,让我们学习查询数据!
最后更新:2026-03-27