MapReduce编程实例(二)-MR2操作MySQL

MR2中如果需要从数据库中读取或者写入数据,需要自己实现Writable和DBWritable两个接口,同时还需在DBConfiguration对数据库的元信息做相应配置。

下面这个例子是Hadoop自带的,只是将数据库改为MySQL,在执行之前需要将Java连接MySQL的驱动上传到每台机器的${HADOOP_HOME}/share/hadoop/common路径下

这里需要说明两点:

1、一般不需要MR直接操作数据库,因为MR并发执行,很容易把数据库跑崩,此例只展示如何操作

2、如果必须要操作数据库,可以将数据库里面的数据导出到文本文件中,计算完成后,在通过SQLLoad的方式保存到数据库

例子比较简单,通过注释可以看懂

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.test.mr2;  
  2.   
  3. /** 
  4.  *MapReduce操作数据库实例 
  5.  *计算页面访问总量,Access表中保存了每个页面访问明细,Pageview表保存了每个页面被浏览的总次数 
  6.  *sum Access表的每个url,将计算结果写到Pageview 
  7.  */  
  8.   
  9. import java.io.DataInput;  
  10. import java.io.DataOutput;  
  11. import java.io.IOException;  
  12. import java.sql.Connection;  
  13. import java.sql.DriverManager;  
  14. import java.sql.PreparedStatement;  
  15. import java.sql.ResultSet;  
  16. import java.sql.SQLException;  
  17. import java.sql.Statement;  
  18. import java.util.Random;  
  19.   
  20. import org.apache.commons.logging.Log;  
  21. import org.apache.commons.logging.LogFactory;  
  22. import org.apache.hadoop.conf.Configuration;  
  23. import org.apache.hadoop.conf.Configured;  
  24. import org.apache.hadoop.io.LongWritable;  
  25. import org.apache.hadoop.io.NullWritable;  
  26. import org.apache.hadoop.io.Text;  
  27. import org.apache.hadoop.io.Writable;  
  28. import org.apache.hadoop.mapreduce.Job;  
  29. import org.apache.hadoop.mapreduce.Mapper;  
  30. import org.apache.hadoop.mapreduce.Reducer;  
  31. import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;  
  32. import org.apache.hadoop.mapreduce.lib.db.DBInputFormat;  
  33. import org.apache.hadoop.mapreduce.lib.db.DBOutputFormat;  
  34. import org.apache.hadoop.mapreduce.lib.db.DBWritable;  
  35. import org.apache.hadoop.mapreduce.lib.reduce.LongSumReducer;  
  36. import org.apache.hadoop.util.StringUtils;  
  37. import org.apache.hadoop.util.Tool;  
  38. import org.apache.hadoop.util.ToolRunner;  
  39.   
  40. public class DBOperator extends Configured implements Tool {  
  41.   
  42.     private static final Log LOG = LogFactory.getLog(DBOperator.class);  
  43.   
  44.     private Connection connection;  
  45.     private boolean initialized = false;  
  46.     // Access表字段名称  
  47.     private static final String[] AccessFieldNames = { "url""referrer",  
  48.             "time" };  
  49.     // Pageview表字段名称  
  50.     private static final String[] PageviewFieldNames = { "url""pageview" };  
  51.   
  52.     private static final String DB_URL = "jdbc:mysql://192.168.1.182:3306/hadoop?createDatabaseIfNotExist=true";  
  53.     private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";  
  54.   
  55.     private static final String DB_USER = "root";  
  56.     private static final String DB_PASSWORD = "root";  
  57.   
  58.     // 建立数据库连接  
  59.     private void createConnection(String driverClassName, String url)  
  60.             throws Exception {  
  61.   
  62.         Class.forName(driverClassName);  
  63.         connection = DriverManager.getConnection(url, DB_USER, DB_PASSWORD);  
  64.         connection.setAutoCommit(false);  
  65.     }  
  66.   
  67.     // 关闭数据库连接  
  68.     private void shutdown() {  
  69.         try {  
  70.             connection.commit();  
  71.   
  72.         } catch (Throwable ex) {  
  73.             LOG.warn("Exception occurred while closing connection :"  
  74.                     + StringUtils.stringifyException(ex));  
  75.         } finally {  
  76.             try {  
  77.                 if (connection != null) {  
  78.                     connection.close();  
  79.                 }  
  80.             } catch (Throwable ex) {  
  81.                 LOG.warn("Exception occurred while shutting down HSQLDB :"  
  82.                         + StringUtils.stringifyException(ex));  
  83.             }  
  84.         }  
  85.     }  
  86.   
  87.     // 初始化数据库信息  
  88.     private void initialize(String driverClassName, String url)  
  89.             throws Exception {  
  90.         if (!this.initialized) {  
  91.             createConnection(driverClassName, url);  
  92.             dropTables();  
  93.             createTables();  
  94.             populateAccess();  
  95.             this.initialized = true;  
  96.         }  
  97.     }  
  98.   
  99.     private void dropTables() {  
  100.         String dropAccess = "DROP TABLE Access IF EXISTS";  
  101.         String dropPageview = "DROP TABLE Pageview IF EXISTS";  
  102.         Statement st = null;  
  103.         try {  
  104.             st = connection.createStatement();  
  105.             st.executeUpdate(dropAccess);  
  106.             st.executeUpdate(dropPageview);  
  107.             connection.commit();  
  108.             st.close();  
  109.         } catch (SQLException ex) {  
  110.             try {  
  111.                 if (st != null) {  
  112.                     st.close();  
  113.                 }  
  114.             } catch (Exception e) {  
  115.             }  
  116.         }  
  117.     }  
  118.   
  119.     private void createTables() throws SQLException {  
  120.   
  121.         String createAccess = "CREATE TABLE IF NOT EXISTS "  
  122.                 + "Access(url      VARCHAR(100) NOT NULL,"  
  123.                 + " referrer VARCHAR(100)," + " time     BIGINT NOT NULL, "  
  124.                 + " PRIMARY KEY (url, time))";  
  125.   
  126.         String createPageview = "CREATE TABLE IF NOT EXISTS "  
  127.                 + "Pageview(url      VARCHAR(100) NOT NULL,"  
  128.                 + " pageview     BIGINT NOT NULL, " + " PRIMARY KEY (url))";  
  129.   
  130.         Statement st = connection.createStatement();  
  131.         try {  
  132.             st.executeUpdate(createAccess);  
  133.             st.executeUpdate(createPageview);  
  134.             connection.commit();  
  135.         } finally {  
  136.             st.close();  
  137.         }  
  138.     }  
  139.   
  140.     /** 
  141.      * 填充测试数据到Access表中 
  142.      */  
  143.     private void populateAccess() throws SQLException {  
  144.   
  145.         PreparedStatement statement = null;  
  146.         try {  
  147.             statement = connection  
  148.                     .prepareStatement("INSERT INTO Access(url, referrer, time)"  
  149.                             + " VALUES (?, ?, ?)");  
  150.   
  151.             Random random = new Random();  
  152.   
  153.             int time = random.nextInt(50) + 50;  
  154.   
  155.             final int PROBABILITY_PRECISION = 100// 1 / 100  
  156.             final int NEW_PAGE_PROBABILITY = 15// 15 / 100  
  157.   
  158.             // Pages in the site :  
  159.             String[] pages = { "/a""/b""/c""/d""/e""/f""/g""/h",  
  160.                     "/i""/j" };  
  161.             // linkMatrix[i] is the array of pages(indexes) that page_i links  
  162.             // to.  
  163.             int[][] linkMatrix = { { 157 }, { 0746, },  
  164.                     { 0178 }, { 024679 }, { 01 },  
  165.                     { 0359 }, { 0 }, { 013 }, { 026 },  
  166.                     { 026 } };  
  167.   
  168.             // a mini model of user browsing a la pagerank  
  169.             int currentPage = random.nextInt(pages.length);  
  170.             String referrer = null;  
  171.   
  172.             for (int i = 0; i < time; i++) {  
  173.   
  174.                 statement.setString(1, pages[currentPage]);  
  175.                 statement.setString(2, referrer);  
  176.                 statement.setLong(3, i);  
  177.                 statement.execute();  
  178.   
  179.                 int action = random.nextInt(PROBABILITY_PRECISION);  
  180.   
  181.                 // go to a new page with probability  
  182.                 // NEW_PAGE_PROBABILITY / PROBABILITY_PRECISION  
  183.                 if (action < NEW_PAGE_PROBABILITY) {  
  184.                     currentPage = random.nextInt(pages.length); // a random page  
  185.                     referrer = null;  
  186.                 } else {  
  187.                     referrer = pages[currentPage];  
  188.                     action = random.nextInt(linkMatrix[currentPage].length);  
  189.                     currentPage = linkMatrix[currentPage][action];  
  190.                 }  
  191.             }  
  192.   
  193.             connection.commit();  
  194.   
  195.         } catch (SQLException ex) {  
  196.             connection.rollback();  
  197.             throw ex;  
  198.         } finally {  
  199.             if (statement != null) {  
  200.                 statement.close();  
  201.             }  
  202.         }  
  203.     }  
  204.   
  205.     /** 
  206.      *  
  207.      * 验证结果是否正确 
  208.      */  
  209.   
  210.     private boolean verify() throws SQLException {  
  211.         String countAccessQuery = "SELECT COUNT(*) FROM Access";  
  212.         String sumPageviewQuery = "SELECT SUM(pageview) FROM Pageview";  
  213.         Statement st = null;  
  214.         ResultSet rs = null;  
  215.         try {  
  216.             st = connection.createStatement();  
  217.             rs = st.executeQuery(countAccessQuery);  
  218.             rs.next();  
  219.             long totalPageview = rs.getLong(1);  
  220.   
  221.             rs = st.executeQuery(sumPageviewQuery);  
  222.             rs.next();  
  223.             long sumPageview = rs.getLong(1);  
  224.   
  225.             LOG.info("totalPageview=" + totalPageview);  
  226.             LOG.info("sumPageview=" + sumPageview);  
  227.             /* 
  228.              * Access表中记录总数应该和Pageview表中pageview的和相等 
  229.              */  
  230.             return totalPageview == sumPageview && totalPageview != 0;  
  231.         } finally {  
  232.             if (st != null)  
  233.                 st.close();  
  234.             if (rs != null)  
  235.                 rs.close();  
  236.         }  
  237.     }  
  238.   
  239.     /** 
  240.      * Access表的记录对象 
  241.      */  
  242.     static class AccessRecord implements Writable, DBWritable {  
  243.         String url;  
  244.         String referrer;  
  245.         long time;  
  246.   
  247.         /* 
  248.          * 从输入流中反序列化需要的属性 
  249.          */  
  250.         public void readFields(DataInput in) throws IOException {  
  251.             this.url = Text.readString(in);  
  252.             this.referrer = Text.readString(in);  
  253.             this.time = in.readLong();  
  254.         }  
  255.   
  256.         /* 
  257.          * 将属性序列化到输出流中 
  258.          */  
  259.         public void write(DataOutput out) throws IOException {  
  260.             Text.writeString(out, url);  
  261.             Text.writeString(out, referrer);  
  262.             out.writeLong(time);  
  263.         }  
  264.   
  265.         public void readFields(ResultSet resultSet) throws SQLException {  
  266.             this.url = resultSet.getString(1);  
  267.             this.referrer = resultSet.getString(2);  
  268.             this.time = resultSet.getLong(3);  
  269.         }  
  270.   
  271.         public void write(PreparedStatement statement) throws SQLException {  
  272.             statement.setString(1, url);  
  273.             statement.setString(2, referrer);  
  274.             statement.setLong(3, time);  
  275.         }  
  276.         @Override  
  277.         public String toString() {  
  278.             return url + " " + referrer +" "+time;  
  279.         }  
  280.     }  
  281.   
  282.     /** 
  283.      * Pageview表的记录对象 
  284.      */  
  285.     static class PageviewRecord implements Writable, DBWritable {  
  286.         String url;  
  287.         long pageview;  
  288.   
  289.         public PageviewRecord(String url, long pageview) {  
  290.             this.url = url;  
  291.             this.pageview = pageview;  
  292.         }  
  293.   
  294.         public void readFields(DataInput in) throws IOException {  
  295.             this.url = Text.readString(in);  
  296.             this.pageview = in.readLong();  
  297.         }  
  298.   
  299.         public void write(DataOutput out) throws IOException {  
  300.             Text.writeString(out, url);  
  301.             out.writeLong(pageview);  
  302.         }  
  303.   
  304.         public void readFields(ResultSet resultSet) throws SQLException {  
  305.             this.url = resultSet.getString(1);  
  306.             this.pageview = resultSet.getLong(2);  
  307.         }  
  308.   
  309.         public void write(PreparedStatement statement) throws SQLException {  
  310.             statement.setString(1, url);  
  311.             statement.setLong(2, pageview);  
  312.         }  
  313.   
  314.         @Override  
  315.         public String toString() {  
  316.             return url + " " + pageview;  
  317.         }  
  318.     }  
  319.   
  320.     /** 
  321.      * Mapper从AccessRecord中摘录出url,然后将<url:1>输出给Reducer 
  322.      */  
  323.     static class PageviewMapper extends  
  324.             Mapper<LongWritable, AccessRecord, Text, LongWritable> {  
  325.   
  326.         LongWritable ONE = new LongWritable(1L);  
  327.   
  328.         @Override  
  329.         public void map(LongWritable key, AccessRecord value, Context context)  
  330.                 throws IOException, InterruptedException {  
  331.             System.out.println("key:" + key + ",value:" + value.toString());  
  332.             Text oKey = new Text(value.url);  
  333.             context.write(oKey, ONE);  
  334.         }  
  335.     }  
  336.   
  337.     /** 
  338.      * Reducer 
  339.      */  
  340.     static class PageviewReducer extends  
  341.             Reducer<Text, LongWritable, PageviewRecord, NullWritable> {  
  342.   
  343.         NullWritable n = NullWritable.get();  
  344.   
  345.         @Override  
  346.         public void reduce(Text key, Iterable<LongWritable> values,  
  347.                 Context context) throws IOException, InterruptedException {  
  348.   
  349.             long sum = 0L;  
  350.             for (LongWritable value : values) {  
  351.                 sum += value.get();  
  352.             }  
  353.             context.write(new PageviewRecord(key.toString(), sum), n);  
  354.         }  
  355.     }  
  356.   
  357.     public int run(String[] args) throws Exception {  
  358.   
  359.         String driverClassName = DRIVER_CLASS;  
  360.         String url = DB_URL;  
  361.   
  362.         if (args.length > 1) {  
  363.             driverClassName = args[0];  
  364.             url = args[1];  
  365.         }  
  366.   
  367.         initialize(driverClassName, url);  
  368.         Configuration conf = getConf();  
  369.           
  370.         //为MR配置数据库信息用以读取和写入  
  371.         DBConfiguration.configureDB(conf, driverClassName, url, DB_USER,  
  372.                 DB_PASSWORD);  
  373.   
  374.         Job job = new Job(conf);  
  375.   
  376.         job.setJobName("Count Pageviews of URLs");  
  377.         job.setJarByClass(DBOperator.class);  
  378.         job.setMapperClass(PageviewMapper.class);  
  379.         job.setCombinerClass(LongSumReducer.class);  
  380.         job.setReducerClass(PageviewReducer.class);  
  381.   
  382.         DBInputFormat.setInput(job, AccessRecord.class"Access"null"url",  
  383.                 AccessFieldNames);  
  384.   
  385.         DBOutputFormat.setOutput(job, "Pageview", PageviewFieldNames);  
  386.   
  387.         job.setMapOutputKeyClass(Text.class);  
  388.         job.setMapOutputValueClass(LongWritable.class);  
  389.   
  390.         job.setOutputKeyClass(PageviewRecord.class);  
  391.         job.setOutputValueClass(NullWritable.class);  
  392.         int ret;  
  393.         try {  
  394.             ret = job.waitForCompletion(true) ? 0 : 1;  
  395.             boolean correct = verify();  
  396.             if (!correct) {  
  397.                 throw new RuntimeException("Evaluation was not correct!");  
  398.             }else{  
  399.                 System.out.println("calculate success");  
  400.             }  
  401.         } finally {  
  402.             shutdown();  
  403.         }  
  404.         return ret;  
  405.     }  
  406.   
  407.     public static void main(String[] args) throws Exception {  
  408.         int ret = ToolRunner.run(new DBOperator(), args);  
  409.         System.exit(ret);  
  410.     }  
  411.   
  412. }  


