PHP中的Mongo DB MapReduce

PHP中的Mongo DB MapReduce,php,mongodb,mapreduce,schema,nosql,Php,Mongodb,Mapreduce,Schema,Nosql,首先这是我第一次来蒙哥 概念: 用户能够用自然语言描述图像 划分用户输入,并将他描述的单词存储在一个名为 语言 用户必须能够浏览最常用的单词,并将这些单词添加到他们的描述中 系统将使用使用最多的单词(适用于所有用户)并使用 用这些词来描述形象 我的Word文档(当前)如下(示例) 这些单词将被复制,以便每个单词都可以与一个用户关联 问题:我需要执行Mongo查询,以便知道不是由给定用户创建的最常用的单词(用于描述图像)。(符合上述第3点) 我见过MapReduce算法,但从我的阅读来看,它有几个

首先这是我第一次来蒙哥

概念:

  • 用户能够用自然语言描述图像
  • 划分用户输入,并将他描述的单词存储在一个名为 语言
  • 用户必须能够浏览最常用的单词,并将这些单词添加到他们的描述中
  • 系统将使用使用最多的单词(适用于所有用户)并使用 用这些词来描述形象
  • 我的Word文档(当前)如下(示例)

    这些单词将被复制,以便每个单词都可以与一个用户关联

    问题:我需要执行Mongo查询,以便知道不是由给定用户创建的最常用的单词(用于描述图像)。(符合上述第3点)

    我见过MapReduce算法,但从我的阅读来看,它有几个问题:

  • 无法对结果进行排序(我可以从使用最多的排序到使用较少的排序)
  • 在数以百万计的文档中,它可能需要大量的处理时间
  • 无法限制返回结果的数量
  • 我考虑过每天在给定的时间运行一个任务,在文档(不同的集合)中存储给定用户没有用来描述给定图像的单词列表。我必须将此限制为300个结果或类似的(任何关于适当限制的想法???)类似于:

    {
    user_id: "the user id"
    [
    {word: test, count: 1000},
    {word: test2, count: 980},
    {word: etc, count: 300}
    ]
    }
    
    我发现此解决方案存在以下问题:

  • 结果将有相当大的延迟,这是不可取的
  • 为所有用户生成此文档时的服务器负载可能会急剧增加(实际上我在Mongo中对此知之甚少,所以这只是一个假设)
  • 也许我的方法没有任何意义。。。也许我在Mongo方面缺乏经验,这就指向了错误的“模式设计”

    你知道什么是解决这类问题的好方法吗

    很抱歉发了这么大的帖子,谢谢你的时间和帮助


    João

    组函数应该是
    MapReduce
    的一个更简单版本。您可以这样使用它来计算每个单词的总和:

    db.coll.group(
               {key: { a:true, b:true },
                cond: { active:1 },
                reduce: function(obj,prev) { prev.csum += obj.c; },
                initial: { csum: 0 }
                });
    

    如前所述,您可以使用易于使用的命令,但需要在客户端对结果进行排序。此外,结果作为单个BSON对象返回,因此必须非常小–少于10000个键,否则将出现异常

    基于数据结构的代码示例:

    db.words.group({
        key : {"word" : true},
        initial: {count : 0},
        reduce: function(obj, prev) { prev.count++},
        cond: {"user" :{ $ne : "USERNAME_TO_IGNORE"}}
    })
    
    另一个选择是使用新版本,该版本将在2.2版本中发布。这样的办法应该行得通

    db.words.aggregate({
       $match : { "user" : { "$ne" : "USERNAME_TO_IGNORE"} },
       $group : {
         _id : "$word",
         count: { $sum : 1}
       }
    })
    
    或者您仍然可以使用MapReduce。实际上,您可以限制和排序输出,因为结果是 收藏。只需对输出使用.sort()和.limit()。您还可以使用增量 映射减少输出选项,这将帮助您解决性能问题。请查看中的参数

    下面是一个示例,它使用增量功能将现有集合与words_usage集合中的新数据合并:

    m = function() { 
       emit(this.word, {count: 1}); 
    };
    
    
    r = function( key , values ){
         var sum = 0;
         values.forEach(function(doc) {
              sum += doc.count;
         });
         return {count: sum};
     };
    
    db.runCommand({
        mapreduce : "words", 
        map : m,
        reduce : r,
        out : { reduce: "words_usage"},
        query : <query filter object>
    })
    
    # retrieve the top 10 words
    db.words_usage.find().sort({"value.count" : -1}).sort({"value.count" : -1}).limit(10)
    
    m=function(){
    emit(this.word,{count:1});
    };
    r=功能(键、值){
    var总和=0;
    values.forEach(函数(doc){
    总和+=单据计数;
    });
    返回{count:sum};
    };
    db.runCommand({
    mapreduce:“单词”,
    地图:m,
    减少:r,
    out:{reduce:“单词的用法”},
    查询:
    })
    #检索前10个单词
    db.words_usage.find().sort({“value.count”):-1}.sort({“value.count”):-1}.limit(10)
    
    我想您可以每隔几分钟/小时在cron中运行上面的MapReduce命令,这取决于您想要的结果的准确性。对于更新查询条件,您可以使用单词documents creation date


    一旦你有了系统top words集合,你就可以建立每个用户的top words,或者只是实时计算它们(取决于系统大小)。

    是的,必须在客户端进行排序这是一个很好的答案!真的很期待2.2版本。同时,我会尝试你的评论!真的很感激对不起。但是mapreduce的限制是在计算完所有内容后应用的,还是会停止对10个文档的计算?在性能方面,考虑到我将使用php对结果进行排序(至少在组案例中),您的建议是什么?该限制将在执行MapReduce后或在对集合进行排序/查找时应用。正如我所说的,您可以随时重用结果。何时以及多久更新一次集合取决于您。在性能方面,您应该可以在php端进行排序。如果将来这会成为一个问题,那就使用一些缓冲区。
    m = function() { 
       emit(this.word, {count: 1}); 
    };
    
    
    r = function( key , values ){
         var sum = 0;
         values.forEach(function(doc) {
              sum += doc.count;
         });
         return {count: sum};
     };
    
    db.runCommand({
        mapreduce : "words", 
        map : m,
        reduce : r,
        out : { reduce: "words_usage"},
        query : <query filter object>
    })
    
    # retrieve the top 10 words
    db.words_usage.find().sort({"value.count" : -1}).sort({"value.count" : -1}).limit(10)