HBASE API 操作

1. IDEA 连接 HBASE

1、idea 创建一个 maven 项目

2、添加相关依赖(HBASE 客户端(最主要)、服务端),pom.xml

<dependencies>
    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-server</artifactId>
        <version>1.2.6</version>
    </dependency>

    <dependency>
        <groupId>org.apache.hbase</groupId>
        <artifactId>hbase-client</artifactId>
        <version>1.2.6</version>
    </dependency>
</dependencies>

3、在 resources 中添加 core-site.xml、hbase-site.xml

4、修改本机的 hosts 文件(在C:WindowsSystem32driversetc下),添加集群的 IP 名称:

192.168.131.137 hadoop1
192.168.131.138 hadoop2
192.168.131.139 hadoop3

注意:此步骤不添加,有可能会导致 idea 执行不成功!

项目结构:

F:.
│  pom.xml
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─jun
│  │  │          └─test
│  │  │                  TestApi.java
│  │  │
│  │  └─resources
│  │          core-site.xml
│  │          hbase-site.xml
│  │
│  └─test
│      └─java
└─target
    │  test_one.jar
    │
    ├─classes
    │  │  core-site.xml
    │  │  hbase-site.xml
    │  │
    │  └─com
    │      └─jun
    │          └─test
    │                  TestApi.class

参考文章:在本地用idea连接虚拟机上的hbase集群的实现代码

2. DDL 表操作

DDL 与表操作有关,比如:

  • 判断表是否存在
  • 创建、删除、修改表
  • 创建命名空间

2.1 配置连接

package com.jun.test;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;

import java.io.IOException;

public class TestApi {
    public static Connection connection = null;
    public static Admin admin = null;

