使用Hadoop MapReduce排序字数

使用Hadoop MapReduce排序字数,hadoop,mapreduce,word-count,parallel-processing,Hadoop,Mapreduce,Word Count,Parallel Processing,我是MapReduce的新手,我完成了一个Hadoop字数计算示例 在该示例中,它生成单词计数的未排序文件(带有键值对)。那么,通过将另一个MapReduce任务与先前的任务组合起来,是否可以按单词出现次数对其进行排序?Hadoop MapReduce wordcount示例的输出按键进行排序。所以输出应该按字母顺序排列 使用Hadoop,您可以创建自己的关键对象,这些对象实现WritableComparable接口,允许您覆盖compareTo方法。这允许您控制排序顺序 要创建按发生次数排序的

我是MapReduce的新手,我完成了一个Hadoop字数计算示例


在该示例中,它生成单词计数的未排序文件(带有键值对)。那么,通过将另一个MapReduce任务与先前的任务组合起来,是否可以按单词出现次数对其进行排序?

Hadoop MapReduce wordcount示例的输出按键进行排序。所以输出应该按字母顺序排列

使用Hadoop,您可以创建自己的关键对象,这些对象实现
WritableComparable
接口,允许您覆盖
compareTo
方法。这允许您控制排序顺序

要创建按发生次数排序的输出,您可能需要添加另一个MapReduce作业来处理第一个作业的输出,正如您所说的。第二项工作将非常简单,甚至可能不需要reduce阶段。您只需要实现自己的
Writable
key对象来包装单词及其频率。自定义可写文件如下所示:

 public class MyWritableComparable implements WritableComparable {
       // Some data
       private int counter;
       private long timestamp;

       public void write(DataOutput out) throws IOException {
         out.writeInt(counter);
         out.writeLong(timestamp);
       }

       public void readFields(DataInput in) throws IOException {
         counter = in.readInt();
         timestamp = in.readLong();
       }

       public int compareTo(MyWritableComparable w) {
         int thisValue = this.value;
         int thatValue = ((IntWritable)o).value;
         return (thisValue < thatValue ? -1 : (thisValue==thatValue ? 0 : 1));
       }
     }
