Hbase的JavaAPI

一、java操作Hbase步骤

java操作Hbase步骤:

  • 1、添加依赖
  • 2、获取HbaseConfiguration对象
  • 3、设置zookeeper地址
  • 4、获取连接对象
  • 5、获取操作对象
  • 6、操作
  • 7、释放资源

二、添加依赖

<!--若要使用org.apache.hadoop.hbase.client的API,需要加上:-->
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-client</artifactId>
      <version>2.2.5</version>
    </dependency>
<!--若要使用org.apache.hadoop.hbase.mapreduce的API,需要加上:-->
    <dependency>
      <groupId>org.apache.hbase</groupId>
      <artifactId>hbase-server</artifactId>
      <version>2.2.5</version>
    </dependency>

三、获取连接

public static void main(String[] args) throws Exception {
	//获取HBaseConfiguration对象
    Configuration conf = HBaseConfiguration.create();
    // 设置zk的地址
    conf.set("hbase.zookeeper.quorum" , "linux1:2181,linux2:2181,linux3:2181");
    // 获取连接对象
    Connection conn = ConnectionFactory.createConnection(conf);
    // DDL tools 运维 管理员对象
    Admin admin = conn.getAdmin();
    // 列出系统中所有的表
    TableName[] tableNames = admin.listTableNames();
    for (TableName tableName : tableNames) {
        String name = tableName.getNameAsString();
        System.out.println("当前系统中的表有: "+ name);
    }
    // 操作数据  [表]
   // conn.getTable()
    //释放资源
    admin.close();
    conn.close();
}

核心操作对象有两个:

  • Admin
    conn.getAdmin()获取
    操作命名空间、建表、删除表、查看表列表 … split flush等
  • Table
    conn.getTable()获取
    操作和数据相关的,DML一些命令

四、新增、删除命名空间

public static void main(String[] args) throws Exception {
    //获取Hbase的配置文件对象
    Configuration conf = HBaseConfiguration.create();
    //配置zk集群地址
    conf.set("hbase.zookeeper.quorum", "doit01:2181,doit02:2181,doit03:2181");
    //获取连接对象
    Connection conn = ConnectionFactory.createConnection(conf);
    //获取Admin对象用来操作表
    Admin admin = conn.getAdmin();
	//获取命名空间
	//admin.getNamespaceDescriptor(namespace);
    
    //创建命名空间构造器
    Builder test_java = NamespaceDescriptor.create("test_java");
    //设置命名空间属性
    test_java.addConfiguration("VERSION", "2");
    //构建命名空间描述器
    NamespaceDescriptor build3 = test_java.build();
    //创建命名空间
    admin.createNamespace(build3);
    
    // 删除名称空间
    // admin.deleteNamespace("test_java");
    
    //释放资源
    admin.close();
    conn.close();
}

创建步骤:

  • 创建命名空间构造器
  • 用命名空间构造器设置命名空间属性
  • 用命名空间构造器构造命名空间描述器
  • 用命名空间描述器创建命名空间

删除步骤:

  • admin.deleteNamespace(“命名空间名”)

注意:命名空间创建构建器的方法与表、列族创建构造器方法有所不同

五、新增表

public static void main(String[] args) throws Exception {
    //获取Hbase的配置文件对象
    Configuration conf = HBaseConfiguration.create();
    //配置zk集群地址
    conf.set("hbase.zookeeper.quorum", "doit01:2181,doit02:2181,doit03:2181");
    //获取连接对象
    Connection conn = ConnectionFactory.createConnection(conf);
    //获取Admin对象用来操作表
    Admin admin = conn.getAdmin();
    
     //创建表的构建器
    TableDescriptorBuilder table_java = TableDescriptorBuilder
        .newBuilder(TableName.valueOf("test_java:table_java"));

    //创建列族构建器
    ColumnFamilyDescriptorBuilder info = ColumnFamilyDescriptorBuilder
        .newBuilder("info".getBytes());
    ColumnFamilyDescriptorBuilder other = ColumnFamilyDescriptorBuilder
        .newBuilder("other".getBytes());

    //设置列族属性 最大版本
    info.setMaxVersions(4);
    
    //构建列族描述器
    ColumnFamilyDescriptor build = info.build();
    ColumnFamilyDescriptor build1 = other.build();

    //往表的构建器中加列族描述器
    List<ColumnFamilyDescriptor> bulids = Arrays.asList(build, build1);
    
    //往表的构建器中设置列族
    table_java.setColumnFamilies(bulids);
    
    //构建表描述器
    TableDescriptor table = table_java.build();

    //设置预分区,会被分为[0,5),[5,10),[10,10之后的所有数据)三个分区
    byte[][] bytes = new byte[][]{"5".getBytes(), "10".getBytes()};

    //创建表
    admin.createTable(table, bytes);
    
    //释放资源
    admin.close();
    conn.close();
}

