评论

收藏

[NoSQL] 分布式NoSQL列存储数据库Hbase Java API(三)

数据库 数据库 发布于:2021-07-01 09:53 | 阅读数:482 | 评论:0

  
  文章目录


  • 分布式NoSQL列存储数据库Hbase(三)


    • 知识点01:课程回顾
    • 知识点02:课程目标
    • 知识点03:Java API:DML:Table
    • 知识点04:Java API:DML:Put
    • 知识点05:Java API:DML:Get
    • 知识点06:Java API:DML:Delete
    • 知识点07:Java API:DML:Scan
    • 知识点08:Java API:DML:Filter
    • 知识点09:存储设计:存储架构
    • 知识点10:存储设计:Table、Region、RegionServer的关系
    • 知识点11:存储设计:Region的划分规则
    • 知识点12:存储设计:Region内部存储结构
    • 知识点13:存储设计:HDFS中的存储结构
    • 知识点11:存储设计:Region的划分规则
    • 知识点12:存储设计:Region内部存储结构
    • 知识点13:存储设计:HDFS中的存储结构



  分布式NoSQL列存储数据库Hbase(三)
知识点01:课程回顾

  •   Hbase使用场景

    •   集群管理:定时调度管理的脚本

      • 定时调度:Azkaban、Oozie、Linux Crontab
      • Hbase脚本

        • 将Hbase命令写入一个文件
        • hbase shell运行文件即可


    •   测试开发:Hbase命令

      •   DDL

        • list_namespace/create_namespace
        • create/list/desc

      •   DML

        •   put:插入、更新

          •   插入:每次是为每行插入一列
          •   更新:通过插入数据来代替了更新,用于提高性能
          •   语法
            put表rowkey列族:列值

        •   delete:删除数据

          • delete:删除列
          • deleteall:删除行
          • truncate:清空表

        •   get:获取某个rowkey的数据

          •   优点:查询数据最快的方式,根据rowkey进行查询

            • rowkey是Hbase中的唯一索引

          •   缺点

            • get最多返回一个rowkey的所有列

          •   语法
            get表名rowkey【列族:列】

        •   scan:查询符合条件的数据

          •   优点:返回需要的多条Hbase的数据
          •   缺点:很多情况下是不走索引【不能根据rowkey进行检索】
          •   语法
            scan 表名
            scan 表名 + Filter



    •   生产开发:JavaAPI

      •   Connection:连接对象

        • Configuration:配置管理对象

      •   HbaseAdmin:Hbase管理员对象:用于实现DDL操作



知识点02:课程目标

  •   Hbase JavaAPI实现DML操作【重点内容】

    • put:数据的写入或者更新
    • get:查询数据
    • delete:删除数据
    • scan:扫描数据
    • Filter:过滤器

  •   Hbase存储设计【掌握原理】

    •   表、RegionServer关系?
    •   表的分布式如何实现的?

      • Region的划分规则?
      • 数据如何决定进入哪个分区哪?

    •   分区内部是如何存储数据的?


知识点03:Java API:DML:Table


  •   需求:通过JavaAPI实现对Hbase的DML操作
  •   分析

    • step1:构建连接对象
    • step2:构建Table对象

      • 所有的DML操作,必须构建一个表的对象


  •   实现
    //todo:1-构建一个连接对象
    Configuration conf = HBaseConfiguration.create();
    //指定Hbase集群的服务端地址:给定ZK的地址
    conf.set("hbase.zookeeper.quorum","node1:2181,node2:2181,node3:2181");
    Connection conn = ConnectionFactory.createConnection(conf);
    //todo:2-所有的DML必须构建一个Table表的对象
    //构建一个表的对象
    TableName tbname = TableName.valueOf("itcast:t1");
    Table table = conn.getTable(tbname);
  •   总结

    • step1:先构建一个连接对象:Connection
    • step2:根据所做的操作决定构建哪种对象
    • DDL:HbaseAdmin

      • DML:Table



知识点04:Java API:DML:Put


  •   需求:JavaAPI实现往Hbase表中写入数据
    put表rowkey列族:列值
  •   分析

    • step1:Hbase中实现put操作,需要构建Put对象
    • step2:为Put对象添加列族、列名、值
    • step3:对表执行put操作

  •   实现
    /**
       * 用于实现使用Put插入数据到表中:put表rowkey列族:列值
       * @param table
       */
      private void putData(Table table) throws IOException {
        //step1:构建Put对象,必须指定插入的rowkey的数据
        Put put = new Put(Bytes.toBytes("20201001_888"));
        //step2:初始化put,添加列族、列、值
        put.addColumn(
            Bytes.toBytes("basic"),//指定列族
            Bytes.toBytes("name"),//指定列的名称
            Bytes.toBytes("laoba")//指定列的值
        );
        //step3:让表执行put操作
        table.put(put);   
      }
  •   总结
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a57OCTc7-1616631335573)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318084424081.png)]

    • Put对象:专门用于往Hbase写入数据的对象

      • 指定Rowkey,添加列族、列、值信息

    • table.put


