1. 程式人生 > 其它 >SpringBoot - 使用hbase-client操作HBase教程1(基本用法)

SpringBoot - 使用hbase-client操作HBase教程1(基本用法)

HBase是一個分散式的、面向列的開源的NoSQL資料庫。Spring Boot專案如果需要操作HBase通常有如下幾種客戶端可以使用:
  • hbase-client:比較底層,需要自己進一步封裝api,而且版本號和安裝的hbase也要匹配,否則會報錯
  • spring-data-hadoop:2019年4月5停止維護
  • Apache Phoenix:使用SQL的方式來操作HBase。Phoenix的效能很高(進行簡單查詢,其效能量級是毫秒),相對於hbase原生的scan並不會差多少,而對於類似的元件hive、Impala等,效能有著顯著的提升
本文演示如何使用hbase-client操作HBase資料庫。

一、安裝配置

1,環境準備

(1)關於HBase的安裝,可以參考我之前寫的文章:

(2)同時HBase伺服器主機名不能為localhost或者VM-16-6-centos,否則客戶端無法連線,具體參考我另一篇文章:

2,專案配置

(1)首先編輯專案的pom.xml檔案,新增hbase-client依賴:
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>
2.3.0</version> </dependency>

(2)然後在application.properties中新增HBase相關配置(即ZooKeeper的地址和埠):

# HBase 資料來源配置
hbase.config.hbase.zookeeper.quorum=86.168.xx.xx
hbase.config.hbase.zookeeper.property.clientPort=2181

yml版本

hbase:
  config:
    hbase:
      zookeeper:
        property:
          clientPort: 2181
        quorum: 81.68.xx.xx

3,編寫工具類

(1)首先編寫HBaseConfig.java來讀取配置檔案,獲取hbase引數:
@Configuration
@ConfigurationProperties(prefix = "hbase")
public class HBaseConfig {
 
    private Map<String, String> config = new HashMap<>();
 
    public Map<String, String> getConfig() {
        return config;
    }
 
    public void setConfig(Map<String, String> config) {
        this.config = config;
    }
 
    public org.apache.hadoop.conf.Configuration configuration() {
        org.apache.hadoop.conf.Configuration configuration = HBaseConfiguration.create();
//此處可自己自定義和改造 拓展用
       //        configuration.set(HBASE_QUORUM, "81.68.xx.xx:2181");
//        configuration.set(HBASE_ROOTDIR, "/");
//        configuration.set(HBASE_ZNODE_PARENT, "/hbase");
        for(Map.Entry<String, String> map : config.entrySet()){
            configuration.set(map.getKey(), map.getValue());
        }
        return configuration;
    }
 
    @Bean
    public Admin admin() {
        Admin admin = null;
        try {
            Connection connection = ConnectionFactory.createConnection(configuration());
            admin = connection.getAdmin();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return admin;
    }
}

(2)由於hbase-client比較底層,我們還要封裝一個HBaseUtils.java工具類,實現建立表、插入、讀取、刪除資料:

@Service
public class HBaseUtils {

    @Autowired
    private Admin hbaseAdmin;

