Java 如何将两个映射器合并为一个减速器

Java 如何将两个映射器合并为一个减速器,java,hadoop,mapreduce,key-value,Java,Hadoop,Mapreduce,Key Value,我正在使用hadoop比较两个文件。我使用了两个映射器,其中每个文件指向一个映射和一个减缩器。第一个贴图将获得一个普通文本文件,第二个贴图器将在每行中获得一个具有此格式的文件: word 1 or -1 地图的输入为: public void map(LongWritable key, Text value, Context context) 第一张地图将是: key:word value:0 word 1 or -1 第二个地图绘制者将是: key:word value:0 wor

我正在使用hadoop比较两个文件。我使用了两个映射器,其中每个文件指向一个映射和一个减缩器。第一个贴图将获得一个普通文本文件,第二个贴图器将在每行中获得一个具有此格式的文件:

word 1 or -1
地图的输入为:

public void map(LongWritable key, Text value, Context context) 
第一张地图将是:

key:word value:0
word 1 or -1
第二个地图绘制者将是:

key:word value:0
word 1 or -1
减速器的输入为:

public void reduce(Text key, Iterable<IntWritable> values, Context context) 
context.write(key, new IntWritable(sum));
我得到的结果分别来自每个映射,我希望还原程序从两个映射中获得相同的键/值,并将其转化为一个结果。 这是代码

public class CompareTwoFiles extends Configured implements Tool {
static ArabicStemmer Stemmer=new ArabicStemmer();
String ArabicWord="";

public static class Map extends Mapper <LongWritable, Text, Text, IntWritable> {

int n=0;
private Text num = new Text();
private Text word = new Text();
@Override    
public void map(LongWritable key, Text value, Context context)  throws IOException, InterruptedException {

String line = value.toString();
String token="";

StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
token=tokenizer.nextToken();
Stemmer.stemWord(token);
word.set(token);
context.write(word,new IntWritable(0));
}
}
}

public static class Map2 extends Mapper <LongWritable, Text, Text, IntWritable> {
int n=0;
private Text word = new Text();  
@Override
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {

String token="";

if (line.contains("1") && !line.contains("-1"))
{
n=1;
}
else if (line.contains("-1"))
{
n=-1;
}
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
token=tokenizer.nextToken();
if(!(token.equals("1"))&& !(token.equals("-1")))
{word.set(token);
context.write(word,new IntWritable(n));
}
}
}
}

