HBase导入大数据三大方式之(三)——mapreduce+completebulkload 方式

做大数据时,经常需要用到将大量格式化的文本数据导入到hbase中。此处就用到的三种方式:hive类SQL语句方式、importtsv +completebulkload 方式、mapreduce+completebulkload 方式,做下简单示例。hive类SQL语句方式和importtsv +completebulkload 方式都已经介绍过了,现在介绍mapreduce+completebulkload 方式:

实例中,我以虚拟话单作为需要导入的数据,格式上上篇文章中有介绍。

一、设计HBASE的表名、列名和字段名:

1、  创建支持hive查询的hbase表:

CREATE TABLE bill(rowkey string, 00_selfnumber string, 01_day string, 02_hour string, 03_duration string, 04_calltype string, 05_targetnumber string, 06_address string, 07_longdtype string, 08_basecost float, 09_longdcostfloat, 10_infocostfloat,11_privilege string) STORED BY‘org.apache.hadoop.hive.hbase.HBaseStorageHandler’ WITH SERDEPROPERTIES(“hbase.columns.mapping”=“info:00_selfnumber,info:01_day,info:02_hour,info:03_duration,info:04_calltype,info:05_targetnumber,info:06_address,info:07_longdtype,info:08_basecost,info:09_longdcost,info:10_infocost,info:11_privilege”) TBLPROPERTIES (“hbase.table.name”=”bill”);

说明:

1、确定了表名:bill;列名:info;字段名:01_day~11_privilege

2、第一排的”bill”是在hive中的表名,最后一排的”bill”是对应hbase中的表名。两个表名可以不同,字段名需要相同。

注意:目前导入方法只支持一个列族,这里是“info”。Hbase中的字段名必须要按照alphabet人为排好序。

二、上传文件到HDFS:

1、  方法一:使用eclipse插件:



2、  方法二:put命令:

hadoop@master:/usr/hadoop/hadoop-2.0.0-cdh4.2.2$ bin/hdfs dfs-put bill.txt/user/hadoop/loadDataToHBase/input


1、  其它,如hadoopAPI,调用OTL可执行程序。

略。

说明:这里确定上传到HDFS的input文件的路径,如:

/user/hadoop/loadDataToHBase/input

三、写mapreduce代码将需要导入的数据生成hfile的格式:

LoadDataToHBase.java


   
   
  1. package com.melina;
  2. import java.io.IOException;
  3. import java.util.ArrayList;
  4. import java.util.Calendar;
  5. import java.util.Iterator;
  6. import java.util.List;
  7. import org.apache.hadoop.conf.Configuration;
  8. import org.apache.hadoop.fs.FileSystem;
  9. import org.apache.hadoop.fs.Path;
  10. import org.apache.hadoop.hbase.HBaseConfiguration;
  11. import org.apache.hadoop.hbase.KeyValue;
  12. import org.apache.hadoop.hbase.client.HTable;
  13. import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
  14. import org.apache.hadoop.hbase.util.Bytes;
  15. import org.apache.hadoop.io.LongWritable;
  16. import org.apache.hadoop.io.Text;
  17. import org.apache.hadoop.mapreduce.Job;
  18. import org.apache.hadoop.mapreduce.Mapper;
  19. import org.apache.hadoop.mapreduce.Reducer;
  20. import org.apache.hadoop.mapreduce.Reducer.Context;
  21. import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat;
  22. import org.apache.hadoop.hbase.mapreduce.KeyValueSortReducer;
  23. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  24. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  25. public class LoadDataToHBase {
  26. public static class LoadDataToHBaseMapper extends
  27. Mapper< LongWritable, Text, ImmutableBytesWritable, Text> {
  28. public static int y,m,d;
  29. Calendar cal=Calendar.getInstance();
  30. //map的key用一个immutableBytesWritable类型的无意义的key,map的value是直接将原来的一行记录输出,
  31. //map完成后会shuffle和sort,将key-value按照key排序,否则写不进hfile,hfile要求后写的key不能小于先写的key
  32. private ImmutableBytesWritable immutableBytesWritable = new ImmutableBytesWritable();
  33. protected void map(LongWritable key, Text value, Context context)
  34. throws IOException, InterruptedException {
  35. immutableBytesWritable.set(Bytes.toBytes(key.get()));
  36. context.write(immutableBytesWritable, value);
  37. }
  38. }
  39. //reducer每次得到map输出的value就是输入文件的中的一行
  40. //reducer的key也无意义,每一个value值就是一个hfile格式的输出,包括rowkey、family、qualifier、timestamp、value
  41. //其中rowkey是由“年月日+该行的行号”组成,每行的行号由预处理的时候加在每一行的开头
  42. public static class LoadDataToHBaseReducer extends
  43. Reducer< ImmutableBytesWritable, Text, ImmutableBytesWritable, KeyValue> {
  44. public static int y, m, d;
  45. Calendar cal = Calendar.getInstance();
  46. protected void reduce(ImmutableBytesWritable key, Iterable<Text> values,
  47. Context context)
  48. throws IOException, InterruptedException {
  49. String value= “”;
  50. while(values.iterator().hasNext())
  51. {
  52. value = values.iterator().next().toString();
  53. if(value != && ! “”.equals(value))
  54. {
  55. List<KeyValue> list = new ArrayList<KeyValue>();
  56. list = createKeyValue(value.toString());
  57. Iterator<KeyValue> it = list.iterator();
  58. while (it.hasNext()) {
  59. KeyValue kv = new KeyValue();
  60. kv = it.next();
  61. if(kv!= ) {
  62. context.write(key, kv);
  63. }
  64. }
  65. }
  66. }
  67. }
  68. private List<KeyValue> createKeyValue(String str) {
  69. List<KeyValue> list = new ArrayList<KeyValue>();
  70. String[] values = str.toString().split( “,”);
  71. String[] qualifiersName = CONSTANT.qualifiersName;
  72. //long timeStamp = CONSTANT.timeStamp;
  73. for ( int i = 1; i < qualifiersName.length; i++) {
  74. String rownum = values[ 0];
  75. String family = CONSTANT.familyName;
  76. String qualifier = qualifiersName[i];
  77. String value_str = values[i];
  78. y=cal.get(Calendar.YEAR);
  79. m=cal.get(Calendar.MONTH);
  80. d=cal.get(Calendar.DATE);
  81. String rowkey_str = Integer.toString(y)+Integer.toString(m)+Integer.toString(d)+rownum;
  82. KeyValue kv = new KeyValue(Bytes.toBytes(rowkey_str),
  83. Bytes.toBytes(family), Bytes.toBytes(qualifier),
  84. System.currentTimeMillis(), Bytes.toBytes(value_str));
  85. list.add(kv);
  86. }
  87. return list;
  88. }
  89. }
  90. public static void main(String[] args) throws IOException,
  91. InterruptedException, ClassNotFoundException {
  92. Configuration conf = HBaseConfiguration.create();
  93. Job job = new Job(conf, CONSTANT.jobName);
  94. job.setJarByClass(LoadDataToHBase.class);
  95. job.setOutputKeyClass(ImmutableBytesWritable.class);
  96. //注意此处的Text.class要与map函数的输出key-value的value类型相对应
  97. job.setOutputValueClass(Text.class);
  98. job.setMapperClass(LoadDataToHBaseMapper.class);
  99. job.setReducerClass(LoadDataToHBaseReducer.class);
  100. // job.setOutputFormatClass(org.apache.hadoop.hbase.mapreduce.HFileOutputFormat.class);
  101. job.setOutputFormatClass(HFileOutputFormat.class);
  102. // job.setNumReduceTasks(4);
  103. // job.setPartitionerClass(org.apache.hadoop.hbase.mapreduce.SimpleTotalOrderPartitioner.class);
  104. Configuration fs_conf = new Configuration();
  105. FileSystem fs = FileSystem.get(fs_conf);
  106. String str_inPath = CONSTANT.str_inPath;
  107. String str_outPath = CONSTANT.str_outPath;
  108. //如果输出路径存在就先删掉,因为不允许输出路径事先存在
  109. Path outPath = new Path(str_outPath);
  110. if (fs.exists(outPath))
  111. fs.delete(outPath, true);
  112. FileInputFormat.addInputPath(job, new Path(str_inPath));
  113. FileOutputFormat.setOutputPath(job, new Path(str_outPath));
  114. System.exit(job.waitForCompletion( true) ? 0 : 1);
  115. }
  116. }

