本节主要讲解了HBase API的几个原子操作:AppendCheckAndPutCheckAndDeleteIncrement
即追加、检查并添加、检查并删除以及计数器。

1. 本节准备

1.1 Hbase表实例

这里还是以学生分数表为例:
表名为studentScore,行键为name,列族为gradeaverage score
其逻辑视图如下所示:

name

grade

average score

Zhangsan

A

95.0

Lisi

B

100

1.2 启动相应服务

启动HadoopZookeeperHBase

start-dfs.sh
start-yarn.sh
zkServer.sh start
start-hbase.sh

1.3 创建项目

② 打开Eclipse,新建项目(本节项目名为hbase_study2),新建包(edu.hbase.study)。
③ 复制hbase/bin目录下的log4j.propertiesEclipse项目的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操作

加入我们已经添加了ZhangsangradeA,但是后面需要修改为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的后面

结果如下图所示:

hbase 创建压缩表命令 hbase api创建表_大数据

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

这个操作如其名,就是对存储的数据进行加减运算。
例如,这里我们需要将Zhangsanaverage 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 创建压缩表命令 hbase api创建表_hbase 创建压缩表命令_02

这个操作很有用,由于HBase存储的是字符串类型的数据,对整型数据不好操作。有了这个方法,就可以获得整型值,修改整型值。
例如,做了一个点赞器。点赞一次,数值增加1。那么就可以用这个方法直接修改,而不用获取字符串再进行操作。

演示一下HBase shell的操作和结果:

incr 'studentScore', 'Zhangsan', 'grad:', 0 # 获得当前值
incr 'studentScore', 'Zhangsan', 'grad:', 5 # 当前值 +5
incr 'studentScore', 'Zhangsan', 'grad:', -5 # 当前值 -5

hbase 创建压缩表命令 hbase api创建表_hadoop_03

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版本下的差异。