设为首页 收藏本站
查看: 716|回复: 0

[经验分享] Hadoop中的数据库访问

[复制链接]

尚未签到

发表于 2016-12-6 11:15:26 | 显示全部楼层 |阅读模式
Hadoop主要用来对非结构化或半结构化(HBase)数据进行存储和分析,而结构化的数据则一般使用数据库来进行存储和访问。本文的主要内容则是讲述如何将Hadoop与现有的数据库结合起来,在Hadoop应用程序中访问数据库中的文件。
 
1.DBInputFormat
DBInputFormatHadoop0.19.0开始支持的一种输入格式,包含在包org.apache.hadoop.mapred.lib.db中,主要用来与现有的数据库系统进行交互,包括MySQLPostgreSQLOracle等几个数据库系统。DBInputFormatHadoop应用程序中通过数据库供应商提供的JDBC接口来与数据库进行交互,并且可以使用标准的SQL来读取数据库中的记录。在使用DBInputFormat之前,必须将要使用的JDBC驱动拷贝到分布式系统各个节点的$HADOOP_HOME/lib/目录下。
DBInputFormat类中包含以下三个内置类:
1protected class DBRecordReaderimplements RecordReader<LongWritable, T>:用来从一张数据库表中读取一条条元组记录。
2public staticclass NullDBWritable implements DBWritable, Writable:主要用来实现DBWritable接口。
3protected staticclass DBInputSplit implements InputSplit:主要用来描述输入元组集合的范围,包括startend两个属性,start用来表示第一条记录的索引号,end表示最后一条记录的索引号。
其中DBWritable接口与Writable接口比较类似,也包含writereadFields两个函数,只是函数的参数有所不同。DBWritable中的两个函数分别为:
public voidwrite(PreparedStatement statement) throws SQLException;
public voidreadFields(ResultSet resultSet) throws SQLException;
这两个函数分别用来给java.sql.PreparedStatement设置参数,以及从java.sql.ResultSet中读取一条记录,熟悉Java JDBC用法的应该对这两个类的用法比较了解。
 
2.使用DBInputFormat读取数据库表中的记录
上文已经对DBInputFormat以及其中的相关内置类作了简单介绍,下面对怎样使用DBInputFormat读取数据库记录进行详细的介绍,具体步骤如下:
1.使用DBConfiguration.configureDB (JobConfjob, String driverClass, String dbUrl, String userName, String passwd)函数配置JDBC驱动,数据源,以及数据库访问的用户名和密码。例如MySQL数据库的JDBC的驱动为“com.mysql.jdbc.Driver”,数据源可以设置为“jdbc:mysql://localhost/mydb”,其中mydb可以设置为所需要访问的数据库。
2.使用DBInputFormat.setInput(JobConfjob, Class<? extends DBWritable> inputClass, String tableName, Stringconditions, String orderBy, String... fieldNames)函数对要输入的数据进行一些初始化设置,包括输入记录的类名(必须实现了DBWritable接口)、数据表名、输入数据满足的条件、输入顺序、输入的属性列。也可以使用重载的函数setInput(JobConfjob, Class<? extends DBWritable> inputClass, String inputQuery, StringinputCountQuery)进行初始化,区别在于后者可以直接使用标准SQL进行初始化,具体可以参考Hadoop API中的讲解。
3.按照普通Hadoop应用程序的格式进行配置,包括Mapper类、Reducer类、输入输出文件格式等,然后调用JobClient.runJob(conf)
 
3.使用示例
假设MySQL数据库中有数据库school,其中的teacher数据表定义如下:
DROP TABLE IFEXISTS `school`.`teacher`;
CREATE TABLE  `school`.`teacher` (
  `id` int(11) default NULL,
  `name` char(20) default NULL,
  `age` int(11) default NULL,
  `departmentID` int(11) default NULL
) ENGINE=InnoDBDEFAULT CHARSET=latin1;
 
首先给出实现了DBWritable接口的TeacherRecord类:
public class TeacherRecord implementsWritable, DBWritable{
 
      int id;
      String name;
      int age;
      int departmentID;
     
      @Override
      public voidreadFields(DataInput in) throws IOException {
             // TODO Auto-generatedmethod stub
             this.id = in.readInt();
             this.name = Text.readString(in);
             this.age = in.readInt();
             this.departmentID =in.readInt();
      }
 