知识点05:Java API:DML:Get


  •   需求:JavaAPI实现从Hbase表中读取某个Rowkey的数据
    get 表名rowkey【列族,列】
  •   分析

    •   step1:Hbase中实现get操作,需要构建Get对象
    •   step2:为Get对象添加列族、列名
    •   step3:对表执行get操作,获取返回值,打印输出
      table.get(Get)

  •   实现
    /**
       * 使用Get查询Hbase表中的数据:get 表名rowkey【列族,列】
       * @param table
       */
      private void getData(Table table) throws IOException {
        //step1:构建Get对象,必须指定Rowkey
        Get get = new Get(Bytes.toBytes("20201001_888"));
        //step2:可选的,配置Get需要的参数:列族、列
    //    get.addColumn()//指定获取某一列的数据
    //    get.addFamily()//指定获取某个列族的数据
        //step3:表执行get操作
        Result result = table.get(get);//Get操作的返回值为Result类型对象
        /**
         * 迭代输出Result对应的rowkey中的每一列的数据,一个Rowkey包含很多列,循环迭代输出每一列的数据
         *    Result:一个Result对象就是一个Rowkey的数据
         *    Cell:一个Cell代表一个rowkey中一列的数据
         *    一个Result对象中会包含多个Cell
         */
        for(Cell cell : result.rawCells()){
          //输出每一列Cell对象中的数据:20201001_888  column=basic:age, timestamp=1616029665232, value=20
          System.out.println(
              Bytes.toString(CellUtil.cloneRow(cell)) //获取这一列的rowkey,转换为字符串类型
              +"\t"+
              Bytes.toString(CellUtil.cloneFamily(cell)) //获取这一列的列族,转换为字符串类型
              +"\t"+
              Bytes.toString(CellUtil.cloneQualifier(cell)) //获取这一列的名称,转换为字符串类型
              +"\t"+
              Bytes.toString(CellUtil.cloneValue(cell)) //获取这一列的值,转换为字符串类型
              +"\t"+
              cell.getTimestamp() //获取时间戳
          );
        }
      }
  •   总结

    • step1:先构建Get
    • step2:执行Get,得到返回值
    • Result:一个Result就是一个Rowkey的数据,包含一个Cell数组

      • Cell:一个Cell就是一列的数据



知识点06:Java API:DML:Delete


  •   需求:JavaAPI实现从Hbase表删除某个Rowkey的某列的数据
  •   分析

    •   step1:Hbase中实现delete操作,需要构建Delete对象
    •   step2:为Delete对象添加列族、列名
    •   step3:对表执行delete操作
      table.delete(Delete)

  •   实现
    /**
       * 删除某个Rowkey的某一列的数据:delete  表名   rowkey    列族:列
       * @param table
       */
      private void deleteData(Table table) throws IOException {
        //step1:构建删除对象
        Delete delete = new Delete(Bytes.toBytes("20201001_888"));
        //step2:添加删除配置
    //    delete.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name")); //只删除最新版本
        delete.addColumns(Bytes.toBytes("basic"),Bytes.toBytes("name")); //删除所有版本
        //step3:执行删除
        table.delete(delete);
      }
  •   总结

    • step1:构建Delete对象
    • step2:根据需求调用配置方法:添加列族、列
    • step3:表对象指定delete对象即可


知识点07:Java API:DML:Scan


  •   需求:JavaAPI实现从Hbase表中读取所有数据
    scan 表
    scan 表 + filter
  •   分析

    • step1:Hbase中实现scan操作,需要构建Scan对象
    • step2:对表执行scan操作
    • step3:获取返回值,取出每个Rowkey的数据,打印输出

  •   实现
    /**
       * 通过Scan,进行Hbase表的数据查询:scan 表
       * @param table
       */
      private void scanData(Table table) throws IOException {
        //step1:构建Scan对象
        Scan scan = new Scan();
        //step2:执行scan:返回值是ResultScanner,包含了多个Rowkey的数据
        ResultScanner rsScan = table.getScanner(scan);
        /**
         *    ResultScanner:包含多个Rowkey的数据,包含了多个Result对象:Iterator<Result>
         *    Result:一个Rowkey的数据,包含了这个Rowkey多列的数据:Cell[]
         *    Cell :一列的数据
         */
        //step3:打印数据
        //先获取每个rowkey
        for(Result rs:rsScan){
          //直接输出当前rowkey的值
          System.out.println(Bytes.toString(rs.getRow()));
          //再获取每个rowkey中的每一列
          for(Cell cell : rs.rawCells()){
            //输出每一列Cell对象中的数据:20201001_888  column=basic:age, timestamp=1616029665232, value=20
            System.out.println(
                Bytes.toString(CellUtil.cloneRow(cell)) //获取这一列的rowkey,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneFamily(cell)) //获取这一列的列族,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneQualifier(cell)) //获取这一列的名称,转换为字符串类型
                    +"\t"+
                    Bytes.toString(CellUtil.cloneValue(cell)) //获取这一列的值,转换为字符串类型
                    +"\t"+
                    cell.getTimestamp() //获取时间戳
            );
          }
          System.out.println("----------------------------------------------------------------------");
        }
      }
  •   总结

    • step1:先构建Scan对象
    • step2:执行Scan操作
    • step3:返回值

      • ResultScanner:包含多个Rowkey的数据的集合

        • Iter《Result》

      • Result:一个Rowkey的数据

        • Cell[]

      • Cell:一列的数据



