Hadoop与MongoDB集成:MapReduce作业实战
1. 执行首个示例MapReduce作业
在这个部分,我们将学习如何从源代码构建mongo - hadoop连接器,并设置Hadoop以独立模式运行示例。该连接器是使用Mongo中的数据在Hadoop上运行Hadoop MapReduce作业的核心。
准备工作
- Hadoop发行版 :使用Apache Hadoop(http://hadoop.apache.org/),安装在Ubuntu Linux上。生产环境中,Apache Hadoop通常运行在Linux环境,Windows未经过生产系统测试,但开发时可以使用。Windows用户可安装VirtualBox(https://www.virtualbox.org/)等虚拟化环境,在其中设置Linux环境并安装Hadoop。
- Git客户端 :用于将mongo - hadoop连接器的仓库克隆到本地文件系统,参考http://git - scm.com/book/en/Getting - Started - Installing - Git安装。
- MongoDB :需安装在操作系统上,参考http://docs.mongodb.org/manual/installation/进行安装,并启动监听端口27017的mongod实例。
- 知识储备 :不需要是Hadoop专家,但熟悉Hadoop和MapReduce概念会有帮助,可从http://en.wikipedia.org/wiki/MapReduce获取MapReduce编程的相关信息。
操作步骤
-
安装Java、Hadoop及所需包
- 检查Java安装情况,在操作系统命令提示符输入:
$ javac –version
- 若程序未执行,提示需要包含javac的包,则安装Java:
$ sudo apt - get install default - jdk
- 下载Hadoop :从http://www.apache.org/dyn/closer.cgi/hadoop/common/下载版本2.4.0(或mongo - hadoop连接器支持的最新版本)。
- 解压Hadoop并配置
$ tar –xvzf <下载的.tar.gz文件名>
$ cd <解压目录>
打开
etc/hadoop/hadoop - env.sh
文件,将
export JAVA_HOME = ${JAVA_HOME}
替换为
export JAVA_HOME = /usr/lib/jvm/default - java
。
4.
克隆mongo - hadoop连接器代码
$ git clone https://github.com/mongodb/mongo - hadoop.git
$ cd mongo - hadoop
- 创建软链接
$ ln –s <Hadoop安装目录> ~/hadoop - binaries
例如,若Hadoop解压到主目录:
$ ln –s ~/hadoop - 2.4.0 ~/hadoop - binaries
默认情况下,mongo - hadoop连接器会在
~/hadoop - binaries
文件夹下查找Hadoop发行版。
6.
构建mongo - hadoop连接器
$./gradlew jar –Phadoop_version='2.4'
构建过程需要一些时间。
7.
导入数据到Mongo集合
假设mongod实例正在运行并监听端口27017,当前目录为mongo - hadoop连接器代码库的根目录,执行:
$ mongoimport - c yield_historical.in - d mongo_hadoop --drop examples/treasury_yield/src/main/resources/yield_historical_in.json
- 复制jar文件到lib目录
$ wget http://repo1.maven.org/maven2/org/mongodb/mongo - java - driver/2.12.0/mongo - java - driver - 2.12.0.jar
$ cp core/build/libs/mongo - hadoop - core - 1.2.1 - SNAPSHOT - hadoop_2.4.jar ~/hadoop - binaries/hadoop - 2.4.0/lib/
$ mv mongo - java - driver - 2.12.0.jar ~/hadoop - binaries/hadoop - 2.4.0/lib
- 执行MapReduce作业
~/hadoop - binaries/hadoop - 2.4.0/bin/hadoop jar examples/treasury_yield/build/libs/treasury_yield - 1.2.1 - SNAPSHOT - hadoop_2.4.jar \
com.mongodb.hadoop.examples.treasury.TreasuryYieldXMLConfig \
- Dmongo.input.split_size = 8 - Dmongo.job.verbose = true \
- Dmongo.input.uri = mongodb://localhost:27017/mongo_hadoop.yield_historical.in \
- Dmongo.output.uri = mongodb://localhost:27017/mongo_hadoop.yield_historical.out
若输出中出现以下行,则表示MapReduce作业成功:
14/05/11 21:38:54 INFO mapreduce.Job: Job job_local1226390512_0001 completed successfully
- 查询输出集合
$ mongo
> use mongo_hadoop
switched to db mongo_hadoop
> db.yield_historical.out.find()
工作原理
- 安装Hadoop并非易事,但为了运行mongo - hadoop连接器示例,我们只需下载存档、解压并以独立模式运行MapReduce作业。
- 步骤1 - 6用于安装Hadoop,后续步骤克隆mongo - hadoop连接器代码并构建。
-
导入数据到
yield_historical.in集合作为MapReduce作业的输入。 -
执行Hadoop命令时,指定的jar文件包含实现国库收益率示例MapReduce操作的类,
com.mongodb.hadoop.examples.treasury.TreasuryYieldXMLConfig类是入口点。 -
mongo.input.uri和mongo.output.uri分别指定MapReduce操作的输入和输出集合。
2. 关键类分析
TreasuryYieldXMLConfig
类
该类是MapReduce方法的入口点,包含
main
方法。使用mongo - hadoop连接器编写Mongo的MapReduce作业时,主类必须继承
com.mongodb.hadoop.util.MongoTool
,该类实现了
org.apache.hadoop.Tool
接口。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ToolRunner;
import com.mongodb.hadoop.MongoConfig;
import com.mongodb.hadoop.util.MongoTool;
public class TreasuryYieldXMLConfig extends MongoTool {
static {
// 加载配置文件
}
public static void main(String[] args) throws Exception {
ToolRunner.run(new Configuration(), new TreasuryYieldXMLConfig(), args);
}
}
有一个静态块从
hadoop - local.xml
和
mongo - defaults.xml
两个XML文件加载配置。在构造函数中实例化
com.mongodb.hadoop.MongoConfig
,并设置输入输出格式、映射器和归约器类等重要配置。
映射器类
TreasuryYieldMapper
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Mapper;
import org.bson.BSONObject;
import java.io.IOException;
import java.util.Date;
public class TreasuryYieldMapper extends Mapper<Object, BSONObject, IntWritable, DoubleWritable> {
@Override
public void map(final Object pKey,
final BSONObject pValue,
final Context pContext)
throws IOException, InterruptedException {
final int year = ((Date) pValue.get("_id")).getYear() + 1900;
double bid10Year = ((Number) pValue.get("bc10Year")).doubleValue();
pContext.write(new IntWritable(year), new DoubleWritable(bid10Year));
}
}
映射器继承
org.apache.hadoop.mapreduce.Mapper
类,读取输入文档的
_id
值(日期)提取年份,获取
bc10Year
字段的双精度值,将年份作为键,双精度值作为值写入上下文。
归约器类
TreasuryYieldReducer
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Reducer;
import org.bson.BasicBSONObject;
import org.bson.BSONWritable;
import java.io.IOException;
import java.util.Iterator;
public class TreasuryYieldReducer extends Reducer<IntWritable, DoubleWritable, IntWritable, BSONWritable> {
@Override
public void reduce(final IntWritable pKey, final Iterable<DoubleWritable> pValues, final Context pContext)
throws IOException, InterruptedException {
int count = 0;
double sum = 0;
Iterator<DoubleWritable> iterator = pValues.iterator();
while (iterator.hasNext()) {
DoubleWritable value = iterator.next();
sum += value.get();
count++;
}
final double avg = sum / count;
BasicBSONObject output = new BasicBSONObject();
output.put("count", count);
output.put("avg", avg);
output.put("sum", sum);
pContext.write(pKey, new BSONWritable(output));
}
}
归约器继承
org.apache.hadoop.mapreduce.Reducer
类,输入为映射器的输出。对相同键的双精度值进行求和、计数,计算平均值,并将结果写入上下文。
3. 编写首个Hadoop MapReduce作业
接下来,我们将使用Hadoop MapReduce API编写首个MapReduce作业,并使用mongo - hadoop连接器从MongoDB获取数据。
准备工作
- 参考前面执行示例MapReduce作业的步骤设置mongo - hadoop连接器。
- 该项目是Maven项目,需安装Maven,在Ubuntu Linux上执行:
$ sudo apt - get install maven
操作步骤
-
从Packt网站下载
Java mongo - hadoop - mapreduce - test项目,该项目目标与之前使用MongoDB MapReduce框架的用例相同。 -
在项目根目录(包含
pom.xml文件)的命令提示符下执行:
$ mvn clean package
-
生成的
mongo - hadoop - mapreduce - test - 1.0.jar文件将保存在target目录。 -
假设CSV文件已导入
postalCodes集合,在项目根目录执行以下命令:
~/hadoop - binaries/hadoop - 2.4.0/bin/hadoop \
jar target/mongo - hadoop - mapreduce - test - 1.0.jar \
com.packtpub.mongo.cookbook.TopStateMapReduceEntrypoint \
- Dmongo.input.split_size = 8 \
- Dmongo.job.verbose = true \
- Dmongo.input.uri = mongodb://localhost:27017/test.postalCodes \
- Dmongo.output.uri = mongodb://localhost:27017/test.postalCodesHadoopmrOut
- MapReduce作业完成后,打开mongo shell并执行查询:
$ mongo
> db.postalCodesHadoopmrOut.find().sort({count: - 1}).limit(5)
- 将输出与之前使用MongoDB MapReduce框架的结果进行比较。
工作原理
-
项目包含三个类:
TopStateMapReduceEntrypoint、TopStateReducer和TopStatesMapper。 -
TopStatesMapper类的map方法将州名作为键,整数值1作为值写入上下文:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.bson.BSONObject;
import java.io.IOException;
public class TopStatesMapper extends Mapper<Object, BSONObject, Text, IntWritable> {
@Override
protected void map(Object key, BSONObject value, Context context) throws IOException, InterruptedException {
context.write(new Text((String) value.get("state")), new IntWritable(1));
}
}
-
TopStateReducer类对相同州名的整数值求和:
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import org.bson.BSONObject;
import org.bson.BasicBSONObject;
import org.bson.BSONWritable;
import java.io.IOException;
import java.util.Iterator;
public class TopStateReducer extends Reducer<Text, IntWritable, Text, BSONWritable> {
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
Iterator<IntWritable> iterator = values.iterator();
while (iterator.hasNext()) {
IntWritable value = iterator.next();
sum += value.get();
}
BSONObject object = new BasicBSONObject();
object.put("count", sum);
context.write(key, new BSONWritable(object));
}
}
-
TopStateMapReduceEntrypoint类的main方法设置配置并提交MapReduce作业:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.util.ToolRunner;
import com.mongodb.hadoop.MongoConfig;
import com.mongodb.hadoop.MongoInputFormat;
import com.mongodb.hadoop.MongoOutputFormat;
import com.mongodb.hadoop.io.BSONWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
public class TopStateMapReduceEntrypoint {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
MongoConfig config = new MongoConfig(conf);
config.setInputFormat(MongoInputFormat.class);
config.setMapperOutputKey(Text.class);
config.setMapperOutputValue(IntWritable.class);
config.setMapper(TopStatesMapper.class);
config.setOutputFormat(MongoOutputFormat.class);
config.setOutputKey(Text.class);
config.setOutputValue(BSONWritable.class);
config.setReducer(TopStateReducer.class);
ToolRunner.run(conf, new TopStateMapReduceEntrypoint(), args);
}
}
通过以上步骤,我们可以使用Hadoop和MongoDB进行数据处理和分析,实现MapReduce作业。后续还可以探索使用Hadoop Streaming用不同语言编写Map和Reduce函数。
Hadoop与MongoDB集成:MapReduce作业实战(续)
4. 代码结构与功能总结
| 类名 | 功能描述 | 关键代码片段 |
|---|---|---|
TreasuryYieldXMLConfig
|
MapReduce作业的入口点,继承
MongoTool
,加载配置并启动作业
|
java<br>static {<br> // 加载配置文件<br>}<br>public static void main(String[] args) throws Exception {<br> ToolRunner.run(new Configuration(), new TreasuryYieldXMLConfig(), args);<br>}<br>
|
TreasuryYieldMapper
|
从输入文档提取年份和
bc10Year
值,写入上下文
|
java<br>final int year = ((Date) pValue.get("_id")).getYear() + 1900;<br>double bid10Year = ((Number) pValue.get("bc10Year")).doubleValue();<br>pContext.write(new IntWritable(year), new DoubleWritable(bid10Year));<br>
|
TreasuryYieldReducer
|
对相同年份的
bc10Year
值求和、计数、计算平均值,写入上下文
|
java<br>int count = 0;<br>double sum = 0;<br>Iterator<DoubleWritable> iterator = pValues.iterator();<br>while (iterator.hasNext()) {<br> DoubleWritable value = iterator.next();<br> sum += value.get();<br> count++;<br>}<br>final double avg = sum / count;<br>BasicBSONObject output = new BasicBSONObject();<br>output.put("count", count);<br>output.put("avg", avg);<br>output.put("sum", sum);<br>pContext.write(pKey, new BSONWritable(output));<br>
|
TopStateMapReduceEntrypoint
| 设置MapReduce作业的配置并提交作业 |
java<br>Configuration conf = new Configuration();<br>MongoConfig config = new MongoConfig(conf);<br>config.setInputFormat(MongoInputFormat.class);<br>config.setMapperOutputKey(Text.class);<br>config.setMapperOutputValue(IntWritable.class);<br>config.setMapper(TopStatesMapper.class);<br>config.setOutputFormat(MongoOutputFormat.class);<br>config.setOutputKey(Text.class);<br>config.setOutputValue(BSONWritable.class);<br>config.setReducer(TopStateReducer.class);<br>ToolRunner.run(conf, new TopStateMapReduceEntrypoint(), args);<br>
|
TopStatesMapper
| 将州名作为键,值为1写入上下文 |
java<br>context.write(new Text((String) value.get("state")), new IntWritable(1));<br>
|
TopStateReducer
| 对相同州名的值求和,写入上下文 |
java<br>int sum = 0;<br>Iterator<IntWritable> iterator = values.iterator();<br>while (iterator.hasNext()) {<br> IntWritable value = iterator.next();<br> sum += value.get();<br>}<br>BSONObject object = new BasicBSONObject();<br>object.put("count", sum);<br>context.write(key, new BSONWritable(object));<br>
|
5. 流程图分析
graph TD;
A[开始] --> B[安装Java、Hadoop及所需包];
B --> C[下载Hadoop];
C --> D[解压Hadoop并配置];
D --> E[克隆mongo - hadoop连接器代码];
E --> F[创建软链接];
F --> G[构建mongo - hadoop连接器];
G --> H[导入数据到Mongo集合];
H --> I[复制jar文件到lib目录];
I --> J[执行MapReduce作业];
J --> K{作业是否成功};
K -- 是 --> L[查询输出集合];
K -- 否 --> M[检查配置和代码];
M --> J;
N[编写MapReduce作业] --> O[准备工作];
O --> P[下载项目];
P --> Q[执行mvn命令打包];
Q --> R[执行作业命令];
R --> S{作业是否成功};
S -- 是 --> T[查询结果并比较];
S -- 否 --> U[检查配置和代码];
U --> R;
该流程图展示了整个Hadoop与MongoDB集成实现MapReduce作业的流程,包括环境搭建、示例作业执行和自定义作业编写与执行等步骤。从开始安装Java、Hadoop等基础环境,到逐步构建mongo - hadoop连接器,导入数据,执行示例作业。之后是编写自定义MapReduce作业的流程,从准备工作到下载项目、打包、执行作业,最后根据作业是否成功进行相应处理。
6. 注意事项与常见问题
- 环境配置 :在安装Java、Hadoop和MongoDB时,要确保版本兼容。例如,mongo - hadoop连接器支持的Apache Hadoop版本为2.4.0,在下载和配置时需注意。
-
配置文件修改
:修改
etc/hadoop/hadoop - env.sh文件时,要准确替换JAVA_HOME的值,否则可能导致Hadoop无法正常启动。 -
数据导入
:使用
mongoimport导入数据时,要确保文件路径和集合名称正确,并且mongod实例正在运行并监听正确的端口。 - 代码编译和运行 :在使用Maven打包项目时,可能会遇到依赖下载失败的问题,可检查网络连接和Maven配置。执行作业时,若出现类找不到或配置错误,要仔细检查代码和配置文件。
7. 拓展应用
- 使用不同语言编写MapReduce函数 :可以使用Hadoop Streaming,通过标准输出(stdout)在程序和Hadoop MapReduce框架之间进行通信,实现用Python等不同语言编写Map和Reduce函数。
-
处理大规模数据
:可以结合Hadoop的分布式计算能力和MongoDB的存储能力,处理大规模数据。通过调整
mongo.input.split_size等参数,优化数据处理性能。 - 实时数据处理 :可以结合MongoDB的实时数据更新特性和Hadoop的流式处理框架,实现实时数据的处理和分析。
通过以上步骤和分析,我们可以深入理解Hadoop与MongoDB集成实现MapReduce作业的原理和方法,并且可以根据实际需求进行拓展和优化,实现更复杂的数据处理和分析任务。
超级会员免费看
923

被折叠的 条评论
为什么被折叠?