      @Override
      public void write(DataOutputout) throws IOException {
             // TODO Auto-generatedmethod stub
             out.writeInt(this.id);
             Text.writeString(out, this.name);
             out.writeInt(this.age);
             out.writeInt(this.departmentID);
      }
 
      @Override
      public voidreadFields(ResultSet result) throws SQLException {
             // TODO Auto-generatedmethod stub
             this.id = result.getInt(1);
             this.name =result.getString(2);
             this.age = result.getInt(3);
             this.departmentID =result.getInt(4);
      }
 
      @Override
      public voidwrite(PreparedStatement stmt) throws SQLException {
             // TODO Auto-generatedmethod stub
             stmt.setInt(1, this.id);
             stmt.setString(2, this.name);
             stmt.setInt(3, this.age);
             stmt.setInt(4, this.departmentID);
      }
 
      @Override
      public String toString() {
             // TODO Auto-generatedmethod stub
             return new String(this.name+ " " + this.age + " " + this.departmentID);
      }
 
}
 
利用DBAccessMapper读取一条条记录:
public class DBAccessMapperextends MapReduceBase implements
Mapper<LongWritable,TeacherRecord, LongWritable, Text> {
 
      @Override
      public void map(LongWritablekey, TeacherRecord value,
                    OutputCollector<LongWritable,Text> collector, Reporter reporter)
                    throws IOException {
             // TODO Auto-generatedmethod stub
collector.collect(newLongWritable(value.id),
 new Text(value.toString()));
      }
     
}
 
Main函数如下:
public class DBAccess {
 
      public static voidmain(String[] args) throws IOException {
             JobConf conf = newJobConf(DBAccess.class);
             conf.setOutputKeyClass(LongWritable.class);
             conf.setOutputValueClass(Text.class);
 
             conf.setInputFormat(DBInputFormat.class);
             FileOutputFormat.setOutputPath(conf,new Path("dboutput"));
            
             DBConfiguration.configureDB(conf,"com.mysql.jdbc.Driver",
                       "jdbc:mysql://localhost/school","root","123456");
 
             String [] fields = {"id","name", "age", "departmentID"};
             DBInputFormat.setInput(conf,TeacherRecord.class, "teacher",
                        null, "id", fields);
            
             conf.setMapperClass(DBAccessMapper.class);
             conf.setReducerClass(IdentityReducer.class);
            
             JobClient.runJob(conf);
      }
 
}
 
该示例从teacher表中读取所有记录,并以TextOutputFormat的格式输出到dboutput目录下,输出格式为<”id”, “nameage departmentID”>
 
4.使用DBOutputFormat向数据库中写记录
DBOutputFormat将计算结果写回到一个数据库,同样先调用DBConfiguration.configureDB()函数进行数据库配置,然后调用函数DBOutputFormat.setOutput (JobConf job, String tableName, String... fieldNames)进行初始化设置,包括数据库表名和属性列名。同样,在将记录写回数据库之前,要先实现DBWritable接口。每个DBWritable的实例在传递给Reducer中的OutputCollector时都将调用其中的write(PreparedStatementstmt)方法。在Reduce过程结束时,PreparedStatement中的对象将会被转化成SQL语句中的INSERT语句,从而插入到数据库中。
 
5.总结
DBInputFormatDBOutputFormat提供了一个访问数据库的简单接口,虽然接口简单,但应用广泛。例如,可以将现有数据库中的数据转储到Hadoop中,由Hadoop进行分布式计算,通过Hadoop对海量数据进行分析,然后将分析后的结果转储到数据库中。在搜索引擎的实现中,可以通过Hadoop将爬行下来的网页进行链接分析,评分计算,建立倒排索引,然后存储到数据库中,通过数据库进行快速搜索。虽然上述的数据库访问接口已经能满足一般的数据转储功能,但是仍然存在一些限制不足,例如并发访问、数据表中的键必须要满足排序要求等,还需Hadoop社区的人员进行改进和优化。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-310494-1-1.html 上篇帖子: HADOOP SHUFFLE(转载) 下篇帖子: hadoop 优化的一些点
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表