    /**
     * 判斷表是否存在
     *
     * @param tableName 表名
     * @return true/false
     */
    public boolean isExists(String tableName) {
        boolean tableExists = false;
        try {
            TableName table = TableName.valueOf(tableName);
            tableExists = hbaseAdmin.tableExists(table);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return tableExists;
    }

    /**
     * 建立表
     * @param tableName 表名
     * @param columnFamily 列族
     * @return true/false
     */
    public boolean createTable(String tableName, List<String> columnFamily) {
        return createTable(tableName, columnFamily, null);
    }

    /**
     * 預分割槽建立表
     * @param tableName 表名
     * @param columnFamily 列族
     * @param keys 分割槽集合
     * @return true/false
     */
    public boolean createTable(String tableName, List<String> columnFamily, List<String> keys) {
        if (!isExists(tableName)) {
            try {
                TableName table = TableName.valueOf(tableName);
                HTableDescriptor desc = new HTableDescriptor(table);
                for (String cf : columnFamily) {
                    desc.addFamily(new HColumnDescriptor(cf));
                }
                if (keys == null) {
                    hbaseAdmin.createTable(desc);
                } else {
                    byte[][] splitKeys = getSplitKeys(keys);
                    hbaseAdmin.createTable(desc, splitKeys);
                }
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println(tableName + "is exists!!!");
            return false;
        }
        return false;
    }

    /**
     * 刪除表
     *
     * @param tableName 表名
     */
    public void dropTable(String tableName) throws IOException {
        if (isExists(tableName)) {
            TableName table = TableName.valueOf(tableName);
            hbaseAdmin.disableTable(table);
            hbaseAdmin.deleteTable(table);
        }
    }

    /**
     * 插入資料(單條)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param column 列
     * @param value 值
     * @return true/false
     */
    public boolean putData(String tableName, String rowKey, String columnFamily, String column,
                           String value) {
        return putData(tableName, rowKey, columnFamily, Arrays.asList(column),
                Arrays.asList(value));
    }

    /**
     * 插入資料(批量)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param columns 列
     * @param values 值
     * @return true/false
     */
    public boolean putData(String tableName, String rowKey, String columnFamily,
                           List<String> columns, List<String> values) {
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Put put = new Put(Bytes.toBytes(rowKey));
            for (int i=0; i<columns.size(); i++) {
                put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columns.get(i)),
                        Bytes.toBytes(values.get(i)));
            }
            table.put(put);
            table.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 獲取資料(全表資料)
     * @param tableName 表名
     * @return map
     */
    public List<Map<String, String>> getData(String tableName) {
        List<Map<String, String>> list = new ArrayList<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Scan scan = new Scan();
            ResultScanner resultScanner = table.getScanner(scan);
            for(Result result : resultScanner) {
                HashMap<String, String> map = new HashMap<>();
                //rowkey
                String row = Bytes.toString(result.getRow());
                map.put("row", row);
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                            cell.getFamilyOffset(), cell.getFamilyLength());
                    //
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                            cell.getQualifierOffset(), cell.getQualifierLength());
                    //
                    String data = Bytes.toString(cell.getValueArray(),
                            cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
                list.add(map);
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 獲取資料(根據傳入的filter)
     * @param tableName 表名
     * @param filter 過濾器
     * @return map
     */
    public List<Map<String, String>> getData(String tableName, Filter filter) {
        List<Map<String, String>> list = new ArrayList<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Scan scan = new Scan();
            // 新增過濾器
            scan.setFilter(filter);
            ResultScanner resultScanner = table.getScanner(scan);
            for(Result result : resultScanner) {
                HashMap<String, String> map = new HashMap<>();
                //rowkey
                String row = Bytes.toString(result.getRow());
                map.put("row", row);
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                        cell.getFamilyOffset(), cell.getFamilyLength());
                    //
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                        cell.getQualifierOffset(), cell.getQualifierLength());
                    //
                    String data = Bytes.toString(cell.getValueArray(),
                        cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
                list.add(map);
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 獲取資料(根據rowkey)
     * @param tableName 表名
     * @param rowKey rowKey
     * @return map
     */
    public Map<String, String> getData(String tableName, String rowKey) {
        HashMap<String, String> map = new HashMap<>();
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Get get = new Get(Bytes.toBytes(rowKey));
            Result result = table.get(get);
            if (result != null && !result.isEmpty()) {
                for (Cell cell : result.listCells()) {
                    //列族
                    String family = Bytes.toString(cell.getFamilyArray(),
                            cell.getFamilyOffset(), cell.getFamilyLength());
                    //
                    String qualifier = Bytes.toString(cell.getQualifierArray(),
                            cell.getQualifierOffset(), cell.getQualifierLength());
                    //
                    String data = Bytes.toString(cell.getValueArray(),
                            cell.getValueOffset(), cell.getValueLength());
                    map.put(family + ":" + qualifier, data);
                }
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 獲取資料(根據rowkey,列族,列)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param columnQualifier 列
     * @return map
     */
    public String getData(String tableName, String rowKey, String columnFamily,
                          String columnQualifier) {
        String data = "";
        try {
            Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
            Get get = new Get(Bytes.toBytes(rowKey));
            get.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(columnQualifier));
            Result result = table.get(get);
            if (result != null && !result.isEmpty()) {
                Cell cell = result.listCells().get(0);
                data = Bytes.toString(cell.getValueArray(), cell.getValueOffset(),
                        cell.getValueLength());
            }
            table.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 刪除資料(根據rowkey)
     * @param tableName 表名
     * @param rowKey rowKey
     */
    public void deleteData(String tableName, String rowKey) throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        table.delete(delete);
        table.close();
    }

    /**
     * 刪除資料(根據rowkey,列族)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     */
    public void deleteData(String tableName, String rowKey, String columnFamily)
            throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        delete.addFamily(columnFamily.getBytes());
        table.delete(delete);
        table.close();
    }

    /**
     * 刪除資料(根據rowkey,列族)
     * @param tableName 表名
     * @param rowKey rowKey
     * @param columnFamily 列族
     * @param column 列
     */
    public void deleteData(String tableName, String rowKey, String columnFamily, String column)
            throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        Delete delete = new Delete(Bytes.toBytes(rowKey));
        delete.addColumn(columnFamily.getBytes(), column.getBytes());
        table.delete(delete);
        table.close();
    }

    /**
     * 刪除資料(多行)
     * @param tableName 表名
     * @param rowKeys rowKey集合
     */
    public void deleteData(String tableName, List<String> rowKeys) throws IOException{
        Table table = hbaseAdmin.getConnection().getTable(TableName.valueOf(tableName));
        List<Delete> deleteList = new ArrayList<>();
        for(String row : rowKeys){
            Delete delete = new Delete(Bytes.toBytes(row));
            deleteList.add(delete);
        }
        table.delete(deleteList);
        table.close();
    }

    /**
     * 分割槽【10, 20, 30】 -> ( ,10] (10,20] (20,30] (30, )
     * @param keys 分割槽集合[10, 20, 30]
     * @return byte二維陣列
     */
    private byte[][] getSplitKeys(List<String> keys) {
        byte[][] splitKeys = new byte[keys.size()][];
        TreeSet<byte[]> rows = new TreeSet<>(Bytes.BYTES_COMPARATOR);
        for(String key : keys) {
            rows.add(Bytes.toBytes(key));
        }
        int i = 0;
        for (byte[] row : rows) {
            splitKeys[i] = row;
            i ++;
        }
        return splitKeys;
    }
}

附:使用樣例

(1)下面建立一個Controller呼叫HBaseUtils來操作HBase資料庫:

@RestController
@AllArgsConstructor
@RequestMapping("/common/front")
public class FrontController {
 
    @Autowired
    private HBaseUtils hbaseUtils;
 
    @GetMapping("/test")
    public void test() throws IOException {
        System.out.println("---開始建立test表---");
        hbaseUtils.createTable("test", Arrays.asList("cf"));
 
        System.out.println("---判斷test表是否存在---");
        Boolean t = hbaseUtils.isExists("test");
        System.out.println(t);
 
        System.out.println("\n---插入一列資料---");
        hbaseUtils.putData("test", "row1", "cf", "a", "value1-1");
 
        System.out.println("\n---插入多列資料---");
        hbaseUtils.putData("test", "row2", "cf",
                Arrays.asList("a", "b", "c"),  Arrays.asList("value2-1", "value2-2", "value2-3"));
 
        System.out.println("\n---根據rowkey、列族、列查詢資料---");
        String columnData = hbaseUtils.getData("test", "row2", "cf", "b");
        System.out.println(columnData);
 
        System.out.println("\n---根據rowkey查詢資料---");
        Map<String, String> rowData = hbaseUtils.getData("test", "row2");
        System.out.println(rowData);
 
        System.out.println("\n---查詢全表資料---");
        List<Map<String, String>> tableData = hbaseUtils.getData("test");
        System.out.println(tableData);
 
        System.out.println("\n---根據rowkey、列族、列刪除資料---");
        hbaseUtils.deleteData("test", "row2", "cf", "b");
 
        System.out.println("\n---根據rowkey、列族刪除資料---");
        hbaseUtils.deleteData("test", "row2", "cf");
 
        System.out.println("\n---根據rowkey刪除資料---");
        hbaseUtils.deleteData("test", "row2");
 
        System.out.println("\n---根據rowkey批量刪除資料---");
        hbaseUtils.deleteData("test", Arrays.asList("row1", "row2"));
 
        System.out.println("\n---刪除表---");
        hbaseUtils.dropTable("test");
    }
}

2)使用瀏覽器訪問/test介面,可以看到控制檯輸出如下:

早年同窗始相知,三載瞬逝情卻萌。年少不知愁滋味,猶讀紅豆生南國。別離方知相思苦,心田紅豆根以生。