步骤:

  • 创建表构建器
  • 创建列族构建器
  • 用列族构建器设置列族属性
  • 用列族构建器构建列族描述器
  • 将列族描述器添加到表构建器
  • 用表构建器构建表描述器
  • 用表描述器去创建表,在此之前可以设置表的预分区

注意:设置表的预分区的属性是个byte的二维数组,因为设置表的预分区需要指定每个分区的起始row_key,而row_key在存储时本身就是一个byte数组。

设置表的预分区可以防止大量请求涌入一台服务器

创建表时,至少要有一个列族

五、修改表

public static void main(String[] args) throws IOException {
  //获取Hbase的配置文件对象
  Configuration conf = HBaseConfiguration.create();
  //配置zk集群地址
  conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
  //获取连接对象
  Connection coon = ConnectionFactory.createConnection(conf);

  //获取admin对象操作表
  Admin admin = coon.getAdmin();

  //添加列族
  //创建列族构造器
//    ColumnFamilyDescriptorBuilder builder = ColumnFamilyDescriptorBuilder
//        .newBuilder("cf1".getBytes());
//    ColumnFamilyDescriptorBuilder builder1 = ColumnFamilyDescriptorBuilder
//        .newBuilder("cf2".getBytes());
//    //添加列族属性
//    builder.setMaxVersions(3);
//    //构建列族
//    ColumnFamilyDescriptor cf1 = builder.build();
//    ColumnFamilyDescriptor cf2 = builder1.build();
//    //admin添加列族
//    admin.addColumnFamily(TableName.valueOf("test_java:table_java"),cf1);
//    admin.addColumnFamily(TableName.valueOf("test_java:table_java"),cf2);


  //修改列族
  //创建列族构造器
  ColumnFamilyDescriptorBuilder builder3 = ColumnFamilyDescriptorBuilder
      .newBuilder("cf2".getBytes());
  //添加列族属性
  builder3.setMaxVersions(3);
  //构建列族
  ColumnFamilyDescriptor cf3 = builder3.build();
  //admin修改列族
  admin.modifyColumnFamily(TableName.valueOf("test_java:table_java"),cf3);

  //删除列族
  //admin.deleteColumnFamily(TableName.valueOf("test_java:table_java"),"cf1".getBytes());

  admin.close();
  coon.close();

  }
  • 添加列族:admin.addColumnFamily(TableName.valueOf(“test_java:table_java”),cf2);
  • 修改列族:admin.modifyColumnFamily(TableName.valueOf(“test_java:table_java”),cf3);
    修改列族时列族不存在会报错
  • 删除列族:admin.deleteColumnFamily(TableName.valueOf(“test_java:table_java”),“cf1”.getBytes());

六、删除表

public static void main(String[] args) throws Exception{
 	//自己写了个Util类将前面获取连接的代码封装了起来
    Admin admin = HbaseUtil.getAdmin();
    // 获取表对象
    TableName a = TableName.valueOf("a");
    //判断表是否存在
    if(admin.tableExists(a)){
        // 禁用表
        admin.disableTable(a);
        // 判断表是否被禁用
        if(admin.isTableDisabled(a)){
        	//是的话删除表
            admin.deleteTable(a);
        }else{
        	//不是的话禁用表
            admin.disableTable(a);
            if(admin.isTableDisabled(a)){
                admin.deleteTable(a);
            }
        }
    }else{
        System.out.println("脑子有病 ,没有这张表");
    }
    //释放资源 
    admin.close();
}

删除表之前需要先禁用表

七、DML操作

1、增加一行或多行数据

public static void main(String[] args) throws IOException {
  //获取配置文件对象
  Configuration conf = HBaseConfiguration.create();
  //连接zooleeper
  conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
  //获取连接
  Connection conn = ConnectionFactory.createConnection(conf);

  //获取表对象
  Table table = conn.getTable(TableName.valueOf("test_java:table_java"));

  //增加数据
  //获取put对象,指定要增加数据的行
  Put put1 = new Put("rk1003".getBytes());
  //在put对象中增加单元格数据,指定该单元格数据的列族、列名、值
  put1.addColumn("base_info".getBytes() , "name".getBytes() , "xxxliu".getBytes()) ;
  put1.addColumn("base_info".getBytes() , "age".getBytes() , "1".getBytes()) ;
  put1.addColumn("base_info".getBytes() , "gender".getBytes() , "M".getBytes()) ;

  Put put2 = new Put("rk1004".getBytes());
  put2.addColumn("base_info".getBytes() , "name".getBytes() , "xxxxliu".getBytes()) ;
  put2.addColumn("base_info".getBytes() , "age".getBytes() , "1".getBytes()) ;
  put2.addColumn("base_info".getBytes() , "gender".getBytes() , "F".getBytes()) ;
  //添加多行
  table.put(Arrays.asList(put1 , put2));

  //释放资源
  table.close();
  conn.close();
}