公共类MyWritableComparable实现了WritableComparable{
//一些数据
专用int计数器;
私有长时间戳;
public void write(DataOutput out)引发IOException{
输出、写入(计数器);
out.writeLong(时间戳);
}
public void readFields(DataInput in)引发IOException{
计数器=in.readInt();
timestamp=in.readLong();
}
公共整数比较(MyWritableW){
int thisValue=this.value;
int thatValue=((intwriteable)o).value;
返回(thisValue
我从一本书中摘取了这个例子


您可能应该重写
hashCode
equals
toString

在Hadoop中,排序是在Map和Reduce阶段之间完成的。一种按单词出现情况排序的方法是使用一个自定义的组比较器,它不会对任何内容进行分组;因此,每次调用reduce都只是关键和一个值

public class Program {
   public static void main( String[] args) {

      conf.setOutputKeyClass( IntWritable.class);
      conf.setOutputValueClass( Text.clss);
      conf.setMapperClass( Map.class);
      conf.setReducerClass( IdentityReducer.class);
      conf.setOutputValueGroupingComparator( GroupComparator.class);   
      conf.setNumReduceTasks( 1);
      JobClient.runJob( conf);
   }
}

public class Map extends MapReduceBase implements Mapper<Text,IntWritable,IntWritable,Text> {

   public void map( Text key, IntWritable value, OutputCollector<IntWritable,Text>, Reporter reporter) {
       output.collect( value, key);
   }
}

public class GroupComaprator extends WritableComparator {
    protected GroupComparator() {
        super( IntWritable.class, true);
    }

    public int compare( WritableComparable w1, WritableComparable w2) {
        return -1;
    }
}
公共类程序{
公共静态void main(字符串[]args){
conf.setOutputKeyClass(IntWritable.class);
conf.setOutputValueClass(Text.clss);
conf.setMapperClass(Map.class);
conf.setReducerClass(IdentityReducer.class);
conf.setOutputValueGroupingComparator(GroupComparator.class);
conf.setNumReduceTasks(1);
runJob(conf);
}
}
公共类映射扩展MapReduceBase实现映射器{
公共void映射(文本键、IntWritable值、OutputCollector、Reporter){
输出。收集(值、键);
}
}
公共类GroupComaprator扩展了WritableComparator{
受保护的GroupComparator(){
super(intwriteable.class,true);
}
公共整数比较(可写可比w1,可写可比w2){
返回-1;
}
}

在简单字数映射reduce程序中,我们得到的输出按字数排序。样本输出可以是:
苹果1号
男孩30
第2类
青蛙20
斑马1号
如果希望根据字数对输出进行排序,即采用以下格式
1个苹果
1匹斑马
2类
20青蛙
30个男孩
您可以使用下面的mapper和reducer创建另一个MR程序,其中输入将是从简单的字数计算程序获得的输出

class Map1 extends MapReduceBase implements Mapper<Object, Text, IntWritable, Text>
{
    public void map(Object key, Text value, OutputCollector<IntWritable, Text> collector, Reporter arg3) throws IOException 
    {
        String line = value.toString();
        StringTokenizer stringTokenizer = new StringTokenizer(line);
        {
            int number = 999; 
            String word = "empty";

            if(stringTokenizer.hasMoreTokens())
            {
                String str0= stringTokenizer.nextToken();
                word = str0.trim();
            }

            if(stringTokenizer.hasMoreElements())
            {
                String str1 = stringTokenizer.nextToken();
                number = Integer.parseInt(str1.trim());
            }

            collector.collect(new IntWritable(number), new Text(word));
        }

    }

}


class Reduce1 extends MapReduceBase implements Reducer<IntWritable, Text, IntWritable, Text>
{
    public void reduce(IntWritable key, Iterator<Text> values, OutputCollector<IntWritable, Text> arg2, Reporter arg3) throws IOException
    {
        while((values.hasNext()))
        {
            arg2.collect(key, values.next());
        }

    }

}
类Map1扩展MapReduceBase实现Mapper
{
公共void映射(对象键、文本值、OutputCollector、报告器arg3)引发IOException
{
字符串行=value.toString();
StringTokenizer StringTokenizer=新的StringTokenizer(行);
{
整数=999;
String word=“empty”;
if(stringTokenizer.hasMoreTokens())
{
String str0=stringTokenizer.nextToken();
word=str0.trim();
}
if(stringTokenizer.hasMoreElements())
{
String str1=stringTokenizer.nextToken();
number=Integer.parseInt(str1.trim());
}
collector.collect(新的IntWritable(number)、新的Text(word));
}
}
}
类Reduce1扩展了MapReduceBase实现了Reducer
{
公共void reduce(IntWritable键、迭代器值、OutputCollector arg2、Reporter arg3)引发IOException
{
while((values.hasNext()))
{
arg2.collect(key,values.next());
}
}
}

正如您所说,一种可能是编写两个作业来完成此任务。 第一份工作: 简单字数示例

第二份工作: 做排序部分

伪代码可以是:

注意:第一个作业生成的输出文件将作为第二个作业的输入

    Mapper2(String _key, Intwritable _value){
    //just reverse the position of _value and _key. This is useful because reducer will get the output in the sorted and shuffled manner.
    emit(_value,_key);
    }

    Reduce2(IntWritable valueofMapper2,Iterable<String> keysofMapper2){
//At the reducer side, all the keys that have the same count are merged together.
        for each K in keysofMapper2{
        emit(K,valueofMapper2); //This will sort in ascending order.
        }

    }

在发送到减速器侧之前,该比较器将按降序对值进行排序。因此,在reducer上,您只需发出值。

这个问题已经很老了,所以我只想评论一下:在pig:a=load'/out/wordcount'as(word:chararray,num:int)中可以很容易地完成;b=按数量排列的订单a;将b存储到“/out/wordcount sorted”中;比较法和给定的例子有关吗?所以。。。我们应该在原始代码下面添加这个吗?你能告诉我更具体的情况吗?我对java和hadoop都是新手。。。这是我的代码:我也得到了这个错误“类型映射器不能是Map1的超级接口;超级接口必须是接口”“在简单字数映射减少程序中,我们得到的输出是按字排序的”。那不是true@minghan不,需要
compare
Job.setComparatorclass(Comparator.class);