永发信息网

如何用数组的reduce实现数组的map函数

答案:2  悬赏:60  手机版
解决时间 2021-03-15 17:18
如何用数组的reduce实现数组的map函数
最佳答案
假定我们需要计算大文本中每一行的长度,并且报告每个长度的行数。在HadoopMapReduce中,我们首先使用一个Mapper,生成为以行的长度作为key,1作为value的键值对。

public class LineLengthMapper extends
Mapper {
@Override
protected void map(LongWritable lineNumber, Text line, Context context)
throws IOException, InterruptedException {
context.write(new IntWritable(line.getLength()), new IntWritable(1));
}
}

值得注意的是Mappers和Reducers只对键值对进行操作。所以由TextInputFormat提供输入给LineLengthMapper,实际上也是以文本中位置为key(很少这么用,但是总是需要有东西作为Key),文本行为值的键值对。

与之对应的Spark实现:

lines.map(line => (line.length, 1))

Spark中,输入只是String构成的RDD,而不是key-value键值对。Spark中对key-value键值对的表示是一个Scala的元组,用(A,B)这样的语法来创建。上面的map操作的结果是(Int,Int)元组的RDD。当一个RDD包含很多元组,它获得了多个方法,如reduceByKey,这对再现MapReduce行为将是至关重要的。

Reduce
reduce()与reduceBykey()
统计行的长度的键值对,需要在Reducer中对每种长度作为key,计算其行数的总和作为value。

public class LineLengthReducer extends
Reducer {
@Override
protected void reduce(IntWritable length, Iterable counts,
Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable count : counts) {
sum += count.get();
}
context.write(length, new IntWritable(sum));
}
}

Spark中与上述Mapper,Reducer对应的实现只要一行代码:

val lengthCounts = lines.map(line => (line.length, 1)).reduceByKey(_ + _)

Spark的RDD API有个reduce方法,但是它会将所有key-value键值对reduce为单个value。这并不是Hadoop MapReduce的行为,Spark中与之对应的是ReduceByKey。

另外,Reducer的Reduce方法接收多值流,并产生0,1或多个结果。而reduceByKey,它接受的是一个将两个值转化为一个值的函数,在这里,就是把两个数字映射到它们的和的简单加法函数。此关联函数可以被调用者用来reduce多个值到一个值。与Reducer方法相比,他是一个根据Key来Reduce Value的更简单而更精确的API。

Mapper
map() 与 flatMap()
现在,考虑一个统计以大写字母开头的单词的个数的算法。对于每行输入文本,Mapper可能产生0个,1个或多个键值对。

public class CountUppercaseMapper extends
Mapper {
@Override
protected void map(LongWritable lineNumber, Text line, Context context)
throws IOException, InterruptedException {
for (String word : line.toString().split(" ")) {
if (Character.isUpperCase(word.charAt(0))) {
context.write(new Text(word), new IntWritable(1));
}
}
}
}

Spark对应的写法:

lines.flatMap(
_.split(" ").filter(word => Character.isUpperCase(word(0))).map(word => (word,1))
)

简单的Spark map函数不适用于这种场景,因为map对于每个输入只能产生单个输出,但这个例子中一行需要产生多个输出。所以,和MapperAPI支持的相比,Spark的map函数语义更简单,应用范围更窄。

Spark的解决方案是首先将每行映射为一组输出值,这组值可能为空值或多值。随后会通过flatMap函数被扁平化。数组中的词会被过滤并被转化为函数中的元组。这个例子中,真正模仿Mapper行为的是flatMap,而不是map。

groupByKey()
写一个统计次数的reducer是简单的,在Spark中,reduceByKey可以被用来统计每个单词的总数。比如出于某种原因要求输出文件中每个单词都要显示为大写字母和其数量,在MapReduce中,实现如下:

public class CountUppercaseReducer extends
Reducer {
@Override
protected void reduce(Text word, Iterable counts, Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable count : counts) {
sum += count.get();
}
context
.write(new Text(word.toString().toUpperCase()), new IntWritable(sum));
}
}

但是redeceByKey不能单独在Spark中工作,因为他保留了原来的key。为了在Spark中模拟,我们需要一些更像Reducer API的操作。我们知道Reducer的reduce方法接受一个key和一组值,然后完成一组转换。groupByKey和一个连续的map操作能够达到这样的目标:

groupByKey().map { case (word,ones) => (word.toUpperCase, ones.sum) }

groupByKey只是将某一个key的所有值收集在一起,并且不提供reduce功能。以此为基础,任何转换都可以作用在key和一系列值上。此处,将key转变为大写字母,将values直接求和。
全部回答
支持一下感觉挺不错的
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
如何电脑的开机速度更快!!!我的系统是win7
不知道南宁哪有电动车锂电池我想买一个装到自
班里有一个女生想和我单挑,只要能把人放倒就
我喜欢你,cui 没有勇气告诉你 还是不明白当
一品国际大酒店地址有知道的么?有点事想过去
玩CF要安装什么驱动才不卡?
从云南开远市经建水县去普洱市怎么走,有多少
为什么GTA4(1.04版)安装了恶灵骑士MOD后就
爱尚一元涮地址在哪,我要去那里办事
Oracle pl/sql编程的execute immediate问题
(2013?玉林模拟)如图所示,在电路两端接上
急需机械设计兼职人员,有意者回应。
鲁东装饰我想知道这个在什么地方
学美容好还是学美体好呢?
魔卡幻想卡在8-10了
推荐资讯
在少女时代中是谁说的我是爸爸我会负责的
信用卡账单用日语怎么怎么说。
[讨论]关于生化危机0里用打火机才能进的暗房
新益隆置业发展有限公司地址在什么地方,想过
关于用铜丝做保险丝
爱嘉木门·推拉门地址在什么地方,想过去办事
文津图文快印地址有知道的么?有点事想过去
请问UI行业的就业前景怎么样?
唐睿宗是怎么死的
日语k毛七是什么意思?
绍兴博物馆的参观信息
小学生环保小常识
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?