MapReduce与MySQL交互

  MapReduce技术推出后,曾遭到关系数据库研究者的挑剔和批评,认为MapReduce不具备有类似于关系数据库中的结构化数据存储和处理能力。为此,Google和MapReduce社区进行了很多努力。一方面,他们设计了类似于关系数据中结构化数据表的技术(Google的BigTable,Hadoop的HBase)提供一些粗粒度的结构化数据存储和处理能力;另一方面,为了增强与关系数据库的集成能力,Hadoop MapReduce提供了相应的访问关系数据库库的编程接口。

  MapReduce与MySQL交互的整体架构如下图所示。

 

图2-1整个环境的架构

  具体到MapReduce框架读/写数据库,有2个主要的程序分别是 DBInputFormatDBOutputFormat,DBInputFormat 对应的是SQL语句select,而DBOutputFormat 对应的是 Inster/update,使用DBInputFormat和DBOutputForma时候需要实现InputFormat这个抽象类,这个抽象类含有getSplits()和createRecordReader()抽象方法,在DBInputFormat类中由 protected String getCountQuery() 方法传入结果集的个数,getSplits()方法再确定输入的切分原则,利用SQL中的 LIMIT 和 OFFSET 进行切分获得数据集的范围 ,请参考DBInputFormat源码中public InputSplit[] getSplits(JobConf job, int chunks) throws IOException的方法,在DBInputFormat源码中createRecordReader()则可以按一定格式读取相应数据。

      1)建立关系数据库连接

  • DBConfiguration:提供数据库配置和创建连接的接口。

      DBConfiguration类中提供了一个静态方法创建数据库连接:

 

public static void configureDB(Job job,String driverClass,String dbUrl,String userName,String Password)

 

      其中,job为当前准备执行的作业,driverClasss为数据库厂商提供的访问其数据库的驱动程序,dbUrl为运行数据库的主机的地址,userName和password分别为数据库提供访问地用户名和相应的访问密码。

      2)相应的从关系数据库查询和读取数据的接口

  • DBInputFormat:提供从数据库读取数据的格式。
  • DBRecordReader:提供读取数据记录的接口。

  3)相应的向关系数据库直接输出结果的编程接口

  • DBOutputFormat:提供向数据库输出数据的格式。
  • DBRecordWrite:提供数据库写入数据记录的接口。

  数据库连接完成后,即可完成从MapReduce程序向关系数据库写入数据的操作。为了告知数据库将写入哪个表中的哪些字段,DBOutputFormat中提供了一个静态方法来指定需要写入的数据表和字段:

 

public static void setOutput(Job job,String tableName,String ... fieldName)

 

      其中,tableName指定即将写入的数据表,后续参数将指定哪些字段数据将写入该表。

1.1 从数据库中输入数据

      虽然Hadoop允许从数据库中直接读取数据记录作为MapReduce的输入,但处理效率较低,而且大量频繁地从MapReduce程序中查询读取关系数据库可能会大大增加数据库访问负载,因此DBInputFormat仅适合读取小量数据记录计算和应用不适合数据仓库联机数据分析大量数据读取处理

      读取大量数据记录一个更好的解决办法是:用数据库中的Dump工具将大量待分析数据输出文本数据文件,并上载到HDFS中进行处理。

 

      1)首先创建要读入的数据

  • Windows环境

  首先创建数据库"school",使用下面命令进行:

 

create database school;

 

      然后通过以下几句话,把我们事先准备好的sql语句(student.sql事先放到了D盘目录)导入到刚创建的"school"数据库中。用到的命令如下:

 

use school;

source d:\student.sql

 

      "student.sql"中的内容如下所示:

 

DROP TABLE IF EXISTS `school`.`student`;

 

