我对MapReduce非常陌生,我完成了一个Hadoop字数统计示例。
在该示例中,它生成单词计数的未排序文件(具有键值对)。那么是否可以通过将另一个MapReduce任务与前一个任务相结合来按字出现次数对其进行排序?
答案 0 :(得分:1)
在简单的字数统计减少程序中,我们得到的输出按字排序。样本输出可以是:
Apple 1
男孩30
Cat 2
青蛙20
斑马1
如果您希望根据单词的出现次数对输出进行排序,即格式如下
1 Apple
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());
}
}
}
答案 1 :(得分:0)
Hadoop MapReduce wordcount示例的输出按键排序。因此输出应按字母顺序排列。
使用Hadoop,您可以创建自己的密钥对象,实现WritableComparable
接口,允许您覆盖compareTo
方法。这允许您控制排序顺序。
要创建一个按出现次数排序的输出,您可能需要添加另一个MapReduce作业来处理第一个输出,如您所说。第二项工作非常简单,甚至可能不需要减少阶段。您只需要实现自己的Writable
密钥对象来包装单词及其频率。自定义可写的内容如下所示:
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));
}
}
我从here抓住了这个例子。
您也应该覆盖hashCode
,equals
和toString
。
答案 2 :(得分:0)
在Hadoop中,在Map和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;
}
}
答案 3 :(得分:0)
正如你所说,一种可能性是写两个工作来做到这一点。 第一份工作: 简单的wordcount示例
第二份工作: 是排序部分。
伪代码可以是:
注意:第一个作业生成的输出文件将是第二个作业的输入
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.
}
}
您也可以按降序排序,可以编写一个单独的比较器类来完成这个操作。 在作业中包含比较器:
Job.setComparatorclass(Comparator.class);
此比较器将在发送到reducer端之前按降序对值进行排序。所以在reducer上,你只需要发出值。