hbase--Hbase与MapReduce集成

本文介绍了Hbase分布式数据库与MapReduce分布式计算的集成应用。阐述了应用场景、集成原理,详细说明了读Hbase数据到文件和将文件数据存储到Hbase的开发规则及实现过程,还分析了运行程序时出现的jar包冲突和缺失问题,并给出解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、应用场景

  • Hbase:分布式数据库
    • 实现分布式存储
  • MapReduce:分布式计算
    • 实现分布式计算
    • 读写分布式存储
      • HDFS:文件系统,以文件形式管理数据,一次写入,多次读取
      • Hive数据仓库,以形式管理数据,但底层数据还是文件,一次写入,多次读取
      • Hbase数据库,以的形式管理数据,但底层优先使用内存,随机实时读写访问

2、集成原理

  • 读:InputFormat
    • Text/File:读取文件
    • DB:读数据库
    • Table:读Hbase
  • 写:OutputFormat
    • Text/File:写文件
    • DB:写数据库
    • Table:写Hbase

3、读Hbase数据

  • 需求:读stu表中的数据,写入文件
  • 分析
    • TableInputFormat
    • TextOutputFormat
  • 读Hbase数据的开发规则
    • Driver中的输入和Map发生了改变
      • 以前
//配置输入
job.setInputFormat(xxxInputFormat.class);
xxxInputFormat.setInputPath(inputPath);
//配置Map
job.setMapperClass
job.setMapperOutputKeyClass
job.setMapperOutputValueClass
  • 现在读hbase,MapReduce将读Hbase的配置做了封装
    • 调用这个 方法,传递参数,就能实现输入input和Map的配置
TableMapReduceUtil.initTableMapperJob(
    给定输入和Map的属性
);
  • Mapper类需要继承自TableMapper
    • 读Hbase:用的是TableInputFormat
      • Key:ImmutableBytesWritable:一种特殊的字节数组类型
        • rowkey
      • Value:Result:存储一个Rowkey的所有数据
        • 这个rowkey的所有数据
      • 一个Rowkey变成一个KV,调用一次map方法
    • KeyIn:不能指定,定死了
      • ImmutableBytesWritable
    • ValueIn:不能指定,定死了
      • Result
    • KeyOut
    • ValueOut
  • 其他的:Reduce和Shuffle和以前写法是一样的
  • 实现
/**
* @ClassName ReadHbaseTable
* @Description TODO 通过MapReduce读取Hbase表中的数据
* @Date 2020/6/30 11:43
* @Create By     Frank
*/
public class ReadHbaseTable extends Configured implements Tool {
   @Override
   public int run(String[] args) throws Exception {
       //todo:1-创建
       Job job =  Job.getInstance(this.getConf(),"read");
       job.setJarByClass(ReadHbaseTable.class);
       //todo:2-配置
       //input&map
       /**
        * public static void initTableMapperJob(
        *       String table,                             指定从哪张表读取
        *       Scan scan,                                 读取Hbase数据使用的Scan对象,自定义过滤器
        *       Class<? extends TableMapper> mapper,       Mapper类
        *       Class<?> outputKeyClass,                   Map输出的Key类型
        *       Class<?> outputValueClass,                 Map输出的Value类型
        *       Job job                                   当前的job
        * )
        */
       Scan scan = new Scan();
       //可以为scan设置过滤器
       TableMapReduceUtil.initTableMapperJob(
               "student:stu",
               scan,
               ReadHbaseMap.class,
               Text.class,
               Text.class,
               job
      );
       //reduce
       job.setNumReduceTasks(0);
       //output
       TextOutputFormat.setOutputPath(job,new Path("datas/output/hbase"));
       //todo:3-提交
       return job.waitForCompletion(true) ? 0:-1;
  }

   public static void main(String[] args) throws Exception {
       Configuration conf = HBaseConfiguration.create();
       int status = ToolRunner.run(conf, new ReadHbaseTable(), args);
       System.exit(status);
  }

   /**
    * TableMapper<KEYOUT, VALUEOUT>
    * extends Mapper<ImmutableBytesWritable, Result, KEYOUT, VALUEOUT>
    */
   public static class ReadHbaseMap extends TableMapper<Text, Text>{
       //rowkey
       Text outputKey = new Text();
       //每一列的数据
       Text outputValue = new Text();


       /**
        * 每个KV调用一次map方法
        * @param key:rowkey
        * @param value:这个rowkey的数据
      * @param context
        * @throws IOException
        * @throws InterruptedException
        */
       @Override
       protected void map(ImmutableBytesWritable key, Result value, Context context) throws IOException, InterruptedException {
           //给key进行赋值
           String rowkey = Bytes.toString(key.get());
           this.outputKey.set(rowkey);
           //给value赋值
           for(Cell cell : value.rawCells()){
               //得到每一列的数据
               String family = Bytes.toString(CellUtil.cloneFamily(cell));
               String column = Bytes.toString(CellUtil.cloneQualifier(cell));
               String val  = Bytes.toString(CellUtil.cloneValue(cell));
               long ts = cell.getTimestamp();
               this.outputValue.set(family+"\t"+column+"\t"+val+"\t"+ts);
               context.write(this.outputKey,this.outputValue);
          }
      }
  }
}

4、存储到Hbase

  • 需求:将文件中数据写入Hbase
  • 分析
    • Input:TextInputFormat
    • Output:TableOutputFormat
  • 写入Hbase的规则
    • Driver类中配置reduce和output,不能用以前的方式,调用Hbase封装好的方法来配置reduce和output
  • 以前
job.setreduceclass
job.setoutputkey
job.setoutputvalue