一些Python脚本保存数据库中,今天需要将MySQL数据库中,“Python XXXX.py”修改为绝对路径,即“/usr/bin/python XXXX.py”,这里就需要用到MySQL的字符串连接函数CONCAT


CONCAT(str1,str2)
返回字符串str1,str2连接后的结果,
例如原表:
mysql> select * from student;
+----+---------+--------+------+--------+-------+
| id | sid     | name   | cid  | cname  | score |
+----+---------+--------+------+--------+-------+
|  1 | 2005001 | 张三   | 0001 | 数学   |    69 |
|  2 | 2005002 | 李四   | 0001 | 数学   |    89 |
|  3 | 2005001 | 张三   | 0001 | 数学   |    69 |
+----+---------+--------+------+--------+-------+
使用CONCAT函数查询
mysql> select CONCAT('H',name) from student;
+------------------+
| CONCAT('H',name) |
+------------------+
| H张三            |
| H李四            |
| H张三            |
+------------------+
使用CONCAT函数更新
mysql> update student set name =CONCAT('A',name) where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


mysql> select * from student;           
+----+---------+---------+------+--------+-------+
| id | sid     | name    | cid  | cname  | score |
+----+---------+---------+------+--------+-------+
|  1 | 2005001 | A张三   | 0001 | 数学   |    69 |
|  2 | 2005002 | 李四    | 0001 | 数学   |    89 |
|  3 | 2005001 | 张三    | 0001 | 数学   |    69 |
+----+---------+---------+------+--------+-------+


MySQL还内置了一些非常又有的字符串截取函数:
1、left(str, length) 截取左边的字符串
说明:left(被截取字段,截取长度) 
mysql> select Left(name,2) from student where id=1;
+--------------+
| Left(name,2) |
+--------------+
| A张          |
+--------------+
2、right(str, length) 截取右边的字符串
说明:right(被截取字段,截取长度) 
mysql> select right(name,2) from student where id=1;
+---------------+
| right(name,2) |
+---------------+
| 张三          |
+---------------+
3、 substring(str, pos, length) 从指定位置截取指定长度的字符串
说明:substring(被截取字段,从第几位开始截取) 
mysql> select substring(name,2,1) from student where id=1; 
+---------------------+
| substring(name,2,1) |
+---------------------+
| 张                  |
+---------------------+
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值