Hbase——JavaAPI操作笔记

写在前面

这篇文章上接Hbase搭建和Shell命令,咕咕咕了好久,最近终于有空歇下来总结一下了。

基本API——增删改

导入依赖

首先新建一个maven项目,导入如下的依赖:

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

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

这里的版本要和服务器里的版本相对应。

准备工作

为了方便以后的连接,我们直接把连接HBase的配置写到静态代码块里,这样每次这个类运行的时候都会执行这些代码:

    private static Connection connection = null;
    private static Admin admin = null;
    static {
        try {
            // 1.获取配置信息
            Configuration configuration = HBaseConfiguration.create();
            configuration.set("hbase.zookeeper.quorum","hadoop03,hadoop04,hadoop05");

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

            // 3.创建admin对象
            admin = connection.getAdmin();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这里的configuration里set的值要换成你自己的hbase地址。我这里是在windows里配置了hosts文件映射,所以可以直接写主机名。建议都去配一下映射,不然好像会报错。

检验表是否存在

先来看代码:

    /**
     * 1.判断表是否存在
     * @return
     */
    public static boolean isTableExist(String tableName) throws IOException {
        // 1.判断表是否存在
        boolean exists = admin.tableExists(TableName.valueOf(tableName));
        // 2.关闭连接
        admin.close();
        // 3.返回结果
        return exists;
    }

这里要注意的点是,tableExists()方法只能传入一个TableName对象,我们可以通过TableName.valueOf()来获得一个TableName对象。

创建表

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

        return;
    }
    // 3.创建表描述器
    HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));
    // 4.循环添加列族信息
    for (String cf : cfs) {
        // 5.创建列族描述器
        HColumnDescriptor hColumnDescriptor = new HColumnDescriptor(cf);
        // 6.添加具体的列族信息
        hTableDescriptor.addFamily(hColumnDescriptor);

    }
    // 7.创建表
    admin.createTable(hTableDescriptor);
}

这里要注意的点是,我们通过面向对象的思想来创建一个表,首先创建一个表描述器,然后对表描述器添加列族描述器。这里只是一个例子,可以传入的类型不止这些,可以再细看API。

删除表

删除表,就跟我们用shell操作一样,先让表失效,再去删除表:

    /**
     * 3.删除表
     */
    public static void dropTable(String tableName) throws IOException {
        // 1.判断表是否存在
        if(!isTableExist(tableName)){
            System.out.println(tableName + "表不存在!!");
            return;
        }
        // 2.使表下线
        admin.disableTable(TableName.valueOf(tableName));

        // 3.删除表
        admin.deleteTable(TableName.valueOf(tableName));
    }

向表插入(修改)数据

向表插入或者修改数据,我们使用Put对象即可。创建一个Put对象,然后对其赋值即可:

    /**
     * 5.向表插入数据
     */
    public static void putData(String tableName,String rowKey,String cf,String cn,String value) throws IOException {
        // 1.获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));
        // 2.创建put对象
        Put put = new Put(Bytes.toBytes(rowKey));
        // 3.给Put对象赋值
        put.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn),Bytes.toBytes(value));
        // 4.插入数据
        table.put(put);
        // 5.关闭表连接
        table.close();
    }

删除表中数据

/**
     * 8.删除数据
     */
    public static void deleteData(String tableName,String rowKey,String cf,String cn) throws IOException {
        // 1.获取表对象
        Table table = connection.getTable(TableName.valueOf(tableName));
        // 2.构建删除对象
        Delete delete = new Delete(Bytes.toBytes(rowKey));

        // 2.1设置删除的列
//        delete.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn));
//        delete.addColumns(Bytes.toBytes(cf),Bytes.toBytes(cn));
        // 2.2 删除指定的列族
        delete.addFamily(Bytes.toBytes(cf));
        // 3.执行删除操作
        table.delete(delete);

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

这里我们在删除时,可以指定删除的列或者列族,进而达到指定的列或者列族的目的。

查询API——get和scan

get

/**
 * 6.获取数据 (get)
 */
public static void getData(String tableName,String rowKey,String cf,String cn) throws IOException {
    // 1.获取表对象
    Table table = connection.getTable(TableName.valueOf(tableName));
    // 2.创建get对象
    Get get = new Get(Bytes.toBytes(rowKey));
    // 2.1指定获取的列族
    get.addFamily(Bytes.toBytes(cf));
    // 2.2指定列族和列
    get.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn));
    // 2.3设置获取数据的版本数
    get.setMaxVersions();
    // 3.获取数据
    Result result = table.get(get);
    // 4.解析result并打印
    for (Cell cell : result.rawCells()) {
        // 5.打印数据
        System.out.println("cf:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
                ",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
                ",Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
    }
    // 6.关闭表连接
    table.close();
}