我把需要用到的一些路径参数之类的写到了CONSTANT.java


   
   
  1. package com.melina;
  2. public class CONSTANT {
  3. public static final String jobName = "LoadDataToHBase";
  4. public static final String[] qualifiersName = { "", "00_selfnumber", "01_day", "02_hour", "03_duration",
  5. "04_calltype", "05_targetnumber", "06_address", "07_longdtype",
  6. "08_basecost", "09_longdcost", "10_infocost", "11_privilege" };
  7. public static final String familyName = "info";
  8. public static final String tableName = "bill";
  9. public static final String str_inPath = "/user/hadoop/loadDataToHBase/input";
  10. public static final String str_outPath = "/user/hadoop/loadDataToHBase/output";
  11. public static final long timeStamp = System.currentTimeMillis();
  12. }

需要相应地修改CONSTANT:

1、  把上面涉及到的表名、列名、字段名和输入文件的目录写进去。

2、  随便指定一个输出目录。如:

/user/hadoop/loadDataToHBase/output


说明:mapreduce的输出路径不允许实现存在,因为按理说这个输出目录应该为notexist的。不过程序里面会先判断这个路径如果事先存在则删除。所以可以填写一个已经存在的路径并且该路径下的文件可以被删除。

四、编译打包:

1、  java代码打包成jar:


五、修改运行脚本文件:

1、  把上一步打好的jar包放在集群中任意主机任意路径下,如:

/home/hadoop

2、  创建或者修改脚本文件LoadDataToHBase.sh,该脚本文件的作用是执行上面的jar包生成hfile,之后再将hfile导入到第一步建的hbase表中。

#!/bin/bash

/usr/hadoop/hadoop-2.0.0-mr1-cdh4.2.2/bin/hadoop jar /home/hadoop/LoadDataToHBase.jar com.melina.LoadDataToHBase&&

/usr/hadoop/hadoop-2.0.0-mr1-cdh4.2.2/bin/hadoop jar /usr/hadoop/hbase-0.94.2-cdh4.2.2/hbase-0.94.2-cdh4.2.2-security.jar completebulkload /user/hadoop/loadDataToHBase/output bill

说明:

1、  该脚本中包含两条命令,中间用”&&”分开,表示需要等待上一条命令执行完成之后才能执行第二条命令。

2、  第一条命令指明要执行的jar包就是刚刚生成的jar包,以及要执行的main所在的类。

3、  第二条命令要执行的jar包就是hbase的jar包,执行completebulkload后面是hfile在HDFS上的存放路径以及要导的hbase表。

可 以看出这个方法 与 importtsv +completebulkload 的区别在于用mapreduce替代了importtsv将数据生成了hfile格式。


六、运行:

1、  让脚本可执行:

Sudo chmod +x/home/hadoop/LoadDataToHBase.sh

2、  执行脚本:

./LoadDataToHBase.sh

七、查看结果:

1、  通过eclipse可以看到HDFS上面hbase里面的表bill里面已经有hfile了:



2、  通过hive命令查询hbase的表bill的数据:

hive> select *from bill limit 10;


八、附件:

1、  话单预处理之后的数据bill.txt。

2、  Mapreduce程序工程。

3、  Mapreduce程序jar包。

4、  脚本文件LoadDataToHBase.sh。

下载地址:http://download.csdn.net/detail/luckymelina/7142747



OK!GOOD LUCK!小伙伴们加油!
            </div>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值