public static class Reduce extends  Reducer<Text, IntWritable, Text, IntWritable> {

Text sumT= new Text();
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
int num=0;
int[] intArr =new int[2];
boolean flag=false;
int i=0;

while (values.iterator().hasNext()) {            
sum += values.iterator().next().get();
}   

if(sum!=0){
context.write(key, new IntWritable(sum));
}   
}
}
public static void main(String[] args) throws Exception {
           int res = ToolRunner.run(new Configuration(), new CompareTwoFiles(), args);
System.exit(res);
}
@Override
public int run(String[] args) throws Exception {

Configuration conf = new Configuration();
conf.set("fs.defaultFS", "hdfs://localhost:8020");
conf.set("hadoop.job.ugi", "hdfs");
Job job = new Job(conf);
job.setJarByClass(CompareTwoFiles.class);
job.setJobName("compare");
job.setReducerClass(Reduce.class);
job.setMapperClass(Map.class);
job.setMapperClass(Map2.class);
job.setCombinerClass(Reduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
MultipleInputs.addInputPath(job, new Path(args[0]),
TextInputFormat.class, Map.class);
MultipleInputs.addInputPath(job, new Path(args[1]),
TextInputFormat.class, Map2.class); 
FileOutputFormat.setOutputPath(job, new Path(args[2]));
job.waitForCompletion(true);
return job.waitForCompletion(true) ? 0 : 1;
}
公共类CompareTofiles扩展配置的工具{
静态ArabicStemmer词干分析器=新的ArabicStemmer();
字符串ArabicWord=“”;
公共静态类映射扩展映射器{
int n=0;
private Text num=新文本();
私有文本字=新文本();
@凌驾
公共void映射(LongWritable键、文本值、上下文上下文)引发IOException、InterruptedException{
字符串行=value.toString();
字符串标记=”;
StringTokenizer标记器=新的StringTokenizer(行);
while(tokenizer.hasMoreTokens()){
token=tokenizer.nextToken();
stemmword(令牌);
word.set(令牌);
write(word,新的intwriteable(0));
}
}
}
公共静态类Map2扩展了Mapper{
int n=0;
私有文本字=新文本();
@凌驾
公共void映射(LongWritable键、文本值、上下文上下文)引发IOException、InterruptedException{
字符串标记=”;
if(line.contains(“-1”)&&!line.contains(“-1”))
{
n=1;
}
else if(第行包含(“-1”))
{
n=-1;
}
StringTokenizer标记器=新的StringTokenizer(行);
while(tokenizer.hasMoreTokens()){
token=tokenizer.nextToken();
如果(!(令牌等于(“-1”)&&(!(令牌等于(“-1”))
{word.set(令牌);
write(word,新的intwriteable(n));
}
}
}
}
公共静态类Reduce扩展Reducer{
Text sumT=新文本();
@凌驾
公共void reduce(文本键、Iterable值、上下文上下文)引发IOException、InterruptedException{
整数和=0;
int num=0;
int[]intArr=新的int[2];
布尔标志=假;
int i=0;
while(values.iterator().hasNext()){
sum+=values.iterator().next().get();
}   
如果(总和=0){
write(key,newintwriteable(sum));
}   
}
}
公共静态void main(字符串[]args)引发异常{
int res=ToolRunner.run(新配置(),新比较文件(),args);
系统退出(res);
}
@凌驾
公共int运行(字符串[]args)引发异常{
Configuration conf=新配置();
conf.set(“fs.defaultFS”hdfs://localhost:8020");
conf.set(“hadoop.job.ugi”、“hdfs”);
作业=新作业(配置);
job.setJarByClass(compareTofiles.class);
job.setJobName(“比较”);
job.setReducerClass(Reduce.class);
job.setMapperClass(Map.class);
job.setMapperClass(Map2.class);
job.setCombinerClass(Reduce.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
多个输入。addInputPath(作业,新路径(args[0]),
TextInputFormat.class,Map.class);
多个输入。addInputPath(作业,新路径(args[1]),
TextInputFormat.class,Map2.class);
setOutputPath(作业,新路径(args[2]);
job.waitForCompletion(true);
返回作业。waitForCompletion(true)?0:1;
}
我得到的结果是这样的:

第一张地图
w1 0
w20
第二张地图
w1 1
w23
w3-1


MapReduce的整个概念是,映射器可以为每个键发出一个值,在您的示例中为每个字发出一个值,然后每个键将有一个减缩器(在您的示例中,一个减缩器应该接收一个字的所有计数)。也就是说,在映射器中,您将编写类似于[key,value]的内容对于您注册的每个单词。一次运行只能有一个映射器类和一个还原器类

在您的情况下,MapReduce听起来并不适合您的问题。将一个文件与另一个文件进行比较并不一定是一个通过分区和并行化自然提高效率的问题。您可以做的是对文本文件进行分区,并发送一个文本分区和整个
word 1或-1
文件发送到每个映射器。然后还原器将计算每个单词的总和/值


也可以在此处发布您的映射器和Reducer类。

我已经发布了代码,我的意思是我希望两个映射器的结果在Reducer中一起计算,而不是每个映射器单独计算。是否可能?是的,所有映射器的结果总是在Reducer中合并,MR所做的是收集具有相同键的所有映射输出,然后将输出值列表交给一个reduce实例。因此,每个作业只能有一个映射器类,但是您的代码首先注册
Map.class
,然后注册
Map2.class
,导致第一个被第二个覆盖。也就是说,仅使用
Map2.class
。通过您发布的输出,将对于w1、w2和w3.job.setNumReduceTasks(1),都是一个reduce对象;使用此对象可以使用一个reducer,并且来自两个映射器的所有数据都会进入其中。不幸的是,我尝试过它,但它不起作用。