job.setoutputformat(xxxxOutputFormat.class);
xxxxOutputFormat.setOutputpath
  • 写入Hbase
TableMapReduceUtil.initTableReducerJob(
    配置reduce和输出的参数
);
  • Reducer类必须继承自TableReducer
    • 将输出的类型定死了
  • 其他的代码还是和以前一样
  • 实现
  • 开发代码,打成jar包
/**
* @ClassName WriteHbaseTable
* @Description TODO 通过MapReduce将数据写入Hbase
* @Date 2020/6/30 11:43
* @Create By     Frank
*/
public class WriteHbaseTable extends Configured implements Tool {
   @Override
   public int run(String[] args) throws Exception {
       //todo:1-创建
       Job job =  Job.getInstance(this.getConf(),"write");
       job.setJarByClass(WriteHbaseTable.class);
       //todo:2-配置
       //input
       TextInputFormat.setInputPaths(job,new Path(args[0]));
       //map
       job.setMapperClass(WriteToHbaseMap.class);
       job.setMapOutputKeyClass(Text.class);
       job.setMapOutputValueClass(Put.class);
       //shuffle
       //reduce&output
       /**
        * public static void initTableReducerJob(
        *     String table,                               将数据写入Hbase的哪张表
        *     Class<? extends TableReducer> reducer,       reducer的类
        *     Job job)                                     当前的job
        *
        *     以前输出的写法:
        *     job.setoutputKey:因为Key可以任意的,这里根本用不到
        *     job.setoutputValue:在TableReduce中将outputValue定死了,所以不用写
        *
        */
       TableMapReduceUtil.initTableReducerJob(
           "student:mrwrite",
           WriteToHbaseReduce.class,
           job
      );
       //todo:3-提交
       return job.waitForCompletion(true) ? 0:-1;
  }

   public static void main(String[] args) throws Exception {
       Configuration conf = HBaseConfiguration.create();
       int status = ToolRunner.run(conf, new WriteHbaseTable(), args);
       System.exit(status);
  }

   /**
    * 读取文件,将文件中的内容,id作为key,其他的每一列作为一个Put对象
    */
   public static class WriteToHbaseMap extends Mapper<LongWritable,Text,Text, Put>{

       Text rowkey = new Text();

       @Override
       protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
           //value:1liudehua18male
           String[] split = value.toString().split("\t");
           String row = split[0];
           String name = split[1];
           String age = split[2];
           String sex = split[3];
           //将id作为rowkey,放在key中输出
           this.rowkey.set(split[0]);
           //构造输出的Value
           Put putname = new Put(Bytes.toBytes(row));
           putname.addColumn(Bytes.toBytes("info"),Bytes.toBytes("name"),Bytes.toBytes(name));
           context.write(rowkey,putname);
           Put putage = new Put(Bytes.toBytes(row));
           putage.addColumn(Bytes.toBytes("info"),Bytes.toBytes("age"),Bytes.toBytes(age));
           context.write(rowkey,putage);
           Put putsex = new Put(Bytes.toBytes(row));
           putsex.addColumn(Bytes.toBytes("info"),Bytes.toBytes("sex"),Bytes.toBytes(sex));
           context.write(rowkey,putsex);
      }
  }

   /**
    * public abstract class TableReducer<KEYIN, VALUEIN, KEYOUT>
    * extends Reducer<KEYIN, VALUEIN, KEYOUT, Mutation>
    *     最后Reduce输出的Value类型必须为Put类型,才能将数据写入Hbase
    */
   public static class WriteToHbaseReduce extends TableReducer<Text,Put,Text>{
       /**
        * 相同rowkey的所有Put都在一个迭代器中
        * @param key
        * @param values
        * @param context
        * @throws IOException
        * @throws InterruptedException
        */
       @Override
       protected void reduce(Text key, Iterable<Put> values, Context context) throws IOException, InterruptedException {
           //直接遍历每个put对象,输出即可
           for (Put value : values) {
               context.write(key,value);
          }
      }
  }

}
  • 在HBASE中创建结果表
create 'student:mrwrite','info'
  • 在hdfs上创建目录,上传文件
hdfs dfs -mkdir -p /user/hbaseinput/
hdfs dfs -put hbaseinput.txt /user/hbaseinput/
  • 运行
yarn jar hbase.jar cn.hanjiaxiaozhi.hbase.mr.WriteHbaseTable /user/hbaseinput/
  • 报错:
    在这里插入图片描述
  • 分析
    • 环境变量中类冲突,jar包冲突
    • 环境变量中没有这个类,缺少jar包
    • 当前我们在Hadoop中运行Hbase的程序,肯定会缺少Hbase的jar包
  • 解决
    • 找到缺少哪些 jar包
hbase mapredcp
/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-client-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-prefix-tree-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/htrace-core-3.2.0-incubating.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-common-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/zookeeper-3.4.5-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/guava-12.0.1.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-hadoop-compat-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/netty-all-4.0.23.Final.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-protocol-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/protobuf-java-2.5.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/metrics-core-2.2.0.jar
  • 将这些jar包的路径添加到Hadoop的运行环境变量中
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-client-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-server-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-prefix-tree-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/htrace-core-3.2.0-incubating.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-common-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/zookeeper-3.4.5-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/guava-12.0.1.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-hadoop-compat-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/netty-all-4.0.23.Final.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/hbase-protocol-1.2.0-cdh5.14.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/protobuf-java-2.5.0.jar:/export/servers/hbase-1.2.0-cdh5.14.0/lib/metrics-core-2.2.0.jar
  • 重新运行程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值