项目实训第十二天

本文最后更新于:2021年7月23日 晚上


HBase

基本操作

注意问题

  1. HBase作为一个数据库,提供了基本的增删改查的能力,但是HBase基于HDFS来进行数据的存储,在HDFS“允许一次写入,多次读取,不允许修改,但是允许追加”的前提下,HBase是怎么实现改操作的?当在HBase中,对数据进行修改的时候,实际上并不是真正去改变HDFS中的数据而是在HDFS的文件后边来追加一条数据,当用户需要获取数据的时候,会从文件中来返回最新的数据,那么此时从用户角度就是将数据进行了修改 - HBase在每条数据之后都会追加一个时间戳用于标记数据的新旧问题,这个时间戳称之为数据的版本(VERSION)
  2. 在HBase中,需要通过行键+列族+列+时间戳/版本可以锁定唯一的一条数据,这种结构称之为是一个Cell(单元)
  3. 在HBase中,当表建好之后,这个表的版本数就不能改变了。默认情况下,如果不指定,每一个表只会保留1个版本的数据,同时需要注意,也只允许对外获取1个版本的数据 - 如果需要获取多个版本的数据,那么此时需要在建表的时候指定保留版本数,以及对外获取的时候需要指定获取的版本数量
  4. 在HBase中,删除表之前需要先禁用这个表
  5. 在HBase中,没有database的概念,取而代之的是namespace(名称空间),可以将表放到不同的名称空间下
  6. 在HBase启动的时候,会自带了两个namespace:default和hbase。在建表的时候如果不指定,那么表默认是放在default空间下的;hbase空间下放的是HBase本身的元数据

基本命令

命令 解释
disable ‘person’ 禁用表
drop ‘person’ 删除表
create ‘person’, {NAME => ‘basic’, VERSIONS => 4}, {NAME => ‘info’, VERSIONS => 5} 建立person表,包含2个列族,这2个列族各自保留对应版本数的数据
get ‘person’, ‘p1’, {COLUMN => ‘basic:age’, VERSIONS => 4} 获取指定列的多个版本的数据
scan ‘person’, {COLUMNS => ‘basic’, VERSIONS => 4} 获取指定列族的多版本数据
create_namespace ‘demo’ 创建名称空间
list_namespace 查看所有的名称空间
list_namespace_tables ‘default’ 查看指定空间下的表
create ‘demo:person’, {NAME => ‘basic’, VERSIONS => 5}, {NAME => ‘other’, VERSIONS => 3} 在指定空间下建表
put ‘demo:person’, ‘p1’, ‘basic:name’, ‘tom’ 向指定空间指定表中来添加数据
disable ‘demo:person’ 禁用指定空间下的指定表
drop ‘demo:person’ 删除指定空间下的指定表
drop_namespace ‘demo’ 删除指定空间,要求这个空间为空
count ‘person’ 统计这个表中的行键个数
get_splits ‘person’ 获取指定表中的HRegion的个数
truncate ‘person’ 摧毁重建表
alter ‘person’, {NAME => ‘basic’, VERSIONS => 5} 修改指定表的属性
describe ‘person’
或者
desc ‘person’
描述表信息
exists ‘person’ 判断表是否存在
is_disabled ‘person’ 判断表是否被禁用
is_enabled ‘person’ 判断表是否被启用
list_regions ‘person’ 列出指定表中的HRegion的信息
show_filters 列出所有的过滤器
list 获取所有空间下的所有的表
disable_all ‘demo:.*’ 禁用指定空间下的所有的表,在使用的时候需要给定正则表达式
drop_all ‘demo:.*’ 删除指定空间下的所有的表

