【问题标题】:Mongo DB MapReduce: Emit key from array based on conditionMongodb MapReduce:根据条件从数组中发出键
【发布时间】:2012-05-30 13:54:11
【问题描述】:

我是 mongo db 的新手,如果这很琐碎,请原谅。我非常感谢您的帮助。

这个想法是在某些特定值上生成直方图。在这种情况下,某些文件的 mime 类型。为此,我正在使用 map reduce 作业。

我有一个文件格式如下的 mongo:

{
    "_id" : ObjectId("4fc5ed3e67960de6794dd21c"),
    "name" : "some name",
    "uid" : "some app specific uid",
    "collection" : "some name",
    "metadata" : [
        {
            "key" : "key1",
            "value" : "Plain text",
            "status" : "SINGLE_RESULT",
        },
        {
            "key" : "key2",
            "value" : "text/plain",
            "status" : "SINGLE_RESULT",
        },
        {
            "key" : "key3",
            "value" : 3469,
            "status" : "OK",
        }
     ]
}

请注意,几乎每个文档中都有更多元数据键值。

Map Reduce 作业

我尝试了以下操作:

function map() {
   var mime = "";
   this.metadata.forEach(function (m) {
     if (m.key === "key2") {
        mime = m.value;}
     });
     emit(mime, {count:1});
}

function reduce() {
  var res = {count:0};
  values.forEach(function (v) {res.count += v.count;});
  return res;
}

db.collection.mapReduce(map, reduce, {out: { inline : 1}})

这似乎适用于少量文档(~15K),但问题是在映射阶段遍历所有元数据键值需要大量时间。在更多文档 (~1Mio) 上运行此操作时,该操作将永远进行。

所以我的问题是: 有什么方法可以直接发出 mime 类型(值),而不是遍历所有键并选择它?或者有没有更好的方法来编写 map reduce 函数。

类似 emit (this.metadata.value {$where this.metadata.key:"key2"}) 或类似的东西...

感谢您的帮助!

【问题讨论】:

    标签: performance mongodb mapreduce


    【解决方案1】:

    两个想法……

    第一个想法:您对这个文档架构的依附程度如何?您能否将元数据字段值作为嵌入文档而不是嵌入数组,如下所示:

    {
        "_id" : ObjectId("4fc5ed3e67960de6794dd21c"),
        "name" : "some name",
        "uid" : "some app specific uid",
        "collection" : "some name",
        "metadata" : {
            "key1" : {
                "value" : "Plain text",
                "status" : "SINGLE_RESULT"
            },
            "key2": {
                "value" : "text/plain",
                "status" : "SINGLE_RESULT"
            }, 
            "key3" : {
                "value" : 3469,
                "status" : "OK"
            }
         }
    }
    

    然后你的地图步骤完全取消了循环:

    function map() {
       emit( this.metadata["key2"].value, { count : 1 } );
    }
    

    此时,您甚至可以将其转换为“组”命令而不是“mapReduce”。

    第二个想法:如果没有这样的架构更改,特别是如果“key2”出现在元数据数组的早期,您至少可以在找到密钥后急切地退出循环以节省一些迭代,如下所示:

    function map() {
       var mime = "";
       this.metadata.forEach(function (m) {
         if (m.key === "key2") {
            mime = m.value;
            break;
         } 
         });
         emit(mime, {count:1});
    }
    

    不确定这两条路是否是胜利的关键,但希望对您有所帮助。祝你好运!

    【讨论】:

    • 您好,感谢您的回复。带有中断的建议是不可行的,因为元数据键值对可能相当长,这不一定会提高性能。但是,我按照您的建议更改了架构(对应用程序进行了轻微的修改),现在 map reduce 中的过滤要容易得多。您建议的地图功能效果更好,我能够在不到一分钟的时间内获得近 1.5 条 Mio 记录的直方图。所以,我接受你的回答!非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-18
    • 1970-01-01
    • 2019-02-11
    • 2014-02-23
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多