2、删除一行或多行或一个单元格或多个单元格

public static void main(String[] args) throws IOException {
  //获取配置文件对象
  Configuration conf = HBaseConfiguration.create();
  //连接zooleeper
  conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
  //获取连接
  Connection conn = ConnectionFactory.createConnection(conf);

  //获取表对象
  Table table = conn.getTable(TableName.valueOf("test_java:table_java"));

  //删除数据
  //获取delete对象,指定要删除数据的行
  Delete delete = new Delete("002".getBytes());
  //在delete对象中增加要删除的单元格,指定该单元格的列族、列名
  delete.addColumn("info".getBytes(),"name".getBytes());
  delete.addColumn("other".getBytes(),"age".getBytes());
  Delete delete1 = new Delete("001".getBytes());
  delete1.addColumn("other".getBytes(),"age".getBytes());
  //不增加要删除的单元格,则会一整行都被删除
  Delete delete2 = new Delete("001".getBytes());
  table.delete(Arrays.asList(delete , delete1 , delete2 ));

  //释放资源
  table.close();
  conn.close();
}

3、获取一行或多行数据或一行的列族或单元格

public static void main(String[] args) throws IOException {
  //获取配置文件对象
  Configuration conf = HBaseConfiguration.create();
  //连接zooleeper
  conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
  //获取连接
  Connection conn = ConnectionFactory.createConnection(conf);

  //获取表对象  库名:表名
  Table table = conn.getTable(TableName.valueOf("test_java:table_java"));

  //获取查询对象,获取指定行的数据(整行数据,多个单元格)
  Get get = new Get("001".getBytes());
  
  //添加查询条件,指定该行的某个列族
  //get.addFamily("info".getBytes());
  //添加查询条件,指定该行的某个单元格  列族、列名
  //get.addColumn(Bytes.toBytes(family),Bytes.toBytes(qualifier));

  //获取多行  传个list,list里面多个get对象
  //Result[] results = table.get(Arrays.asList(get, get1));
  
  //获取一行
  Result result = table.get(get);
  //判断是否有下一个单元格数据
  while(result.advance()){
  	//获取单元格
    Cell cell = result.current();
    //获取该单元格的行键
    byte[] bytes = CellUtil.cloneRow(cell);
    //获取该单元格的列族
    byte[] bytes0 = CellUtil.cloneFamily(cell);
    //获取该单元格的列名
    byte[] bytes1 = CellUtil.cloneQualifier(cell);
    //获取该单元格的值
    byte[] bytes2 = CellUtil.cloneValue(cell);
    //注意这里是new String(bytes)
    //bytes.toString和String.valueOf(bytes)得到的是个对象
    System.out.println(new String(bytes)+"---"+
        new String(bytes0)+"---"+
        new String(bytes1)+"---"+
        new String(bytes2)+"---");
  }
  
  //释放资源
  table.close();
  conn.close();
}

4、获取整张表数据

public static void main(String[] args) throws IOException {
  //获取配置文件对象
  Configuration conf = HBaseConfiguration.create();
  //连接zooleeper
  conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
  //获取连接
  Connection conn = ConnectionFactory.createConnection(conf);

  //获取表对象
  Table table = conn.getTable(TableName.valueOf("test_java:table_java"));

   Scan scan = new Scan();
   
   //设置数据的起始行,也可不设置
   scan.withStartRow(Bytes.toBytes("rk1001")) ;
   
   // 设置数据展示的行数,也可不设置
   scan.setLimit(2) ;
   
   //获取到多行数据
   ResultScanner scanner = table.getScanner(scan);

   //获取行迭代器
   Iterator<Result> iterator = scanner.iterator();
   // 遍历每行
   while(iterator.hasNext()){
      // 获取当前行
      Result result = iterator.next();
      //之后的操作与之前过去一行数据的操作一致
      // 获取行内的单元格数据
      while(result.advance()){
		//获取单元格
		Cell cell = result.current();
		//获取该单元格的行键
		byte[] bytes = CellUtil.cloneRow(cell);
		//获取该单元格的列族
		byte[] bytes0 = CellUtil.cloneFamily(cell);
		//获取该单元格的列名
		byte[] bytes1 = CellUtil.cloneQualifier(cell);
		//获取该单元格的值
		byte[] bytes2 = CellUtil.cloneValue(cell);
		//注意这里是new String(bytes)
		//bytes.toString和String.valueOf(bytes)得到的是个对象
		System.out.println(new String(bytes)+"---"+
		    new String(bytes0)+"---"+
		    new String(bytes1)+"---"+
		    new String(bytes2)+"---");
		}

   }
  
  //释放资源
  table.close();
  conn.close();
}