API操作

  1. Namespache操作

    1. 发起连接

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      @Before
      public void connect() throws IOException {

      // 获取HBase的配置信息
      Configuration conf = HBaseConfiguration.create();
      // 指定Zookeeper的连接地址
      conf.set("hbase.zookeeper.quorum", "hadoop:2181,hadoop02:2181,hadoop03:2181");
      // 获取连接
      connection = ConnectionFactory.createConnection(conf);
      // 获取管理权
      admin = connection.getAdmin();

      }
    2. 创建名称空间

      1
      2
      3
      4
      5
      6
      7
      @Test
      public void createNamespace() throws IOException {
      // 构建一个NamespaceDescriptor - 空间描述器
      NamespaceDescriptor descriptor = NamespaceDescriptor.create("demo").build();
      // 创建名称空间
      admin.createNamespace(descriptor);
      }
    3. 查看所有的名称空间

      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Test
      public void listNamespaces() throws IOException {
      // 获取所有的名称空间
      String[] namespaces = admin.listNamespaces();
      // 遍历数组
      for (String namespace : namespaces) {
      System.out.println(namespace);
      }
      }
    4. 删除名称空间

      1
      2
      3
      4
      @Test
      public void dropNamespace() throws IOException {
      admin.deleteNamespace("demo");
      }
    5. 关闭连接

      1
      2
      3
      4
      5
      6
      7
      @After
      public void close() throws IOException {
      // 关闭管理权
      admin.close();
      // 关闭连接
      connection.close();
      }
  2. Table操作

    1. 发起连接

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      @Before
      public void connect() throws IOException {
      // 获取HBase的配置
      Configuration conf = HBaseConfiguration.create();
      // 设置Zookeeper的连接地址
      conf.set("hbase.zookeeper.quorum", "hadoop:2181,hadoop02:2181,hadoop03:2181");
      // 获取连接
      connection = ConnectionFactory.createConnection(conf);
      // 获取管理权
      admin = connection.getAdmin();
      // 指定表
      users = connection.getTable(TableName.valueOf("users"));
      }
    2. 建表

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      @Test
      public void createTable() throws IOException {
      // 构建列族描述器
      ColumnFamilyDescriptor cf1 = ColumnFamilyDescriptorBuilder
      .newBuilder("basic".getBytes(StandardCharsets.UTF_8)).build();
      ColumnFamilyDescriptor cf2 = ColumnFamilyDescriptorBuilder
      .newBuilder("info".getBytes(StandardCharsets.UTF_8)).build();
      // 构建TableDescriptor - 表描述器
      TableDescriptor table = TableDescriptorBuilder
      .newBuilder(TableName.valueOf("users"))
      .setColumnFamily(cf1).setColumnFamily(cf2).build();
      // 建表
      admin.createTable(table);
      }
    3. 添加/追加数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      @Test
      public void appendData() throws IOException {
      // 构建Append对象
      Append append = new Append("u1".getBytes(StandardCharsets.UTF_8));
      // 添加数据
      byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
      byte[] info = "info".getBytes(StandardCharsets.UTF_8);
      append.addColumn(basic, "name".getBytes(StandardCharsets.UTF_8), "David".getBytes(StandardCharsets.UTF_8));
      append.addColumn(basic, "age".getBytes(StandardCharsets.UTF_8), "19".getBytes(StandardCharsets.UTF_8));
      append.addColumn(basic, "gender".getBytes(StandardCharsets.UTF_8), "male".getBytes(StandardCharsets.UTF_8));
      append.addColumn(info, "height".getBytes(StandardCharsets.UTF_8), "185.5".getBytes(StandardCharsets.UTF_8));
      append.addColumn(info, "weight".getBytes(StandardCharsets.UTF_8), "70.5".getBytes(StandardCharsets.UTF_8));
      append.addColumn(info,"address".getBytes(StandardCharsets.UTF_8), "chongqing".getBytes(StandardCharsets.UTF_8));
      // 追加
      users.append(append);
      }
    4. 添加/修改数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      @Test
      public void putData() throws IOException {
      // 封装Put对象
      Put put = new Put("u2".getBytes(StandardCharsets.UTF_8));
      // 指定数据
      put.addColumn("basic".getBytes(StandardCharsets.UTF_8),
      "name".getBytes(StandardCharsets.UTF_8),
      "Evan".getBytes(StandardCharsets.UTF_8));
      // 修改/添加数据
      users.put(put);
      }
    5. 测试:添加百万条数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      @Test
      public void putMillionData() throws IOException {
      // 记录起始时间
      long begin = System.currentTimeMillis();
      // 构建集合,实现批量添加
      List<Put> list = new ArrayList<>();
      // 指定列族和列
      byte[] basic = "basic".getBytes(StandardCharsets.UTF_8);
      byte[] password = "password".getBytes(StandardCharsets.UTF_8);
      for (int i = 0; i < 1000000; i++) {
      // 构建Put对象
      Put put = new Put(("u" + i).getBytes(StandardCharsets.UTF_8));
      // 添加数据
      put.addColumn(basic, password, getPassword());
      // 将数据放入集合
      list.add(put);
      // 每1000条数据写出一次
      if (list.size() >= 1000) {
      users.put(list);
      // 清空集合
      list.clear();
      }
      }
      // 记录结束时间
      long end = System.currentTimeMillis();
      System.out.println(end - begin);
      }
      // 产生初始密码
      private byte[] getPassword() {
      StringBuilder sb = new StringBuilder();
      for (int i = 0; i < 6; i++) {
      char c = (char) (Math.random() * 26 + 65);
      sb.append(c);
      }
      return sb.toString().getBytes(StandardCharsets.UTF_8);
      }

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!