知识点08:Java API:DML:Filter


  •   需求:JavaAPI实现从Hbase表中根据条件读取部分

    • 需求1:查询2021年1月和2月的数据
    • 需求2:查询2021年的所有数据
    • 需求3:查询所有age = 20的数据
    • 需求4:查询所有数据的name和age这两列
    • 需求5:查询所有年age = 20的人的name和age

  •   分析

    •   Rowkey的设计:时间【年月日】+id

      • Rowkey整体有序
      • 前缀匹配

    •   需求1

      • StartRow = 》202101

        • 包含

      • StopRow = 》202103

        • 不包含


    •   需求2

      •   方案一:使用startrow = 2021,stoprow = 2022
      •   方案二:使用Filter:PrefixFilter,Rowkey的前缀过滤器
          [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MfZFeVn-1616631335575)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318103200422.png)]

        • 构建过滤器,指定Rowkey前缀
        • Scan加载过滤器,返回所有符合rowkey前缀的过滤器


    •   需求三:查询所有age = 20的数据
      where age = 20

      • Filter:列值过滤器

        • SingleColumnValueFilter:对某一列的值进行过滤

      • 指定列值过滤器:哪个列族下的哪一列的值等于什么值
      • scan加载过滤器

    •   需求4:查询所有数据的name和age这两列
      select name ,age from table

      • Filter:多列前缀过滤器

        • MutipleColumnPrefixFIlter:用于将每条数据中指定的列过滤出来

      • 指定需要过滤哪些列
      • scan加载过滤器即可

    •   需求5:查询所有年age = 20的人的name和age
      select name,age from table where age = 20

      • 支持组合过滤器:FilterList

        • 列的过滤:MutipleColumnPrefixFIlter
        • 列值过滤:SingleColumnValueFilter

      • 构建两个过滤器,将两个过滤器组合放入过滤器集合
      • Scan加载过滤器集合


  •   实现

    •   批量写入数据到Hbase
      /**
         * 批量写入数据到Hbase
         * @param table
         */
        private void putListData(Table table) throws IOException {
          //step1:构建Put对象,一个Put对象用于表示一个Rowkey写入的数据
          Put put1 = new Put(Bytes.toBytes("20210101_001"));
          Put put2 = new Put(Bytes.toBytes("20210201_002"));
          Put put3 = new Put(Bytes.toBytes("20210301_003"));
          //step2:为Put添加这个Rowkey的每一列
          put1.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laoda"));
          put1.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("18"));
          put1.addColumn(Bytes.toBytes("other"),Bytes.toBytes("phone"),Bytes.toBytes("110"));
          put1.addColumn(Bytes.toBytes("other"),Bytes.toBytes("addr"),Bytes.toBytes("shanghai"));
          put2.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laoer"));
          put2.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("20"));
          put2.addColumn(Bytes.toBytes("other"),Bytes.toBytes("phone"),Bytes.toBytes("120"));
          put3.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("name"),Bytes.toBytes("laosan"));
          put3.addColumn(Bytes.toBytes("basic"),Bytes.toBytes("age"),Bytes.toBytes("22"));
          put3.addColumn(Bytes.toBytes("other"),Bytes.toBytes("addr"),Bytes.toBytes("beijing"));
          //step3:将多个Put封装到List中
          List<Put> puts = new ArrayList<Put>();
          puts.add(put1);
          puts.add(put2);
          puts.add(put3);
          //step4:执行PutList
          table.put(puts);
        }
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ijNYbrbY-1616631335576)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318101928785.png)]
    •   需求一:实现范围过滤
      //需求一:查询2021年1月和2月的数据
      scan.withStartRow(Bytes.toBytes("202101"));
      scan.withStopRow(Bytes.toBytes("202103"));
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kUtwEsEy-1616631335577)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318102604990.png)]
    •   需求二实现
      //需求2:查询2021年的所有数据
      Filter prefixFiter = new PrefixFilter(Bytes.toBytes("2021"));
      //将过滤器加载到scan中
      scan.setFilter(prefixFiter);
    •   需求三实现
      //需求三:查询所有age = 20的数据
          /**
           *  * @param family name of column family
           *  * @param qualifier name of column qualifier
           *  * @param op operator
           *  * @param value value to compare column values against
           */
          Filter valueFilter = new SingleColumnValueFilter(
              Bytes.toBytes("basic"),//指定列族
              Bytes.toBytes("age"),//指定列
              CompareOperator.EQUAL,//指定比较器类型
              Bytes.toBytes("20")  //比较的值
          );
          //将过滤器加载到scan中
          scan.setFilter(valueFilter);
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sP5MLfRe-1616631335579)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318104213375.png)]
    •   需求四实现
      //需求4:查询所有数据的name和age这两列
          //构建所有需要过滤的列
          byte[][] prefixes = {
            Bytes.toBytes("name"),
            Bytes.toBytes("age")
          };
          Filter columnFilter = new MultipleColumnPrefixFilter(prefixes);
          //将过滤器加载到scan中
          scan.setFilter(columnFilter);
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkQbO9w9-1616631335580)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318104930496.png)]
    •   需求五实现
      Filter valueFilter = new SingleColumnValueFilter(
              Bytes.toBytes("basic"),//指定列族
              Bytes.toBytes("age"),//指定列
              CompareOperator.EQUAL,//指定比较器类型
              Bytes.toBytes("20")  //比较的值
          );
          //需求4:查询所有数据的name和age这两列
          //构建所有需要过滤的列
          byte[][] prefixes = {
            Bytes.toBytes("name"),
            Bytes.toBytes("age")
          };
          Filter columnFilter = new MultipleColumnPrefixFilter(prefixes);
          //需求5:查询所有age = 20的人的name和age
          //构建FIlterList
          FilterList lists = new FilterList();//MUST_PASS_ALL:and,MUST_PASS_ONE:or
          //添加过滤器
          lists.addFilter(valueFilter);
          lists.addFilter(columnFilter);
          //将过滤器加载到scan中
          scan.setFilter(lists);
        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GaXWQJwf-1616631335581)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210318110732471.png)]

  •   总结

    • Rowkey范围过滤:StartRow和StopRow
    • Rowkey前缀过滤:PrefixFilter
    • Rowkey中列的值的过滤:SingleColumnValueFilter
    • Rowkey中列的过滤:MultipleColumnPrefixFilter
    • 多种条件的组合过滤:FilterList