5、利用缓存批量写入

public static void main(String[] args) throws Exception {
    //获取配置文件对象
    Configuration conf = HBaseConfiguration.create();
    //连接zooleeper
    conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
    //获取连接
    Connection conn = ConnectionFactory.createConnection(conf);
    
    // 批次操作对象
    BufferedMutator mutator = conn.getBufferedMutator(TableName.valueOf("tb_stu"));
    // 读取文本数据  导入到hbase中
    BufferedReader br = new BufferedReader(new FileReader("d://user.txt"));
    
    String line = null ;
    List<Mutation> ls = new ArrayList<>() ;
    while((line = br.readLine())!=null){
        //u002,lss,22,F
        String[] spls = line.split(",");
        Put put = new Put(spls[0].getBytes());
        put.addColumn("cf".getBytes() , "name".getBytes() , spls[1].getBytes());
        put.addColumn("cf".getBytes() , "age".getBytes() , spls[2].getBytes());
        put.addColumn("cf".getBytes() , "gender".getBytes() , spls[3].getBytes());
        ls.add(put) ;
    }
    
	//读到内存缓冲
    mutator.mutate(ls);
	//刷写到磁盘
    mutator.flush();

   //关闭资源
   br.close(); 
   mutator.close();
   conn.close(); 
}

mutator.flush()和mutator.close()都可以实现刷写到磁盘,只不过一个主动一个被动。
mutator.setWriteBufferPeriodicFlush 隔一段时间刷

6、使用importTsv工具上传数据

Importtsv是hbase自带的一个 csv文件(逗号分隔值文件格式)转HFile文件(Hbase存储文件格式)的工具,它能将csv文件转成HFile文件,并发送给regionserver

它的本质,是内置的一个将csv文件转成hfile文件的mr程序!

ImportTsv命令的参数说明如下:

-Dimporttsv.skip.bad.lines=false - 若遇到无效行则失败
-Dimporttsv.separator=, - 使用特定分隔符,默认是tab也就是\t
-Dimporttsv.timestamp=currentTimeAsLong - 使用导入时的时间戳
-Dimporttsv.mapper.class=my.Mapper - 使用用户自定义Mapper类替换TsvImporterMapper
-Dmapreduce.job.name=jobName - 对导入使用特定mapreduce作业名
-Dcreate.table=no - 避免创建表,注:如设为为no,目标表必须存在于HBase中
-Dno.strict=true - 忽略HBase表列族检查。默认为false
-Dimporttsv.bulk.output=/user/yarn/output 作业的输出目录

两条命令:

  • CSV文件转HFILE文件,需要先将CSV文件传到HDFS中
 hbase org.apache.hadoop.hbase.mapreduce.ImportTsv  -Dimporttsv.separator=, -Dimporttsv.columns='HBASE_ROW_KEY,info:name,info:age,other:gender'  -Dimporttsv.bulk.output=/stu/output  test:tb_stu /stu/input/user.txt

-Dimporttsv.separator=, 指定分隔符为逗号
-Dimporttsv.columns=‘HBASE_ROW_KEY,info:name,info:age,other:gender’ 分割出来的字段对应为表中字段,info、other为列族名
-Dimporttsv.bulk.output=/stu/output 输出目录
test:tb_stu 要对应的表,会自动创建,也可自己手动创建
/stu/input/user.txt 输入目录,即CSV文件所在目录

  • HFile注入Hbase表中
 hbase org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles /stu/output/  test:tb_stu

/stu/output/ HFILE文件所在目录
test:tb_stu 要转换的表

八、行键设计与二级索引

行键和查询维度

排序、region定位、布隆过滤器、块索引定位都需用到行键,所以,对于一些经常性的查询维度一定要在行键上体现,以加快查询效率

