【问题标题】:mongodb - can't understand why/how to use map-reducemongodb - 无法理解为什么/如何使用 map-reduce
【发布时间】:2014-09-23 01:02:19
【问题描述】:

我正在尝试使用 map-reduce 来了解何时这会有所帮助。

所以我有一个名为“actions”的集合,其中包含 100k 文档,如下所示:

{
    "profile_id":1111,
    "action_id":2222
}

现在我正在尝试做 map-reduce 示例。我正在尝试获取“所有用户和每个人的总操作数”的列表。这可能吗?我的代码:

db.fbooklikes.mapReduce(
    function(){
        emit(this.profile_id, this.action_id);
    },
    function(keyProfile, valueAction){
        return Array.sum(valueAction);
    },
    {
        out:"example"
    }
)

.. 这不起作用。结果是:

"counts" : {
    "input" : 100000,
    "emit" : 100000,
    "reduce" : 1146,
    "output" : 13
},
"ok" : 1,
"_o" : {
    "result" : "map_reduce_example",
    "timeMillis" : 2539,
    "counts" : {
        "input" : 100000,
        "emit" : 100000,
        "reduce" : 1146,
        "output" : 13
    },
    "ok" : 1
},

我正在尝试使用 map-reduce 做一些可能的事情?

【问题讨论】:

    标签: javascript mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    是的,你可以使用它,但更精确的回答是,可能有更好的工具来做你想做的事。

    MapReduce 对某些任务很方便,但通常最适合其他不适用的任务。在 MongoDB 中包含 mapReduce 早于 aggregation framework 的引入,这通常是您应该尽可能使用的:

    db.fbooklikes.aggregate([
        { "$group": {
            "_id": "$profile_id",
            "count": { "$sum": 1 }
        }}
    ])
    

    这将简单地返回集合中按“profile_id”的每个值分组的所有文档的计数。

    MapReduce 需要 JavaScript 评估,因此运行速度比聚合框架实现的本机代码函数慢得多。有时你必须使用它,但在简单的情况下最好不要使用它,并且有一些你需要了解的怪癖:

    db.fbooklikes.mapReduce(
        function(){
            emit(this.profile_id, 1);
        },
        function(key,values){
            return Array.sum(values);
        },
        {
            out: { "inline": 1 }
        }
    )
    

    人们对 mapReduce 最怀念的事情是,每个发出的键几乎从不只调用一次 reducer。事实上,它会以“块”的形式处理输出,从而“减少”部分输出并将其放回“减少”的位置,再次针对其他输出进行“减少”,直到该键只有一个值。

    因此,从reduce 函数发出与从“map”函数发送的相同类型的数据非常重要。当您不了解该部分功能时,这是一个棘手的问题,可能会导致奇怪的结果。这实际上是 mapReduce 可以处理单个键值的大量结果并减少它们的底层方式。

    但一般来说,您应该尽可能使用聚合框架,并且如果问题需要一些在那里不可能的特殊计算,或者有一些复杂的文档遍历需要使用 JavaScript 检查,那么就是你在哪里使用 mapReduce。

    【讨论】:

    • +1 - 聚合框架更适合这个
    • 谢谢!聚合工作正常!所以,我正在尝试学习 map-reduce,你能提供一些例子来在这个集合中使用它吗?
    • @user3175226 上面的列表与您所要求的相同。为了更好地理解使用 mapReduce 的案例,最好查看core documentation,它详细解释了各个部分并附有示例。还有另一个部分是samples
    【解决方案2】:

    您不想对操作 ID 求和,而是想对它们进行计数。所以你想要类似下面的东西

    var map = function () {
        emit(this.profile_id, { action_ids : [this.action_id], count : 1  });
    }
    
    var reduce  = function(profile_id, values) {
        var value = { action_ids: [], count: 0 };
    
        for (var i = 0; i < values.length; i++) {
            value.count += values[i].count;
            value.action_ids.push.apply(value.action_ids, values[i].action_ids);
        }
    
        return value;
    }
    
    db.fbooklikes.mapReduce(map, reduce, { out:"example" });
    

    这将为您提供一组操作 ID 和每个配置文件 ID 的计数。可以通过访问action_ids 数组的length 来获得计数,但我想我会将其分开以使示例更清晰。

    【讨论】:

      猜你喜欢
      • 2013-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-16
      • 2010-09-28
      相关资源
      最近更新 更多