get查询方法和scan查询方法的区别在于,get查询方法获得指定的值,而scan方法获得某一范围内的值。

scan

/**
 * 7.获取数据(scan)
 */
public static void scanTable(String tableName) throws IOException {
    // 1.获取表对象
    Table table = connection.getTable(TableName.valueOf(tableName));

    // 2.构建Scan对象 左闭右开
    Scan scan = new Scan(Bytes.toBytes("1001"),Bytes.toBytes("1003"));
    // 3.扫描表
    ResultScanner scanner = table.getScanner(scan);
    // 4.解析scanner
    for (Result result : scanner) {
        // 5.解析Result并打印
        for (Cell cell : result.rawCells()) {
            // 6.打印数据
            System.out.println("RoleKey:" + Bytes.toString(CellUtil.cloneRow(cell))+
                    ",cf:" + Bytes.toString(CellUtil.cloneFamily(cell)) +
                    ",CN:" + Bytes.toString(CellUtil.cloneQualifier(cell)) +
                    ",Value:" + Bytes.toString(CellUtil.cloneValue(cell)));
        }
    }
    // 7.关闭连接
    table.close();

}

进阶查询——过滤器和比较器

这里我通过一个案例来举例:

假设现在有这样一个需求:根据用户输入的对应字段来做一个多条件查询,例如目前要查询的字段有jgmc(机构名称),szdy(所在地域),jsxqmc(技术需求名称)。假设已经把数据存入Hbase(一个列族名为dcwjxx,字段名为对应列),如何使用Hbase实现该查询?

案例中的需求十分明确,我们要根据用户输入的各个字段来拼接查询条件。这种事用mysql十分容易实现,那么用hbase呢?还是先来看代码:

    public List<Dcwjxx> searchByCondition(String jgmc, String szdy,String jsxqmc) {
        // 根据条件是不是空来封装过滤器
        Scan scan = new Scan();
        // 按或条件查询
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE);
        if (!TextUtils.isEmpty(jgmc)) {
            SubstringComparator jgmcSubstringComparator = new SubstringComparator(jgmc);
            SingleColumnValueFilter jgmcFilter = new SingleColumnValueFilter(Bytes.toBytes("dcwjxx"),Bytes.toBytes(
                    "jgmc"), CompareFilter.CompareOp.EQUAL,jgmcSubstringComparator);
            filterList.addFilter(jgmcFilter);
        }
        if (!TextUtils.isEmpty(szdy)) {
            SubstringComparator szdySubstringCom = new SubstringComparator(szdy);
            SingleColumnValueFilter szdyFilter = new SingleColumnValueFilter(Bytes.toBytes("dcwjxx"),Bytes.toBytes(
                    "szdy"), CompareFilter.CompareOp.EQUAL,szdySubstringCom);
            filterList.addFilter(szdyFilter);
        }
        if (!TextUtils.isEmpty(jsxqmc)) {
            SubstringComparator jsxqmcSubstringCom = new SubstringComparator(jsxqmc);
            SingleColumnValueFilter jsxqmcFilter = new SingleColumnValueFilter(Bytes.toBytes("dcwjxx"),Bytes.toBytes(
                    "jsxqmc"), CompareFilter.CompareOp.EQUAL,jsxqmcSubstringCom);
            filterList.addFilter(jsxqmcFilter);
        }
        scan.setFilter(filterList);
        return (List<Dcwjxx>) getResult(scan);
    }

这里的getResult方法把返回的结果封装成了我们需要的对象,不需要在意这个方法,我们来看看如何用HBase的API拼接条件查询。

  • 首先我们要明确,我们这是一个多条件的过滤,且是或的关系。
  • 我们先定义一个FilterList对象,这个对象可以存储多个过滤器,这样我们就可以存储多个过滤条件了。这里传入一个或运算符
  • 之后,根据条件是否为空来拼接filter,这里我们使用了SubstringComparator比较器,这是Hbase自带的比较器中的一种,其作用在类名上写的十分明确了,即判断传入的字符串是不是要查询的字符串的子串。
  • 然后我们定义一个SingleColumnValueFilter过滤器,代表我们要对一个单元格数据进行处理,传入列族,列名和比较器运算符以及比较器,最后添加到filterList即可。
  • 这样一来,我们就实现了类似mysql中的where语句的查询了。

总结

总的来说,Hbase作为一个非关系型分布式数据库和mysql这类关系型数据库差别还是比较大的,操作起来也有诸多不适应。还是希望能多多理解。

上一篇:IBASE category 03 download


下一篇:IBASE category 设置为01的情况下 IBASE自动创建情况