rowkey设计原则

  • 将最高频度的查询维度设计在rowkey上(方便查询)
  • 定长(方便排序)
  • 唯一性(防止数据覆盖)
  • 不要太长(影响存储效率)

二级索引
HBase本身只提供基于行键和全表扫描的查询,而行键索引单一,对于多维度的查询困难(如:对于价格+天数+酒店+交通的多条件组合查询困难),全表扫描效率低下。此时就需要建立二级索引。
二级索引的本质就是建立各列值与行键之间的映射关系
在这里插入图片描述
二级索引设计思路
如图,当要对F:C1这列建立索引时,只需要建立F:C1各列值到其对应行键的映射关系,如C11->RK1等,这样就完成了对F:C1列值的二级索引的构建,当要查询符合F:C1=C11对应的F:C2的列值时(即根据C1=C11来查询C2的值,图1青色部分)

其查询步骤如下:

  1. 根据C1=C11到索引数据中查找其对应的RK,查询得到其对应的RK=RK1

  2. 得到RK1后就自然能根据RK1来查询C2的值了 这是构建二级索引大概思路,其他组合查询的联合索引的建立也类似。

九、MR整合Hbase

Hbase为mapreduce开发了TableInputFormat和TableOutputFormat,因此,在mapreduce程序中访问hbase数据是很轻松的。

1、读取普通文件中的数据存储到hbase表中

public class MapReduce {

  static class MovieMapper extends Mapper<LongWritable, Text, Text, MovieBean> {

    Text k = new Text();

    @Override
    protected void map(LongWritable key, Text value, Context context)
        throws IOException, InterruptedException {
      String line = value.toString();
      //将读取到的数据转化为bean
      MovieBean movieBean = JSON.parseObject(line, MovieBean.class);
      /*
       *  设计行键,使用定长movieid与定长时间戳组合作为rowkey
       */
      String movie = movieBean.getMovie();//1   2340
      String timeStamp = movieBean.getTimeStamp();
      String mid = StringUtils.leftPad(movie, 5, '0');
      String ts = StringUtils.rightPad(timeStamp, 10, '0');
      String rowKey = mid + "_" + ts;
      k.set(rowKey);
      context.write(k, movieBean);
    }
  }

  static class MovieReducer extends TableReducer<Text, MovieBean, ImmutableBytesWritable> {

    @Override
    protected void reduce(Text key, Iterable<MovieBean> values, Context context)
        throws IOException, InterruptedException {
      String rk = key.toString();
      //遍历每个movieBean,将其封装到put对象中
      for (MovieBean mb : values) {
        String movie = mb.getMovie();
        double rate = mb.getRate();
        String timeStamp = mb.getTimeStamp();
        String uid = mb.getUid();
        // 封装put对象
        Put put = new Put(rk.getBytes());

        put.addColumn("cf".getBytes(), "movie".getBytes(), Bytes.toBytes(movie));
        put.addColumn("cf".getBytes(), "rate".getBytes(), Bytes.toBytes(rate));
        put.addColumn("cf".getBytes(), "timeStamp".getBytes(), Bytes.toBytes(timeStamp));
        put.addColumn("cf".getBytes(), "uid".getBytes(), Bytes.toBytes(uid));
        context.write(null, put);

      }
    }

  }

  public static void main(String[] args)
      throws IOException, ClassNotFoundException, InterruptedException {
    Configuration conf = HBaseConfiguration.create();
    //连接zookeeper
    conf.set("hbase.zookeeper.quorum", "linux1:2181,linux2:2181,linux3:2181");
    Job job = Job.getInstance(conf);

    ///设置Mapper对应类
    job.setMapperClass(MovieMapper.class);
    //设置map输出类型
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(MovieBean.class);
    //设置文件输入路径
    FileInputFormat.setInputPaths(job, new Path("D:\\多易教育\\Hbase\\movie"));

    //设置输出为表
    TableMapReduceUtil.initTableReducerJob("movie", MovieReducer.class, job);

    System.exit(job.waitForCompletion(true) ? 0 : 1);
  }
}
  • Mapper中读取数据并设计行键为key
  • Reducer继承TableReducer,并且输出类型改为ImmutableBytesWritable,在Reducer中将每行数据封装为put对象并写出,写出时输出key为null,输出value为每行数据的put对象
  • job中不用再设置最终输出key、value类型,也不用设置Reducer类。设置输出路径改为设置输出为表
//设置输出为表
TableMapReduceUtil.initTableReducerJob("movie", MovieReducer.class, job);

参数分别为表名、Reducer类和job对象
需要注意的是,此表必须在Hbase中已存在

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值