美文网首页
hbase java api 的使用

hbase java api 的使用

作者: 昨夜今夕 | 来源:发表于2018-06-02 00:02 被阅读0次

    [TOC]

    1 hbase java api的使用

    hbase的java api在windows中使用,第一次连接时,会有点慢,大概需要二十秒左右,连接上去就很快了,在linux没有这个问题

    1.1 初始化连接

    private Connection connection;
    private HTable table;
    HBaseAdmin admin;
     
    @Before
    public void init() throws IOException {
        Configuration configuration = HBaseConfiguration.create();
        //设置zookeeper的地址,可以有多个,以逗号分隔
        configuration.set("hbase.zookeeper.quorum","server1,server2");
        //设置zookeeper的端口
        configuration.set("hbase.zookeeper.property.clientPort","2181");
        //创建hbase的连接,这是一个分布式连接
        connection = ConnectionFactory.createConnection(configuration);
        //获取hbase中的表
        table = (HTable) connection.getTable(TableName.valueOf("user"));
     
        //这个admin是管理table时使用的,比如说创建表
        admin = (HBaseAdmin) connection.getAdmin();
    }
    

    1.2 创建表

    创建表只需要指定列族名就行了,不需要指定列名,列名可以动态添加

        /**
         * 创建表,创建表只需要指定列族,不需要指定列
         * 其实用命令真的会更快,create 'user','info1','info2'
         */
        @Test
        public void createTable() throws IOException {
            //声明一个表名
            TableName tableName = TableName.valueOf("user");
            //构造一个表的描述
            HTableDescriptor desc = new HTableDescriptor(tableName);
            //创建列族
            HColumnDescriptor family1 = new HColumnDescriptor("info1");
            HColumnDescriptor family2 = new HColumnDescriptor("info2");
            //添加列族
            desc.addFamily(family1);
            desc.addFamily(family2);
            //创建表
            admin.createTable(desc);
        }
    

    1.3 插入数据(修改数据)

    这里之所以还带了修改数据,是因为对于同一个key的指定列族中的列重新插入数据,就是修改数据

        /**
         * 添加数据
         * 对同一个row key进行重新put同一个cell就是修改数据
         */
        @Test
        public void insertUpdate() throws IOException {
            //构造参数是row key,必传
            Put put = new Put(Bytes.toBytes("zhangsan_123" + i));
            //put.add()已经被弃用了
            //这里的参数依次为,列族名,列名,值
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("name"),Bytes.toBytes("lisi" + i));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("age"),Bytes.toBytes(22 + i));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("sex"),Bytes.toBytes("男"));
            put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("address"),Bytes.toBytes("天堂" + i));
            table.put(put);
            //table.put(List<Put>); //通过一个List集合,可以添加一个集合
     
        }
    

    1.4 删除数据

    删除数据使用Delete对象就行了,我们可以删除一行,或者删除一个列族,或者删除一个列族中的指定列

        /**
         * 删除数据
         */
        @Test
        public void delete() throws IOException {
            Delete deleteRow = new Delete(Bytes.toBytes("zhangsan_1235")); //删除一个行
     
            Delete delete = new Delete(Bytes.toBytes("zhangsan_1235"));
            delete.addFamily(Bytes.toBytes("info1"));//删除该行的指定列族
            delete.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//删除指定的一个单元
     
     
            table.delete(deleteRow);
     
            //table.delete(List<Delete>); //通过添加一个list集合,可以删除多个
        }
    

    1.5 查询单条数据

        /**
         * 查询单条数据
         * @throws IOException
         */
        @Test
        public void queryByKey() throws IOException {
            String rowKey = "zhangsan_1235";
            Get get = new Get(Bytes.toBytes(rowKey));
            Result result = table.get(get);
            byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
            byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
            System.out.print(Bytes.toString(name) + ",");
            System.out.print(Bytes.toString(sex) + ",");
            System.out.print(Bytes.toString(address) + ",");
            System.out.print(Bytes.toInt(age) + ",");
            System.out.println();
        }
    

    1.6 全表扫描

    完整的全表扫描要慎用,不过全表扫描中可以指定很多过滤器,我们可以很好的使用它

        /**
         * 全表扫描
         */
        @Test
        public void scanData() throws IOException {
            Scan scan = new Scan();
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    我们看到上方扫描后得到一个ResultScanner,这是一个扫描结果,我们来看一下要如何使用它

        private void printResult(ResultScanner resultScanner) {
            for (Result result : resultScanner) {
                byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
                byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
                byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
                byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
                byte[] rowKey = result.getRow(); //获取rowKey
                System.out.print(Bytes.toString(rowKey) + ",");
                System.out.print(Bytes.toString(name) + ",");
                System.out.print(Bytes.toString(sex) + ",");
                System.out.print(Bytes.toString(address) + ",");
                System.out.print((age == null ? null : Bytes.toInt(age)) + ",");
                System.out.println();
            }
        }
    

    我们已经把这个打印结果的代码封装成为了一个方法了,我们接下来很多地方都会用到它

    1.7 区间扫描

    区间扫描我们用处也很多,因为row key是按照字典序来排列的,我们可以根据这个特性,查找某一个用户指定时间段的数据,比如查询用户A昨天到今天的数据

    在查询的过程中,我们还可以指定返回的结果,比如指定返回一个列族,以及返回指定的列,这样可以增加查询速度

        /**
         * 区间扫描
         */
        @Test
        public void areaScanData() throws IOException {
            Scan scan = new Scan();
            scan.withStartRow(Bytes.toBytes("zhangsan_1232")); //设置开始行
            scan.withStopRow(Bytes.toBytes("zhangsan_12352")); //设置结束行
            //scan.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//查询指定列
            scan.addFamily(Bytes.toBytes("info1"));//查询指定列族
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    1.8 列值过滤器

    列值过滤器也是我们很常用的操作,它提供了一种甚至值的条件查询。类似sql中的where field = 'xxx',这极大的扩展了hbase的查询方式,因为如果只是根据row key来查询,那么很多产景都不适用hbase

        /**
         * 全表扫描时加过滤器 --> 列值过滤器
         */
        @Test
        public void scanDataByFilter1() throws IOException {
            Scan scan = new Scan();
            /*
             * 第一个参数: 列族
             * 第二个参数: 列名
             * 第三个参数: 是一个枚举类型
             *              CompareOp.EQUAL  等于
             *              CompareOp.LESS  小于
             *              CompareOp.LESS_OR_EQUAL  小于或等于
             *              CompareOp.NOT_EQUAL  不等于
             *              CompareOp.GREATER_OR_EQUAL  大于或等于
             *              CompareOp.GREATER  大于
             */
            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.GREATER_OR_EQUAL, Bytes.toBytes("zhangsan8"));
        //这个方法很重要,需要注意,当此过滤器过滤时,如果遇到该列值为NULL的情况,如果设置的参数为true,则会过滤掉这一行,如果设置的参数为false,那么则会把这一行的结果返回,默认为false
        singleColumnValueFilter.setFilterIfMissing(true);
            scan.setFilter(singleColumnValueFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
     
        }
    

    由上面的代码可以看到,我们使用的的是SingleColumnValueFilter,它传入了四个参数,我们分别介绍一下

    • 第一个:列族
    • 第二个:列名
    • 第三个:是一个枚举类型,告诉列值匹配条件,类型如下
      • CompareOp.EQUAL 等于
      • CompareOp.LESS 小于
      • CompareOp.LESS_OR_EQUAL 小于或等于
      • CompareOp.NOT_EQUAL 不等于
      • CompareOp.GREATER_OR_EQUAL 大于或等于
      • CompareOp.GREATER 大于
    • 第四个:是匹配的值

    1.9 前缀过滤器

    前缀过滤器和表里面的内容没有关系,它只是用来匹配指定的列的,,比如有这样两个列 name1 和name2 ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,并且它会匹配到多个列族

     
        /**
         * 全表扫描时加过滤器 --> 前缀过滤器
         *
         * 这里的查询和单元内容没有关系,仅仅是匹配列名,比如有这样两个列 name1 和name2  ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,
         * 且并会匹配到其它列族的列名
         *
         */
        @Test
        public void scanDataByFilter2() throws IOException {
            ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("name"));
            Scan scan = new Scan();
            scan.setFilter(columnPrefixFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    1.10 多列值前缀过滤器

    好吧,这个过滤器和上面的前缀过滤器ColumnPrefixFilter差不多,区别就是可以匹配多个,其实作用并不大

        /**
         * 全表扫描时添加过滤器  --> 多个列值前缀过滤器
         *
         *  这个过滤器和 ColumnPrefixFilter 过滤器差不多,但是能匹配多个前缀
         */
     
        @Test
        public void scanDataFilter3() throws IOException {
            Scan scan = new Scan();
            byte[][] prefix = new byte[][]{Bytes.toBytes("name"),Bytes.toBytes("add")};
            MultipleColumnPrefixFilter multipleColumnPrefixFilter = new MultipleColumnPrefixFilter(prefix);
     
            scan.setFilter(multipleColumnPrefixFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    1.11 按row key正则表达式查找

    这个也是hbase查找中经常用到的功能

        /**
         * row key查找
         */
        @Test
        public void scanByRowKey() throws IOException {
            //查找以指定内容开头的
            Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
            Scan scan = new Scan();
            scan.setFilter(rowKeyFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    1.12 同时使用多个过滤器

    我们可能有这样的情况,我们想扫描指定row key范围的,又想指定address为深圳的,或者是更多的一些条件,我们要怎么做呢?我们需要组合一些过滤器

        /**
         * 使用多个过滤器,并合查找,可以同时设置多个过滤器
         *
         * 这里查找row key中,name列等于指定值的
         */
        @Test
        public void scanByFilterList() throws IOException {
            /*
            * 我们需要注意Operator这个参数,这是一个枚举类型,里面有两个类型
            *   Operator.MUST_PASS_ALL   需要通过全部的条件,也就是并且,and &&
            *   Operator.MUST_PASS_ONE   任何一个条件满足都可以,也就是或者,or ||
            */
            FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
     
            //row key正则表达式的过滤器
            Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
            //列值过滤器
            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL, Bytes.toBytes("zhangsan9"));
     
     
            //把两个filter添加进filterList中
            filterList.addFilter(rowKeyFilter);
            filterList.addFilter(singleColumnValueFilter);
     
     
            Scan scan = new Scan();
            scan.setFilter(filterList);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
    

    我们可以通过FilterList来添加多个过滤器,然后把这个对象设置进去,我们看下这个对象的构造方法,Operator也是一个枚举类型,类型如下

    • Operator.MUST_PASS_ALL 需要通过全部的条件,也就是并且,and &&
    • Operator.MUST_PASS_ONE 任何一个条件满足都可以,也就是或者,or ||

    1.13 完整代码

    之前所有代码的java类如下

    package com.xiaojiezhu.hbase.demo;
     
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.*;
    import org.apache.hadoop.hbase.client.*;
    import org.apache.hadoop.hbase.filter.*;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.junit.Before;
    import org.junit.Test;
     
    import java.io.IOException;
    import java.util.List;
     
    /**
    * @author xiaojie.zhu
    */
    public class HbaseTest {
        private Connection connection;
        private HTable table;
        HBaseAdmin admin;
        @Before
        public void init() throws IOException {
            Configuration configuration = HBaseConfiguration.create();
            //设置zookeeper的地址,可以有多个,以逗号分隔
            configuration.set("hbase.zookeeper.quorum","dockerServer");
            //设置zookeeper的端口
            configuration.set("hbase.zookeeper.property.clientPort","2181");
            //创建hbase的连接,这是一个分布式连接
            connection = ConnectionFactory.createConnection(configuration);
            //获取hbase中的表
            table = (HTable) connection.getTable(TableName.valueOf("user"));
     
            //这个admin是管理table时使用的,比如说创建表
            admin = (HBaseAdmin) connection.getAdmin();
        }
     
        /**
         * 创建表,创建表只需要指定列族,不需要指定列
         * 其实用命令真的会更快,create 'user','info1','info2'
         */
        @Test
        public void createTable() throws IOException {
            //声明一个表名
            TableName tableName = TableName.valueOf("user");
            //构造一个表的描述
            HTableDescriptor desc = new HTableDescriptor(tableName);
            //创建列族
            HColumnDescriptor family1 = new HColumnDescriptor("info1");
            HColumnDescriptor family2 = new HColumnDescriptor("info2");
            //添加列族
            desc.addFamily(family1);
            desc.addFamily(family2);
            //创建表
            admin.createTable(desc);
        }
     
     
        /**
         * 添加数据
         * 对同一个row key进行重新put同一个cell就是修改数据
         */
        @Test
        public void insertUpdate() throws IOException {
            //构造参数是row key,必传
            for(int i = 0 ; i < 100 ; i ++){
                Put put = new Put(Bytes.toBytes("zhangsan_123" + i));
                //put.add()已经被弃用了
                //这里的参数依次为,列族名,列名,值
                put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("name"),Bytes.toBytes("lisi" + i));
                put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("age"),Bytes.toBytes(22 + i));
                put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("sex"),Bytes.toBytes("男"));
                put.addColumn(Bytes.toBytes("info2"),Bytes.toBytes("address"),Bytes.toBytes("天堂" + i));
                table.put(put);
                //table.put(List<Put>); //通过一个List集合,可以添加一个集合
            }
     
        }
     
        /**
         * 删除数据
         */
        @Test
        public void delete() throws IOException {
            Delete deleteRow = new Delete(Bytes.toBytes("zhangsan_1235")); //删除一个行
     
            Delete delete = new Delete(Bytes.toBytes("zhangsan_1235"));
            delete.addFamily(Bytes.toBytes("info1"));//删除该行的指定列族
            delete.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//删除指定的一个单元
     
     
            table.delete(deleteRow);
     
            //table.delete(List<Delete>); //通过添加一个list集合,可以删除多个
        }
     
     
        /**
         * 查询单条数据
         * @throws IOException
         */
        @Test
        public void queryByKey() throws IOException {
            String rowKey = "zhangsan_1235";
            Get get = new Get(Bytes.toBytes(rowKey));
            Result result = table.get(get);
            byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
            byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
            byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
            byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
            System.out.print(Bytes.toString(name) + ",");
            System.out.print(Bytes.toString(sex) + ",");
            System.out.print(Bytes.toString(address) + ",");
            System.out.print(Bytes.toInt(age) + ",");
            System.out.println();
        }
     
        /**
         * 全表扫描
         */
        @Test
        public void scanData() throws IOException {
            Scan scan = new Scan();
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
     
        /**
         * 区间扫描
         */
        @Test
        public void areaScanData() throws IOException {
            Scan scan = new Scan();
            scan.withStartRow(Bytes.toBytes("zhangsan_1232")); //设置开始行
            scan.withStopRow(Bytes.toBytes("zhangsan_12352")); //设置结束行
            //scan.addColumn(Bytes.toBytes("info1"),Bytes.toBytes("name"));//查询指定列
            scan.addFamily(Bytes.toBytes("info1"));//查询指定列族
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
     
        /**
         * 全表扫描时加过滤器 --> 列值过滤器
         */
        @Test
        public void scanDataByFilter1() throws IOException {
            Scan scan = new Scan();
            /*
             * 第一个参数: 列族
             * 第二个参数: 列名
             * 第三个参数: 是一个枚举类型
             *              CompareOp.EQUAL  等于
             *              CompareOp.LESS  小于
             *              CompareOp.LESS_OR_EQUAL  小于或等于
             *              CompareOp.NOT_EQUAL  不等于
             *              CompareOp.GREATER_OR_EQUAL  大于或等于
             *              CompareOp.GREATER  大于
             */
            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.GREATER_OR_EQUAL, Bytes.toBytes("zhangsan8"));
            scan.setFilter(singleColumnValueFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
     
        }
     
     
        /**
         * 全表扫描时加过滤器 --> 前缀过滤器
         *
         * 这里的查询和单元内容没有关系,仅仅是匹配列名,比如有这样两个列 name1 和name2  ,通过这个过滤器,就会查询这两个列的所有数据,当然,其实这个方式和scan.addColumn差不多,
         * 且并会匹配到其它列族的列名
         *
         */
        @Test
        public void scanDataByFilter2() throws IOException {
            ColumnPrefixFilter columnPrefixFilter = new ColumnPrefixFilter(Bytes.toBytes("name"));
            Scan scan = new Scan();
            scan.setFilter(columnPrefixFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
        /**
         * 全表扫描时添加过滤器  --> 多个列值前缀过滤器
         *
         *  这个过滤器和 ColumnPrefixFilter 过滤器差不多,但是能匹配多个前缀
         */
     
        @Test
        public void scanDataFilter3() throws IOException {
            Scan scan = new Scan();
            byte[][] prefix = new byte[][]{Bytes.toBytes("name"),Bytes.toBytes("add")};
            MultipleColumnPrefixFilter multipleColumnPrefixFilter = new MultipleColumnPrefixFilter(prefix);
     
            scan.setFilter(multipleColumnPrefixFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
     
        /**
         * row key查找
         */
        @Test
        public void scanByRowKey() throws IOException {
            //查找以指定内容开头的
            Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
            Scan scan = new Scan();
            scan.setFilter(rowKeyFilter);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
     
        /**
         * 使用多个过滤器,并合查找,可以同时设置多个过滤器
         *
         * 这里查找row key中,name列等于指定值的
         */
        @Test
        public void scanByFilterList() throws IOException {
            /*
            * 我们需要注意Operator这个参数,这是一个枚举类型,里面有两个类型
            *   Operator.MUST_PASS_ALL   需要通过全部的条件,也就是并且,and &&
            *   Operator.MUST_PASS_ONE   任何一个条件满足都可以,也就是或者,or ||
            */
            FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
     
            //row key正则表达式的过滤器
            Filter rowKeyFilter = new RowFilter(CompareFilter.CompareOp.EQUAL, new RegexStringComparator("^zhangsan_1239"));
            //列值过滤器
            SingleColumnValueFilter singleColumnValueFilter = new SingleColumnValueFilter(Bytes.toBytes("info1"), Bytes.toBytes("name"), CompareFilter.CompareOp.EQUAL, Bytes.toBytes("zhangsan9"));
     
     
            //把两个filter添加进filterList中
            filterList.addFilter(rowKeyFilter);
            filterList.addFilter(singleColumnValueFilter);
     
     
            Scan scan = new Scan();
            scan.setFilter(filterList);
     
            ResultScanner resultScanner = table.getScanner(scan);
            printResult(resultScanner);
        }
     
     
        private void printResult(ResultScanner resultScanner) {
            for (Result result : resultScanner) {
                byte[] address = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("address")); //读取单条记录
                byte[] name = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("name")); //读取单条记录
                byte[] sex = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("sex")); //读取单条记录
                byte[] age = result.getValue(Bytes.toBytes("info1"), Bytes.toBytes("age")); //读取单条记录
                byte[] rowKey = result.getRow(); //获取rowKey
                System.out.print(Bytes.toString(rowKey) + ",");
                System.out.print(Bytes.toString(name) + ",");
                System.out.print(Bytes.toString(sex) + ",");
                System.out.print(Bytes.toString(address) + ",");
                System.out.print((age == null ? null : Bytes.toInt(age)) + ",");
                System.out.println();
            }
        }
    }
     
    

    相关文章

      网友评论

          本文标题:hbase java api 的使用

          本文链接:https://www.haomeiwen.com/subject/fpslsftx.html