0-8 MapReduce
MapReduce
框架#
-
Input
-
Split
-
Map
-
传输整理
-
Reduce
-
Output
Map Reduce 函数的输入输出接口?
Map Reduce 函数的输入输出接口必须是 key, value 形式.
单词计数#
MapReduce 方法来处理单词, Map 过程就相当于把任务打散, 分配到各个机器上. Reduce 过程就是把 Map 结果合并.
比如单词计数这道题, Map 过程就是利用多台机器, 将文件切分分配到各个 Map 机器上来进行排序. 而 Reduce 过程有两种:
一种是按照机器数目来进行合并, 比如 1~10 号 Map 机器结果交给 1 号 Reduce 机器来完成, 11~20 号 Map 机器结构交给 2 号 Reduce 机器来完成.
一种是按照单词来合并, 通过将单词哈希, 所有相同哈希值的单词都被同一台机器合并, 不同 Reduce 机器负责不同范围的哈希值.
哪种更好呢?
第二种按照哈希值来合并更好, 因为第一种按照机器数目的合并就像神经网络一样, 会有很多层, Map-Reduce-Reduce.. 这样就会导致下一层的任务必须等待上一层任务结束后再开始. 而且合并的任务也更加繁重.
而第二种方式 Reduce 任务不需要等待 Map 任务完全结束再开始, 可以一边进行 Map 任务, 一边将 Map 任务的结果交给 Reduce 任务, 这样节约很多时间. 而且最后合并任务只需要最后归并排序即可, 不需要像第一种那样最后还需要再合并一次才能归并排序.
输入输出
type output struct {
word string
times int
}
// 结果通过网络传输给 Reduce 机器
func Map(key fileaddress, value content) []output {
for {
... // 处理, 存放到内存
// 内存快存到上限了
return outputs
}
}
func Reduce(mapOp []output) []output {
for {
... // 合并
}
return outputs
}
机器越多越好么?
key 的数目就是 Reduce 机器的上限.
倒排索引#
倒排索引就好像搜索引擎关键词搜索. 一般来说一个文章会有自己的关键词, 叫正排索引. 倒排索引就是通过关键词来找文章.
MapReduce 任务: 给定文章的正排索引, 输出文章的倒排索引.
func Map(fileid string, words []string) (word, fileid string) {
...
}
type reduceHelper struct {
output map[string][]string
}
func Reducee(word, fileid string) {
output[word] = append(output[word], fileid)
}
Top K 问题#
type pair struct {
Word string
Times int
}
type PairHeap []pair
// 构建小顶堆
func (h PairHeap) compare(a, b pair) bool {
if a.Times != b.Times {
return a.Times < b.Times
}
return a.Word < b.Word
}
func (h PairHeap) Len() int {
return len(h)
}
func (h PairHeap) Less(i, j int) bool {
// 左<右, 小顶堆; 左>右, 大顶堆
return h.compare(h[i], h[j])
}
func (h PairHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h *PairHeap) Push(x interface{}) {
*h = append(*h, x.(pair))
}
func (h *PairHeap) Pop() interface{} {
x := (*h)[len(*h)-1]
*h = (*h)[:len(*h)-1]
return x
}
func Map(fileid int, words []string) []pair {
var (
res = make(map[string]int)
pairs = make([]pair, 0)
)
for _, word := range words {
res[word]++
}
for word, times := range res {
pairs = append(pairs, pair{Word: word, Times: times})
}
return pairs
}
// return Top K pairs
func Reduce(pairs []pair, k int) []pair {
h := &PairHeap{}
heap.Init(h) // initialize
for i := 0; i < len(pairs); i++ {
if h.Len() < k {
heap.Push(h, pairs[i])
continue
}
// compare to the top element of heap
if !h.compare(pairs[i], pairs[0]) {
heap.Pop(h)
heap.Push(h, pairs[i])
}
}
return []pair(*h) // 返回值为从小到大
}
首先使用 Map 来从文件中提取单词, 并提取词频(可选)
接着将相同 key 的单词交给同一个 Reduce, 然后让 Reduce 维护一个小顶堆. 如果当前值小于堆顶值, 那么直接丢弃. 如果当前值大于堆顶值, 那么先将堆顶值弹出(堆顶与堆尾交换 + 堆顶下沉), 然后再将当前值推入堆中(放入堆尾 + 堆尾上浮).
这样用小顶堆 Reduce 可以减少内存使用.
MapReduce 框架设计#
见 MIT 6.824 的课程.
Reduce 一个机器 Key 数目特别多怎么办
加一个随机数前缀, 类似 Sharding Key. 最后合并的时候写一个脚本来去掉前缀就可以.
作者:Kohn
出处:https://www.cnblogs.com/geraldkohn/p/17091093.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南