CREATE TABLE `school`.`student` (

`id` int(11) NOT NULL default '0',

`name` varchar(20) default NULL,

`sex` varchar(10) default NULL,

`age` int(10) default NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

INSERT INTO `student` VALUES ('201201', '张三', '男', '21');

INSERT INTO `student` VALUES ('201202', '李四', '男', '22');

INSERT INTO `student` VALUES ('201203', '王五', '女', '20');

INSERT INTO `student` VALUES ('201204', '赵六', '男', '21');

INSERT INTO `student` VALUES ('201205', '小红', '女', '19');

INSERT INTO `student` VALUES ('201206', '小明', '男', '22');

 

      执行结果如下所示:

 

 

      查询刚才创建的数据库表"student"的内容。

 

 

      结果发现显示是乱码,记得我当时是设置的UTF-8,怎么就出现乱码了呢?其实我们使用的操作系统的系统为中文,且它的默认编码是gbk,而MySQL的编码有两种,它们分别是:

  【client】:客户端的字符集。客户端默认字符集。当客户端向服务器发送请求时,请求以该字符集进行编码。

  【mysqld】:服务器字符集,默认情况下所采用的。

 

      找到安装MySQL目录,比如我们的安装目录为:

 

E:\HadoopWorkPlat\MySQL Server 5.5

 

      从中找到"my.ini"配置文件,最终发现my.ini里的2个character_set把client改成gbk,把server改成utf8就可以了。

    【client】端:

 

[client]

port=3306

[mysql]

default-character-set=gbk

 

    【mysqld】端:

 

[mysqld]

# The default character set that will be used when a new schema or table is

# created and no character set is defined

character-set-server=utf8

 

      按照上面修改完之后,重启MySQL服务。

 

 

      此时在Windows下面的数据库表已经准备完成了。

 

  • Linux环境

  首先通过"FlashFXP"把我们刚才的"student.sql"上传到"/home/hadoop"目录下面,然后按照上面的语句创建"school"数据库。

 

  

      查看我们上传的"student.sql"内容:

 

  

      创建"school"数据库,并导入"student.sql"语句。

 

  

 

      显示数据库"school"中的表"student"信息。

 

  

     显示表"student"中的内容。

 

  

 

      到此为止在"Windows"和"Linux"两种环境下面都创建了表"student"表,并初始化了值。下面就开始通过MapReduce读取MySQL库中表"student"的信息。

      2)使MySQL能远程连接

      MySQL默认是允许别的机器进行远程访问地,为了使Hadoop集群能访问MySQL数据库,所以进行下面操作。

  • 用MySQL用户"root"登录。

 

mysql -u root -p

 

  • 使用下面语句进行授权,赋予任何主机访问数据的权限。

 

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'hadoop' WITH GRANT OPTION;

 

  • 刷新,使之立即生效。

 

FLUSH PRIVILEGES;

 

      执行结果如下图。

      Windows下面:

 

  

      Linux下面:

 

  

      到目前为止,如果连接Win7上面的MySQL数据库还不行,大家还应该记得前面在Linux下面关掉了防火墙但是我们在Win7下对防火墙并没有做任何处理,如果不对防火墙做处理,即使执行了上面的远程授权,仍然不能连接。下面是设置Win7上面的防火墙,使远程机器能通过3306端口访问MySQL数据库。

      解决方案:只要在'入站规则'上建立一个3306端口即可。

  执行顺序控制面板à管理工具à高级安全的Windows防火墙à入站规则

  然后新建规则à选择'端口'à在'特定本地端口'上输入一个'3306' à选择'允许连接'=>选择'域'、'专用'、'公用'=>给个名称,如:MySqlInput

 

      3)对JDBC的Jar包处理

      因为程序虽然用Eclipse编译运行但最终要提交到Hadoop集群上,所以JDBC的jar必须放到Hadoop集群中。有两种方式:

      (1)在每个节点下的${HADOOP_HOME}/lib下添加该包,重启集群,一般是比较原始的方法。

      我们的Hadoop安装包在"/usr/hadoop",所以把Jar放到"/usr/hadoop/lib"下面,然后重启,记得是Hadoop集群中所有的节点都要放,因为执行分布式是程序是在每个节点本地机器上进行。

      (2)在Hadoop集群的分布式文件系统中创建"/lib"文件夹,并把我们的的JDBC的jar包上传上去,然后在主程序添加如下语句,就能保证Hadoop集群中所有的节点都能使用这个jar包。因为这个jar包放在了HDFS上,而不是本地系统,这个要理解清楚。

 

DistributedCache.addFileToClassPath(new Path("/lib/mysql-connector-java-5.1.18-bin.jar"), conf);

 

      我们用的JDBC的jar如下所示:

 

mysql-connector-java-5.1.18-bin.jar

 

      通过Eclipse下面的DFS Locations进行创建"/lib"文件夹,并上传JDBC的jar包。执行结果如下:

  

      备注我们这里采用第二种方式

      4)源程序代码如下所示

 

package com.hebut.mr;

 

import java.io.IOException;

import java.io.DataInput;

import java.io.DataOutput;

import j

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值