知识点09:存储设计:存储架构
  [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFiNIbeF-1616631335582)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317190105892.png)]

  •   问题:Hbase整体如何实现数据的存储?
  •   分析

知识点10:存储设计:Table、Region、RegionServer的关系


  •   问题:客户端操作的是表,数据最终存在RegionServer中,表和RegionServer的关系是什么?
  •   分析

知识点11:存储设计:Region的划分规则
  [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGxSZiF6-1616631335582)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191202582.png)]

  •   问题:一张表划分为多个Region,划分的规则是什么?写一条数据到表中,这条数据会写入哪个Region,分配规则是什么?
  •   分析

知识点12:存储设计:Region内部存储结构
  [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KRgBXSLA-1616631335583)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191716413.png)]

  •   问题:数据在Region的内部是如何存储的?
  •   分析

知识点13:存储设计:HDFS中的存储结构
  [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-10viiw3z-1616631335583)(20210318_分布式NoSQL列存储数据库Hbase(三).assets/image-20210317191754182.png)]

  •   问题:Hbase的数据在HDFS中是如何存储的?
  •   分析
  egionServer的关系


  •   问题:客户端操作的是表,数据最终存在RegionServer中,表和RegionServer的关系是什么?
  •   分析

知识点11:存储设计:Region的划分规则
  [外链图片转存中…(img-xGxSZiF6-1616631335582)]

  •   问题:一张表划分为多个Region,划分的规则是什么?写一条数据到表中,这条数据会写入哪个Region,分配规则是什么?
  •   分析

知识点12:存储设计:Region内部存储结构
  [外链图片转存中…(img-KRgBXSLA-1616631335583)]

  •   问题:数据在Region的内部是如何存储的?
  •   分析

知识点13:存储设计:HDFS中的存储结构
  [外链图片转存中…(img-10viiw3z-1616631335583)]

  •   问题:Hbase的数据在HDFS中是如何存储的?
  •   分析


  
关注下面的标签,发现更多相似文章