    static {
        try {
            // 获取配置信息
            Configuration configuration = HBaseConfiguration.create();
            configuration.set("hbase.zookeeper.quorum", "hadoop1,hadoop2,hadoop3");

            // 创建连接对象
            connection = ConnectionFactory.createConnection(configuration);

            // 创建 admin 对象
            admin = connection.getAdmin();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 关闭连接
    public static void close() {
        if (admin != null) {
            try {
                admin.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (connection != null) {
            try {
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws IOException {
        // 判断表是否存在
//        System.out.println(isTableExists("t1"));

        // 创建表
//        createTable("t2", "info");

        // 将表创建到命名空间中
//        createTable("0808:t2", "info");

        // 删除表
//        deleteTable("t2");

        // 创建命名空间
//        createNameSpace("0808");

        // 关闭资源
        close();
    }
}

2.2 判断表是否存在

// 判断表是否存在
public static boolean isTableExists(String tableName) throws IOException {
    boolean exists = admin.tableExists(TableName.valueOf(tableName));
    return exists;
}

2.3 创建表

创建表包括:添加列族信息、还可以将表添加到命名空间,创建之前可以先检查该表是否存在:

// 创建表
public static void createTable(String tableName, String... cfs) throws IOException {
    // 判断列族信息
    if (cfs.length <= 0) {
        System.out.println("请设置列族信息!!!");
        return;
    }

    // 判断表是否存在
    if (isTableExists(tableName)) {
        System.out.println(tableName + " 表已存在!!!");
        return;
    }

    // 创建表描述器对象
    HTableDescriptor descriptor = new HTableDescriptor(TableName.valueOf(tableName));

    // 循环添加列族
    for (String cf : cfs) {
        descriptor.addFamily(new HColumnDescriptor(cf));
    }

    // 创建表
    admin.createTable(descriptor);
    System.out.println("表 " + tableName + " 创建成功!!!");
}

2.4 删除表

// 删除表
public static void deleteTable(String tableName) throws IOException {
    if (isTableExists(tableName)) {
        admin.disableTable(TableName.valueOf(tableName));   // 先停用表,再删除
        admin.deleteTable(TableName.valueOf(tableName));
        System.out.println("表 " + tableName + " 删除成功!!!");
    } else {
        System.out.println("表 " + tableName + " 不存在!!!");
    }
}

2.5 创建命名空间

// 创建命名空间
public static void createNameSpace(String ns) {
    // 创建命名空间描述器
    NamespaceDescriptor namespaceDescriptor = NamespaceDescriptor.create(ns).build();

    // 创建命名空间
    try {
        admin.createNamespace(namespaceDescriptor);
        System.out.println(ns + "命名空间创建成功!!!");
    } catch (NamespaceExistException e) {
        System.out.println("命名空间 " + ns + " 已存在!!!");
    }
    catch (IOException e) {
        e.printStackTrace();
    }

}

可以在 hbase shell 中使用 list_namespace 查看命名空间:

hbase(main):012:0> list_namespace
NAMESPACE                                                                                 0808                                                                                     default                                                                                   hbase                                                                                                                                
3 row(s) in 0.0420 seconds
    
// t2 表在 0808 命名空间里
hbase(main):014:0> list
TABLE                                                                                     0808:t2                                                                                   t1                                                                                                                                   
2 row(s) in 0.0430 seconds

=> ["0808:t2", "t1"]

3. DML 表记录操作

DML主要是针对表的记录的操作,如插入、删除记录、查询记录等

3.1 插入数据

插入单条数据

 // 插入数据
public static void putData(String tableName, String rowKey, String cf, String cn, String value) throws IOException {
    // 获取表对象
    Table table = connection.getTable(TableName.valueOf(tableName));

    // 获取 Put 对象
    Put put = new Put(Bytes.toBytes(rowKey));

    // 给 put 对象赋值
    put.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn), Bytes.toBytes(value));

    // 插入数据
    table.put(put);

    System.out.println("数据插入成功!!!");

    // 关闭表连接
    table.close();
}

测试:

// 插入数据
putData("t2", "10001", "info", "name", "rose");

插入多条数据

使用集合:

public static byte[] getBytes(String value) {
    return Bytes.toBytes(value);
}

// 插入多条数据
public static void putManyData(String tableName, String cf, String cn, String value) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    // 定义一个集合
    List<Put> puts = new ArrayList<>();
    int row_key = 10001;

    for (int i = 1; i <= 5; i++) {
        row_key = row_key + i;
        Put put = new Put(getBytes(String.valueOf(row_key)));
        put.addColumn(getBytes(cf), getBytes(cn + i), getBytes(value + i));
        puts.add(put);
    }
    table.put(puts);
    System.out.println("成功插入多行数据!");
    table.close();
}

测试:

// 插入多条数据
putManyData("t2", "info", "alias", "jun");

// scan t2
hbase(main):005:0> scan 't2'
ROW                            COLUMN+CELL                                                                          
10001                         column=info:name, timestamp=1628369721705, value=rose     10002                         column=info:alias1, timestamp=1628383262854, value=jun1     10004                         column=info:alias2, timestamp=1628383262854, value=jun2     10007                         column=info:alias3, timestamp=1628383262854, value=jun3     10011                         column=info:alias4, timestamp=1628383262854, value=jun4     10016                         column=info:alias5, timestamp=1628383262854, value=jun5                              
6 row(s) in 0.0860 seconds

3.2 get 数据

获取某行数据

// get 单条数据
public static void getData(String tableName, String rowKey) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    Get get = new Get((Bytes.toBytes(rowKey)));

    // 获取最大版本数
    System.out.println(get.getMaxVersions());
    //        System.out.println(get.setTimeStamp());

    // 获取整行数据
    Result result = table.get(get);
    for (Cell cell : result.rawCells()) {
        System.out.println("行键: " + Bytes.toString(result.getRow()));
        System.out.println("列族: " + Bytes.toString(CellUtil.cloneFamily(cell)));
        System.out.println("列: " + Bytes.toString(CellUtil.cloneQualifier(cell)));
        System.out.println("值: " + Bytes.toString(CellUtil.cloneValue(cell)));
        System.out.println("时间戳: " + cell.getTimestamp());

    }
    table.close();
}

测试数据:

// 获取数据
getData("t2", "10001");

1
行键: 10001
列族: info
列: name
值: rose
时间戳: 1628369721705

指定列族、列名

// 指定列族
get.addFamily(Bytes.toBytes(cf));

// 指定列名
get.addColumn(Bytes.toBytes(cn));

3.3 scan 数据

// scan 所有数据
public static void scanData(String tableName) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    Scan scan = new Scan();
    ResultScanner resultScanner = table.getScanner(scan);
    for (Result result : resultScanner) {
        Cell[] cells = result.rawCells();
        for (Cell cell : cells) {
            System.out.println("行键: " + Bytes.toString(result.getRow()));
            System.out.println("列族: " + Bytes.toString(CellUtil.cloneFamily(cell)));
            System.out.println("列: " + Bytes.toString(CellUtil.cloneQualifier(cell)));
            System.out.println("值: " + Bytes.toString(CellUtil.cloneValue(cell)));
            System.out.println("时间戳: " + cell.getTimestamp());
            System.out.println("-------------------------------------------

");
        }
    }
	table.close();
}

测试数据:

// 扫描所有数据
scanData("t2");

行键: 10001
列族: info
列: name
值: rose
时间戳: 1628369721705
-------------------------------------------


行键: 10002
列族: info
列: alias1
值: jun1
时间戳: 1628383262854
-------------------------------------------


行键: 10004
列族: info
列: alias2
值: jun2
时间戳: 1628383262854
-------------------------------------------


行键: 10007
列族: info
列: alias3
值: jun3
时间戳: 1628383262854
-------------------------------------------


行键: 10011
列族: info
列: alias4
值: jun4
时间戳: 1628383262854
-------------------------------------------


行键: 10016
列族: info
列: alias5
值: jun5
时间戳: 1628383262854
-------------------------------------------

建议

使用 scan 扫描全表时,最好设置 startRow、endRow,亦或者是带过滤条件的翻页,而非全表扫描:

// 设置 startRow
Scan(Bytes.toBytes("startRow"))
  
// 设置 startRow、endRow
Scan(Bytes.toBytes("startRow"), Bytes.toBytes("endRow"))
    
// 实际工作中一般不知道 endRow,而是带过滤条件的翻页
Scan(Bytes.toBytes("startRow"), Filter filter)
    
ResultScanner resultScanner = table.getScanner(scan);

3.4 删除数据

删除单行数据

// 删除单行数据
public static void deleteData(String tableName, String rowKey) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    // 获取 delete 对象
    Delete delete = new Delete(Bytes.toBytes(rowKey));

    // 删除指定的列族、列名
    //        delete.addColumn(Bytes.toBytes(cf), Bytes.toBytes(cn));

    table.delete(delete);
    System.out.println(rowKey + " 删除成功!!!");
    table.close();
}

测试:

// 删除单行数据
deleteData("t2", "10001");

hbase(main):007:0> scan 't2'
ROW                                COLUMN+CELL                                                                                       
 10002                             column=info:alias1, timestamp=1628383262854, value=jun1                                           
 10004                             column=info:alias2, timestamp=1628383262854, value=jun2                                           
 10007                             column=info:alias3, timestamp=1628383262854, value=jun3                                           
 10011                             column=info:alias4, timestamp=1628383262854, value=jun4                                           
 10016                             column=info:alias5, timestamp=1628383262854, value=jun5                                           
5 row(s) in 0.1290 seconds

删除多行数据

// 删除多行数据
public static void deleteManyData(String tableName, String... rows) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    List<Delete> deletes = new ArrayList<>();

    for (String row : rows) {
        Delete delete = new Delete(Bytes.toBytes(row));
        deletes.add(delete);
    }

    table.delete(deletes);
    System.out.println("删除成功!!!");
    table.close();
}

测试:

// 删除多行数据
deleteManyData("t2", "10002", "10007");

hbase(main):008:0> scan 't2'
ROW                                COLUMN+CELL                                                                                       
 10004                             column=info:alias2, timestamp=1628383262854, value=jun2                                           
 10011                             column=info:alias4, timestamp=1628383262854, value=jun4                                           
 10016                             column=info:alias5, timestamp=1628383262854, value=jun5                                           
3 row(s) in 0.1140 seconds

4. 过滤器

要完成一个过滤的操作,至少需要两个参数。一个是抽象的操作符,Hbase 提供了枚举类型的变量来表示这些抽象的操作符:LESS/LESS_OR_EQUAL/EQUAL/NOT_EUQAL等;另外一个就是具体的比较器(Comparator),代表具体的比较逻辑,如果可以提高字节级的比较、字符串级的比较等。有了这两个参数,我们就可以清晰的定义筛选的条件,过滤数据。

抽象操作符(比较运算符)

LESS <
LESS_OR_EQUAL <=
EQUAL =
NOT_EQUAL <>
GREATER_OR_EQUAL >=
GREATER >
NO_OP 排除所有

比较器(指定比较机制)

BinaryComparator 按字节索引顺序比较指定字节数组,采用 Bytes.compareTo(byte[])

BinaryPrefixComparator 跟前面相同,只是比较左端的数据是否相同

NullComparator 判断给定的是否为空

BitComparator 按位比较

RegexStringComparator 提供一个正则的比较器,仅支持 EQUAL 和非 EQUAL

SubstringComparator 判断提供的子串是否出现在 value 中

4.1 行键过滤器

过滤出 rowkey 大于 10004 的数据:

// 过滤器
public static void scanFilterData(String tableName) throws IOException {
    Table table = connection.getTable(TableName.valueOf(tableName));

    // GREATER 大于、 BinaryComparator 按字节索引顺序比较指定字节数组
    Filter rowFilter = new RowFilter(CompareFilter.CompareOp.GREATER, new BinaryComparator("10004".getBytes()));
    Scan scan = new Scan();
    scan.setFilter(rowFilter);

    ResultScanner resultScanner = table.getScanner(scan);
    for (Result result: resultScanner) {
        Cell[] cells = result.rawCells();
        for (Cell cell: cells) {
            System.out.println("行键: " + Bytes.toString(result.getRow()));
            System.out.println("列族: " + Bytes.toString(CellUtil.cloneFamily(cell)));
            System.out.println("列: " + Bytes.toString(CellUtil.cloneQualifier(cell)));
            System.out.println("值: " + Bytes.toString(CellUtil.cloneValue(cell)));

        }
    }
    table.close();
}

测试:

// t2 表中所有数据
hbase(main):008:0> scan 't2'
ROW                                COLUMN+CELL                                                                                       
10004                             column=info:alias2, timestamp=1628383262854, value=jun2                                           
10011                             column=info:alias4, timestamp=1628383262854, value=jun4                                           
10016                             column=info:alias5, timestamp=1628383262854, value=jun5                                           
3 row(s) in 0.1140 seconds

// 过滤器
scanFilterData("t2");

行键: 10011
列族: info
列: alias4
值: jun4

行键: 10016
列族: info
列: alias5
值: jun5

5. 参考文章

原文地址:https://www.cnblogs.com/midworld/p/15116690.html