本节主要讲解了
HBase
API
的几个原子操作:Append
、CheckAndPut
、CheckAndDelete
、Increment
。
即追加、检查并添加、检查并删除以及计数器。
1. 本节准备
1.1 Hbase表实例
这里还是以学生分数表为例:
表名为studentScore
,行键为name
,列族为grade
和average score
。
其逻辑视图如下所示:
name | grade | average score |
Zhangsan | A | 95.0 |
Lisi | B | 100 |
1.2 启动相应服务
启动Hadoop
、Zookeeper
和HBase
。
start-dfs.sh
start-yarn.sh
zkServer.sh start
start-hbase.sh
1.3 创建项目
② 打开Eclipse
,新建项目(本节项目名为hbase_study2
),新建包(edu.hbase.study
)。
③ 复制hbase/bin
目录下的log4j.properties
到Eclipse
项目的src
目录下。
2. 代码讲解
2.1 创建连接和关闭连接
// 连接
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "localhost");
conf.set("hbase.zookeeper.property.clientPort", "2181");
Connection conn = ConnectionFactory.createConnection(conf);
Admin = admin.conn.getAdmin();
// 关闭
if (admin != null)
admin.close();
if (null != conn)
conn.close();
2.2 创建表
以下步骤每次进行之前都需要连接服务,完成操作后必须关闭服务。
TableName = tableName = TableName.valueOf("studentScore");
if (admin.tableExists(tableName) {
System.out.println(tableName "is exists.");
} else {
HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);
String[] colFamily = {"grade", "average score"};
for (String str : colFamily) {
HColumnDescriptor hcoulColumnDescriptor = new HColumnDescriptor(str);
hTableDescriptor.addFamily(hcoulColumnDescriptor);
}
admin.createTable(hTableDescriptor);
2.3 Append操作
加入我们已经添加了Zhangsan
的grade
为A
,但是后面需要修改为A-
。
① 我们可以再次执行put
,将修改的数据覆盖(这里简单理解为覆盖,其实由于HDFS的特性,并没有覆盖原数据)。
② 也可以使用Append
的方式,将-
追加在A
的后面。
Table table = conn.getTable(TableName.valueOf("studentScore"));
Append append = new Append("Zhangsan");
// 语句 1
append.add(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("A"));
// 语句 2
append.add(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("-"));
table.close();
执行顺序:
① 执行语句1,注释语句2
和put类似的功能,插入新行
② 执行语句2,注释语句1
将-
追加在A
的后面
结果如下图所示:
2.4 CheckAndPut 操作
这个操作如其名,检查之后进行插入数据。即如果存在指定的数据,则插入,不存在则不插入。
注意以下几点:
① 这个操作是针对一行进行操作,不能跨行操作。
② 同理,可以跨列族或者跨列限定符。
③ checkAndPut()
方法有5个参数,从左到右分别为行键、列族、列限定符、单元格值以及put实例。前面四个为需要检查的值。put实例是需要插入的值。即如果前面四个成立,则执行put;否则不执行。
Table table = conn.getTable(TableName.valueOf("studentScore"));
Put put = new Put(Bytes.toBytes("Zhangsan"));
put.addColumn(Bytes.toBytes("average Score"), Bytes.toBytes(""), Bytes.toBytes("90"));
// 跨列族检查
table.checkAndPut(Bytes.toBytes("Zhangsan"),"grade"), Bytes.toBytes(""), Bytes.toBytes("A-"), put);
// 跨列限定符检查,这里不做演示,可以执行
// 如果put实例所在的行键和检查的行键不同,即跨行键,会直接报错。抛出DoNotretryIOException异常
table.close();
2.5 CheckAndDelete 操作
这个和CheckAndPut类似。即检查并删除操作。
Table table = conn.getTable(TableName.valueOf("studentScore"));
Delete del = new Delete(Bytes.toBytes("Zhangsan"));
del.addColumns(Bytes.toBytes("average score", Bytes.toBytes("")));
table.checkAndDelete(Bytes.toBytes("Zhangsan"),"grade"), Bytes.toBytes(""), Bytes.toBytes("A-"), del);
table.close();
2.6 Increment操作
这个操作在HBase shell中如下:
incr 'studentScore', 'Zhangsan', 'average score', 90
这个操作如其名,就是对存储的数据进行加减运算。
例如,这里我们需要将Zhangsan
的average score
增加为90
。
Table table = conn.getTable(TableName.valueOf("studentScore"));
// result为返回的增加后的值
long result = table.incrementColumnValue(Bytes.toBytes("Zhangsan"), Bytes.toBytes("average score", Bytes.toBytes(""), 90));
System.out.println(result);
// 如果要获得当前值怎么办?
long result2 = table.incrementColumnValue(Bytes.toBytes("Zhangsan"), Bytes.toBytes("average score", Bytes.toBytes(""), 0));
System.out.println(result2);
table.close();
运行结果如下图所示:
这个操作很有用,由于HBase存储的是字符串类型的数据,对整型数据不好操作。有了这个方法,就可以获得整型值,修改整型值。
例如,做了一个点赞器。点赞一次,数值增加1。那么就可以用这个方法直接修改,而不用获取字符串再进行操作。
演示一下HBase shell的操作和结果:
incr 'studentScore', 'Zhangsan', 'grad:', 0 # 获得当前值
incr 'studentScore', 'Zhangsan', 'grad:', 5 # 当前值 +5
incr 'studentScore', 'Zhangsan', 'grad:', -5 # 当前值 -5
2.7 完整代码
package edu.hbase.study2;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.util.Bytes;
/**
* 1.2.3 HBase 下测试成功
* @author 凝心如定
*
*/
public class EduAppend {
public static Configuration conf;
public static Connection conn;
public static Admin admin;
public static void init() throws IOException {
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "localhost");
conf.set("hbase.zookeeper.property.clientPort", "2181");
conn = ConnectionFactory.createConnection(conf);
admin = conn.getAdmin();
}
public static void close() throws IOException {
if (null != conn) {
conn.close();
}
if (null != admin) {
admin.close();
}
}
// 创建表
public static void createTable() throws IOException {
init();
TableName tableName = TableName.valueOf("studentScore");
if (admin.tableExists(tableName)) {
System.out.println(tableName + " is exists.");
} else {
HTableDescriptor hTableDescriptor = new HTableDescriptor(tableName);
String[] colFamily = { "grade", "average score" };
for (String str : colFamily) {
HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(str);
hTableDescriptor.addFamily(hColumnDescriptor);
}
admin.createTable(hTableDescriptor);
}
close();
}
public static void append() throws IOException{
init();
Table table = conn.getTable(TableName.valueOf("studentScore"));
Append append = new Append(Bytes.toBytes("Zhangsan"));
// append.add(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("A"));
// append.add(Bytes.toBytes("grade"), Bytes.toBytes(""), Bytes.toBytes("-"));
table.append(append);
table.close();
close();
}
public static void checkAndPut() throws IOException {
init();
Table table = conn.getTable(TableName.valueOf("studentScore"));
Put put = new Put(Bytes.toBytes("Zhangsan"));
put.addColumn(Bytes.toBytes("average score"), Bytes.toBytes(""), Bytes.toBytes("90"));
// 跨列族操作
table.checkAndPut(Bytes.toBytes("Zhangsan"), Bytes.toBytes("grade"),
Bytes.toBytes(""), Bytes.toBytes("A-"), put);
table.close();
close();
}
public static void checkAndDelete() throws IOException {
init();
Table table = conn.getTable(TableName.valueOf("studentScore"));
Delete del = new Delete(Bytes.toBytes("Zhangsan"));
del.addColumns(Bytes.toBytes("average score"), Bytes.toBytes(""));
table.checkAndDelete(Bytes.toBytes("Zhangsan"), Bytes.toBytes("grade"),
Bytes.toBytes(""), Bytes.toBytes("A-"), del);
table.close();
close();
}
public static void increment() throws IOException {
init();
Table table = conn.getTable(TableName.valueOf("studentScore"));
long result = table.incrementColumnValue(Bytes.toBytes("Zhangsan"),
Bytes.toBytes("average score"), Bytes.toBytes(""), 90);
System.out.println(result);
long result2 = table.incrementColumnValue(Bytes.toBytes("r1"),
Bytes.toBytes("d"), Bytes.toBytes("i1"), 0);
System.out.println(result2);
table.close();
close();
}
public static void main(String[] args) throws IOException {
// createTable();
// append();
// checkAndPut();
// checkAndDelete();
// increment();
}
}
3. 总结
本节介绍了HBase API的4个操作,可以简便代码编写过程。HBase版本0.96和1.2.3核心思想都一样,只在于连接HBase和其他几个函数的差别,这里就不多赘述了,可以参看HBase增删改查在0.96和1.2.3版本下的差异。