MongoDB MapReduce - 发出一个键/一个值不调用reduce

Posted

技术标签:

【中文标题】MongoDB MapReduce - 发出一个键/一个值不调用reduce【英文标题】:MongoDB MapReduce - Emit one key/one value doesnt call reduce 【发布时间】:2012-06-16 19:34:06 【问题描述】:

所以我一般是 mongodb 和 mapreduce 的新手,遇到了这个“怪癖”(或者至少在我看来是一个怪癖)

假设我的收藏中有这样的对象:

'key':5, 'value':5

'key':5, 'value':4

'key':5, 'value':1

'key':4, 'value':6

'key':4, 'value':4

'key':3, 'value':0

我的 ma​​p 函数只是发出键和值

我的 reduce 函数只是在返回它们之前添加值 AND 加 1(我这样做是为了检查是否调用了 reduce 函数)

我的结果如下:

'_id': 3, 'value': 0

'_id':4, '值': 11.0

'_id':5, '值': 11.0

如您所见,对于键 4 和 5,我得到预期的答案 11,但对于键 3(集合中只有一个条目与该键)我得到意外的 0!

这是 mapreduce 的自然行为吗?对于 MongoDB?对于 pymongo(我正在使用)?

【问题讨论】:

【参考方案1】:

reduce 函数将具有相同键的文档合并为一个文档。如果 map 函数为特定键发出单个文档(如键 3 的情况),则不会调用 reduce 函数。

【讨论】:

明确一点,这就是 map reduce 的设计方式。如果您想使用唯一键(如键 3)修改文档,请考虑使用 finalize 函数:mongodb.org/display/DOCS/MapReduce#MapReduce-FinalizeFunction 如果我们想在结果中包含单个文档的键,解决方案是什么??? @RaviKhakhkhar 单个文档仍然包含在结果中,只是从不调用 reduce 函数 谢谢!你拯救了我的一天:) @Jenna,你说这是 map reduce 的设计方式。你有什么参考资料来解释这样的设计理念吗?【参考方案2】:

我意识到这是一个较老的问题,但我来到它并觉得我仍然不明白为什么会存在这种行为以及如何构建 map/reduce 功能,所以这不是问题。

如果有一个键的单个实例,MongoDB 不调用 reduce 函数的原因是因为它不是必需的(我希望这稍后会更有意义)。以下为requirements for reduce functions:

reduce 函数必须返回一个对象,其类型必须与 map 函数发出的值的类型相同。 valuesArray 中元素的顺序不应影响 reduce 函数的输出 reduce 函数必须是幂等的。

第一个要求非常重要,似乎很多人都忽略了它,因为我看到很多人在 reduce 函数中映射,然后在 finalize 函数中处理单键情况。然而,这是解决问题的错误方法。

这样想:如果键只有一个实例,一个简单的优化就是完全跳过 reducer(没有什么可以减少的)。单键值仍然包含在输出中,但 reducer 的目的是构建集合中多键文档的聚合结果。如果 mapper 和 reducer 输出相同的类型,通过查看 map/reduce 函数的输出的对象结构,您应该完全没有意识到这一点。您不必使用 finalize 函数来更正未通过 reducer 运行的对象的结构。

简而言之,在 map 函数中进行映射,并在 reduce 函数中将多键值归约为单个聚合结果。

【讨论】:

【参考方案3】:

解决方案:

地图中添加了新字段:single: 0 在reduce中将此字段更改为:single: 1

finalize中检查该字段并进行必要的操作

$map = new MongoCode("function() 
    var value = 
        time: this.time,
        email_id: this.email_id,
        single: 0
    ;

    emit(this.email, value);
");

$reduce = new MongoCode("function(k, vals) 

    // make some need actions here
    return 
        time: vals[0].time,
        email_id: vals[0].email_id,
        single: 1
    ;
");

$finalize = new MongoCode("function(key, reducedVal) 
    if (reducedVal.single == 0) 
        reducedVal.time = 11111;
    
    return reducedVal;
;");

【讨论】:

【参考方案4】:

“MongoDB 不会为只有一个值的键调用 reduce 函数。values 参数是一个数组,其元素是“映射”到键的值对象。”

http://docs.mongodb.org/manual/reference/command/mapReduce/#mapreduce-reduce-cmd

【讨论】:

【参考方案5】:

这是 mapreduce 的自然行为吗?

是的。

【讨论】:

不 - 这对于“一般先生”来说是不自然的。原始的 MR 论文和 Hadoop Map Reduce 都没有这样做。您可能想在减速器中将该“1”转换为另一种类型,对吧?所以一般来说,跳过减速器是一个非常糟糕/奇怪的想法;-) 这并不意味着 mongo 的 MR 不会这样做 - 但它不是“一般而言的预期行为”。 这里 docs.mongodb.org/manual/tutorial/troubleshoot-reduce-function Mongo 说 retuce 必须返回与 map 相同类型的值。但是,我同意这是不好的、古怪的、出乎意料的和不清楚的。

以上是关于MongoDB MapReduce - 发出一个键/一个值不调用reduce的主要内容,如果未能解决你的问题,请参考以下文章

MapReduce Input/OutPut 为每个键值对发出

MapReduce Input/OutPut 为每个键值对发出

MongoDB--MapReduce分布统计s

python| MongoDB聚合(countdistinctgroupMapReduce)

用mongodb的mapreduce可以加两个条件吗

[MongoDB]mapReduce