• 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这类关系型数据库差别还是比较大的,操作起来也有诸多不适应。还是希望能多多理解。

  • 相关阅读:
    [专题六] 位运算
    [专题五] 二叉树
    [专题四] 并查集
    [专题三] 图论
    [专题二] 排序
    [专题一] 栈和队列
    我的最新书单
    虚拟机极简配置manjaro gnome
    运算符重载
    Manjaro kde 18.0安装与基本配置
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/14007221.html
Copyright © 2020-2023  润新知