Hbase--海量数据导入Hbase和Hbase数据导入Hdfs

Hbase–海量数据导入Hbase和Hbase数据导入Hdfs

一:海量数据导入Hbase
1.代码实现
package hbasePut;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.TestMiniMRClientCluster.MyReducer;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

public class HdfstrueHbase {
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		System.setProperty("HADOOP_USER_NAME", "hadoop");
		//加载配置文件
		Configuration conf=new Configuration();
		//将core.site  hdfs.site放在src下
		//设置高可用的集群
		conf.set("fs.defaultFS", "hdfs://bd1906/");
		//指定zookeeper的访问路径
		conf.set("hbase.zookeeper.quorum", "hadoop01:2181,hadoop02:2181,hadoop03:2181");
		//启动一个job
		Job job=Job.getInstance(conf);
		/**
		 * 指定job的主要入口
		 * class的获取
		 * 1:类名,class
		 * 2:对象,getClass
		 * 3.Class.forname
		 */
		job.setJarByClass(HdfstrueHbase.class);
		//指定job中mapper对应的类
		job.setMapperClass(MyMapper.class);
		//指定reduce对应的类
		//job.setReducerClass(MyReducer.class);
		
		/**
		 * 泛型:只在代码编译时后生效,代码运行的时候自动删除
		 * 框架---map---reduce---hadfs
		 */
		//指定map输出的key  value的类型
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);
		
		
		//指定reduce输出的key value的类型
		job.setOutputKeyClass(NullWritable.class);
		job.setOutputValueClass(Put.class);
		
		//指定输入  
		Path inpath=new Path("/user/hbase/ratings.dat");
		FileInputFormat.addInputPath(job, inpath);
		
		//指定输出路径 最终结果存储 值得hdfs的路径,输出的路径一定不能存在
		//借助一个工具类指定表名
		/**
		 * 参数1:表名
		 * 参数2:reduce的对应类
		 * 参数三:job
		 */
		TableMapReduceUtil.initTableReducerJob("user_hdfs", MyReducer.class, job, 
				null, null, null, null, false);
		
		//真正的提交job,不会打印日志
		//job.submit()
		job.waitForCompletion(true);
	}
	/**
	 * key:行键
	 * value:其他数据信息
	 *
	 */
	static class MyMapper extends Mapper<LongWritable, Text, Text, Text>{
		Text mk=new Text();
		Text mv=new Text();
		int i = 0;
		@Override
		protected void map(LongWritable key, Text value, Context context)
				throws IOException, InterruptedException {
			//1::1193::5::978300760
			i++;
			String line = value.toString();
			String[] datas = line.split("::");
			mk.set(datas[0]+i);
			mv.set(datas[1]+"\t"+datas[2]+"\t"+datas[3]);
			context.write(mk, mv);
		}
	}
	/**
	 * 泛型1:泛型2:map端输入
	 * 泛型3:reduce端输出的key
	 *泛型4:省略,mutation对象---put|delete
	 *
	 *解析map发送的数据进行封装
	 */
	static class MyReducer extends TableReducer<Text, Text, NullWritable>{
		@Override
		protected void reduce(Text key, Iterable<Text> value,Context context)
				throws IOException, InterruptedException {
			for (Text v : value) {
				String[] datas = v.toString().split("\t");
				Put p=new Put(key.getBytes());
				//1::1193::5::978300760
				p.addColumn("info".getBytes(), "version".getBytes(), datas[0].getBytes());
				p.addColumn("info".getBytes(), "amount".getBytes(), datas[1].getBytes());
				p.addColumn("info".getBytes(), "id".getBytes(), datas[2].getBytes());
				//将put对象写出到hbase中
				context.write(NullWritable.get(), p);
			}
		}
	}
}

2.遇到的错误以及注意要点

1)这里使用的hdfs配置的是高可用集群,需要将linux中Hbase的安装配置文件中的core.site和hdfs.site放在src下,不然不能识别;

2)出现错误:Exception in thread “main” java.lang.IllegalArgumentException: Pathname /D:/bigdata_soft/hbase-1.2.6/lib/hbase-prefix-tree-1.2.6.jar from hdfs://bd1906/D:/bigdata_soft/hbase-1.2.6/lib/hbase-prefix-tree-1.2.6.jar is not a valid DFS filename.这个是jar包冲突导致的错误,解决办法:

  • 调整jar包的导入顺序: hadoop导入在前, hbase 导入在后
  • 代码TableMapReduceUtil.initTableReducerJob(“user_hdfs”, MyReducer.class,job,null,null,null,null,false);

