Hadoop,MapReduce操作Mysql
1、为了方便 MapReduce 直接访问关系型数据库(Mysql,Oracle),Hadoop提供了DBInputFormat和DBOutputFormat两个类。通过DBInputFormat类把数据库表数据读入到HDFS,根据DBOutputFormat类把MapReduce产生的结果集导入到数据库表中。
2、由于0.20版本对DBInputFormat和DBOutputFormat支持不是很好,该例用了0.19版本来说明这两个类的用法。
至少在我的 0.20.203 中的 org.apache.hadoop.mapreduce.lib 下是没见到 db 包,所以本文也是以老版的 API 来为例说明的。
3、运行MapReduce时候报错:java.io.IOException: com.mysql.jdbc.Driver,一般是由于程序找不到mysql驱动包。解决方法是让每个tasktracker运行MapReduce程序时都可以找到该驱动包。
添加包有两种方式:
(1)在每个节点下的${HADOOP_HOME}/lib下添加该包。重启集群,一般是比较原始的方法。
(2)a)把包传到集群上: hadoop fs -put mysql-connector-java-5.1.0- bin.jar /hdfsPath/
b)在mr程序提交job前,添加语句:DistributedCache.addFileToClassPath(new Path(“/hdfsPath/mysql- connector-java- 5.1.0-bin.jar”), conf);
一、数据库操作
CREATE TABLE `t` ( `id` int DEFAULT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `t2` ( `id` int DEFAULT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into t values (1,"june"),(2,"decli"),(3,"hello"), (4,"june"),(5,"decli"),(6,"hello"),(7,"june"), (8,"decli"),(9,"hello"),(10,"june"), (11,"june"),(12,"decli"),(13,"hello");
二、MapReduce代码
1 import java.io.DataInput; 2 import java.io.DataOutput; 3 import java.io.File; 4 import java.io.IOException; 5 import java.sql.PreparedStatement; 6 import java.sql.ResultSet; 7 import java.sql.SQLException; 8 9 import mapr.EJob; 10 11 import org.apache.hadoop.conf.Configuration; 12 import org.apache.hadoop.filecache.DistributedCache; 13 import org.apache.hadoop.fs.Path; 14 import org.apache.hadoop.io.LongWritable; 15 import org.apache.hadoop.io.Text; 16 import org.apache.hadoop.io.Writable; 17 import org.apache.hadoop.mapred.JobConf; 18 import org.apache.hadoop.mapreduce.Job; 19 import org.apache.hadoop.mapreduce.Mapper; 20 import org.apache.hadoop.mapreduce.Reducer; 21 import org.apache.hadoop.mapreduce.lib.db.DBConfiguration; 22 import org.apache.hadoop.mapreduce.lib.db.DBInputFormat; 23 import org.apache.hadoop.mapreduce.lib.db.DBOutputFormat; 24 import org.apache.hadoop.mapreduce.lib.db.DBWritable; 25 26 /** 27 * Function: 测试 mr 与 mysql 的数据交互,此测试用例将一个表中的数据复制到另一张表中 实际当中,可能只需要从 mysql 读,或者写到 28 * mysql 中。 29 * 30 * @author administrator 31 * 32 */ 33 public class Mysql2Mr { 34 public static class StudentinfoRecord implements Writable, DBWritable { 35 int id; 36 String name; 37 38 public StudentinfoRecord() { 39 40 } 41 42 public String toString() { 43 return new String(this.id + " " + this.name); 44 } 45 46 @Override 47 public void readFields(ResultSet result) throws SQLException { 48 this.id = result.getInt(1); 49 this.name = result.getString(2); 50 } 51 52 @Override 53 public void write(PreparedStatement stmt) throws SQLException { 54 stmt.setInt(1, this.id); 55 stmt.setString(2, this.name); 56 } 57 58 @Override 59 public void readFields(DataInput in) throws IOException { 60 this.id = in.readInt(); 61 this.name = Text.readString(in); 62 } 63 64 @Override 65 public void write(DataOutput out) throws IOException { 66 out.writeInt(this.id); 67 Text.writeString(out, this.name); 68 } 69 70 } 71 72 // 记住此处是静态内部类,要不然你自己实现无参构造器,或者等着抛异常: 73 // Caused by: java.lang.NoSuchMethodException: DBInputMapper.<init>() 74 // http://stackoverflow.com/questions/7154125/custom-mapreduce-input-format-cant-find-constructor 75 // 网上脑残式的转帖,没见到一个写对的。。。 76 public static class DBInputMapper extends 77 Mapper<LongWritable, StudentinfoRecord, LongWritable, Text> { 78 @Override 79 public void map(LongWritable key, StudentinfoRecord value, 80 Context context) throws IOException, InterruptedException { 81 context.write(new LongWritable(value.id), new Text(value.toString())); 82 } 83 } 84 85 86 public static class MyReducer extends Reducer<LongWritable, Text, StudentinfoRecord, Text> { 87 @Override 88 public void reduce(LongWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException { 89 String[] splits = values.iterator().next().toString().split(" "); 90 StudentinfoRecord r = new StudentinfoRecord(); 91 r.id = Integer.parseInt(splits[0]); 92 r.name = splits[1]; 93 context.write(r, new Text(r.name)); 94 95 } 96 } 97 98 @SuppressWarnings("deprecation") 99 public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException { 100 File jarfile = EJob.createTempJar("bin"); 101 EJob.addClasspath("usr/hadoop/conf"); 102 103 ClassLoader classLoader = EJob.getClassLoader(); 104 Thread.currentThread().setContextClassLoader(classLoader); 105 106 Configuration conf = new Configuration(); 107 // 这句话很关键 108 conf.set("mapred.job.tracker", "172.30.1.245:9001"); 109 DistributedCache.addFileToClassPath(new Path( 110 "hdfs://172.30.1.245:9000/user/hadoop/jar/mysql-connector-java-5.1.6-bin.jar"), conf); 111 DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver", "jdbc:mysql://172.30.1.245:3306/sqooptest", "sqoop", "sqoop"); 112 113 Job job = new Job(conf, "Mysql2Mr"); 114 // job.setJarByClass(Mysql2Mr.class); 115 ((JobConf)job.getConfiguration()).setJar(jarfile.toString()); 116 job.setMapOutputKeyClass(LongWritable.class); 117 job.setMapOutputValueClass(Text.class); 118 119 job.setMapperClass(DBInputMapper.class); 120 job.setReducerClass(MyReducer.class); 121 122 job.setOutputKeyClass(LongWritable.class); 123 job.setOutputValueClass(Text.class); 124 125 job.setOutputFormatClass(DBOutputFormat.class); 126 job.setInputFormatClass(DBInputFormat.class); 127 128 String[] fields = {"id","name"}; 129 // 从 t 表读数据 130 DBInputFormat.setInput(job, StudentinfoRecord.class, "t", null, "id", fields); 131 // mapreduce 将数据输出到 t2 表 132 DBOutputFormat.setOutput(job, "t2", "id", "name"); 133 134 System.exit(job.waitForCompletion(true)? 0:1); 135 } 136 }
三、数据库结果
1 mysql> select * from t2; 2 +------+-------+ 3 | id | name | 4 +------+-------+ 5 | 1 | june | 6 | 2 | decli | 7 | 3 | hello | 8 | 4 | june | 9 | 5 | decli | 10 | 6 | hello | 11 | 7 | june | 12 | 8 | decli | 13 | 9 | hello | 14 | 10 | june | 15 | 11 | june | 16 | 12 | decli | 17 | 13 | hello | 18 | 1 | june | 19 | 2 | decli | 20 | 3 | hello | 21 | 4 | june | 22 | 5 | decli | 23 | 6 | hello | 24 | 7 | june | 25 | 8 | decli | 26 | 9 | hello | 27 | 10 | june | 28 | 11 | june | 29 | 12 | decli | 30 | 13 | hello | 31 +------+-------+ 32 26 rows in set (0.00 sec)
View Code
面向对象面向君,不负代码不负卿!
浙公网安备 33010602011771号