3)TableMapReduceUtil工具类的initTableReducerJob()方法可以用来指定路径,和解决jar包冲突,是一个好东西。

4)如果使用TableMapReduceUtil指定了路径,前面的job指定的路径就可以删掉了

5)一定要注意路径问题,如果在hdfs中路径错误,可能在map阶段处理的时候回造成数组下表越界的问题

二:数据从Hbase导入到Hdfs
1.代码实现

这里是一个例题:求相同年龄的人数,将结果写到hdfs上面

package HbaseTsxt;

import java.io.IOException;
import java.util.List;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class HbaseToHdfs {
	public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
		System.setProperty("HADOOP_USER_NAME", "hadoop");
		Configuration conf=HBaseConfiguration.create();
		conf.set("fs.defaultFS", "hdfs://bd1906/");//mapreduce相关的,设置为高可用
		conf.set("hbase.zookeeper.quorum", "hadoop01:2181,hadoop02:2181,hadoop03:2181");//指定zookeeper
		//Connection connection=ConnectionFactory.createConnection(conf);
		//启动一个工作
		Job job=Job.getInstance(conf);
		//指定工作的入口
		job.setJarByClass(HbaseToHdfs.class);
		//指定reduce的入口
		job.setReducerClass(MyReduce.class);
		//指定map的入口
		job.setMapperClass(MyMapper.class);
		//指定map输出的key,value
		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(IntWritable.class);
		//指定reduce输出的key,value
		//job.setOutputKeyClass(Text.class);
		//job.setOutputValueClass(IntWritable.class);
		//指定hbase的表
		Scan scan=new Scan();
		//scan.addColumn(family, qualifier);
		TableMapReduceUtil.initTableMapperJob("HbaseAPI:HbaseAPI01", scan, MyMapper.class, Text.class, IntWritable.class, job,false);
		//指定输出
		FileSystem fs=FileSystem.get(conf);
		Path output=new Path("/user/hbase/data/hbasetohdfs");
		if(fs.exists(output)){
			fs.delete(output, true);
		}
		//FileOutputFormat指定工作的输出路径
		FileOutputFormat.setOutputPath(job, output);
		//提交工作
		job.waitForCompletion(true);
		
	}
	/**
	 * 泛型1:输出的key的类型
	 * 泛型2:输出的value的类型
	 *
	 */
	static class MyMapper extends TableMapper<Text, IntWritable>{
		/**
		 * 参数1:行键对象
		 * 参数2:行键那一行的结果集
		 */
		//创建输入输出对象
		Text mk=new Text();
		IntWritable mv=new IntWritable();
		@Override
		protected void map(ImmutableBytesWritable key, Result value,
				Mapper<ImmutableBytesWritable, Result, Text, IntWritable>.Context context)
				throws IOException, InterruptedException {
			//listCells()方法取出所有的单元格
			List<Cell> Cells = value.listCells();
			//遍历单元格,做k,v处理
			for (Cell cell : Cells) {
				String qualifier=Bytes.toString(CellUtil.cloneQualifier(cell));
				if (qualifier.equals("age")) {
					String k=Bytes.toString(CellUtil.cloneValue(cell));
					mk.set(k);
					mv.set(1);
					context.write(mk, mv);
				}
			}
		}
	}
	/**
	 * 参数1:输入key的类型
	 * 参数2:输入value的类型
	 * 参数2:输出key的类型
	 * 参数4:输出value的类型
	 */
	static class MyReduce extends Reducer<Text, IntWritable, Text, IntWritable>{
		IntWritable mv=new IntWritable();
		@Override
		/**
		 * 参数1:输入的key
		 * 参数2:map端的value集合
		 * key相同的启动一个reducetask,对values处理,v累=累加
		 */
		protected void reduce(Text key, Iterable<IntWritable> values,
				Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
			int count=0;
			for (IntWritable v : values) {
				count+=v.get();
			}
			mv.set(count);
			context.write(key, mv);
		}
		
	}
}

2.遇到的错误以及注意要点

1)写出的路径存在导致的错误:Exception in thread “main” org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://bd1906/user/hbase/data/hbasetohdfs already exists 解决办法:每次指定输出到hdfs上面的时候进行判断,如果路径存在就删除路径下的文件

if(fs.exists(output)){
			fs.delete(output, true);
		}

2)权限问题,导致无法连接,可以加上权限管理

System.setProperty("HADOOP_USER_NAME", "hadoop");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值