对内部文档mongodb进行排序的mapreduce

SRC

我对mongodb的map-reduce有一个快速的问题。我有以下文件结构

{
   "_id": "ffc74819-c844-4d61-8657-b6ab09617271",
   "value": {
     "mid_tag": {
       "0": {
         "0": "Prakash Javadekar",
         "1": "Shastri Bhawan",
         "2": "Prime Minister's Office (PMO)",
         "3": "Narendra Modi"
      },
       "1": {
         "0": "explosion",
         "1": "GAIL",
         "2": "Andhra Pradesh",
         "3": "N Chandrababu Naidu"
      },
       "2": {
         "0": "Prime Minister",
         "1": "Narendra Modi",
         "2": "Bharatiya Janata Party (BJP)",
         "3": "Government"
      }
    },
     "total": 3
  }
}

当我在此文档集合上执行地图精简代码时,我想在此命令中将total指定为排序字段

db.ana_mid_big.mapReduce(map, reduce, 
        {
            out: "analysis_result",
            sort: {"value.total": -1}
        }
);

但这似乎不起作用。如何指定嵌套用于排序的键?请帮忙。

- - - - - - - - - - - - 编辑 - - - - - - - - - - - - - -------

根据评论,我在这里发布我的整个问题。我从一个包含超过350万个文档的集合开始(这只是实时文档的旧快照,已经超过了5.5 M),看起来像这样

{
   "_id": ObjectId("53b394d6f9c747e33d19234d"),
   "autoUid": "ffc74819-c844-4d61-8657-b6ab09617271"
   "createDate": ISODate("2014-07-02T05:12:54.171Z"),
   "account_details": {
     "tag_cloud": {
       "0": "FIFA World Cup 2014",
       "1": "Brazil",
       "2": "Football",
       "3": "Argentina",
       "4": "Belgium"
    }
  }
}

因此,可能有许多具有相同autoUid但具有不同(或部分相同或什至相同)tag_cloud的文档。

我已将以下map-reduce编写为生成一个中间集合,该中间集合看起来像问题开头的那个。因此,显然所有tag_clouds的集合在一个文档中都属于一个人。为此,我使用的MR代码如下所示

var map = function(){

  final_val = {
        tag_cloud: this.account_details.tag_cloud,
        total: 1
  };
  emit(this.autoUid, final_val)
}

var reduce = function(key, values){
  var fv = {
        mid_tags: [],
        total: 0
  }
  try{
    for (i in values){
      fv.mid_tags.push(values[i].tag_cloud);
      fv.total = fv.total + 1;
    }
  }catch(e){
    fv.mid_tags.push(values)
    fv.total = fv.total + 1;
  }
  return fv;
}

db.my_orig_collection.mapReduce(map, reduce, 
        {
            out: "analysis_mid",
            sort: {createDate: -1}
    }
);

当有人有一个以上的记录并且遵循归约功能时,就会出现问题1。但是,当某人只有一个而不是将其命名为“ mid_tag”时,它将保留名称“ tag_cloud”。我了解到reduce代码存在一些问题,但找不到什么。

现在,我想得出一个最终的结果,看起来像

{"_id": "ffc74819-c844-4d61-8657-b6ab09617271",
"value": {
    "tags": {
        "Prakash Javadekar": 1,
        "Shastri Bhawan": 1,
        "Prime Minister's Office (PMO)": 1,
        "Narendra Modi": 2,
        "explosion": 1,
        "GAIL": 1,
        "Andhra Pradesh": 1,
        "N Chandrababu Naidu": 1,
        "Prime Minister": 1,
        "Bharatiya Janata Party (BJP)": 1,
        "Government": 1
    }
}

最终,这是每个人的一个文件,代表他们使用的标签密度。我要使用的MR代码(尚未测试)看起来像这样-

var map = function(){
  var val = {};
  if ("mid_tags" in this.value){
    for (i in this.value.mid_tags){
        for (j in this.value.mid_tags[i]){
            k = this.value.mid_tags[i][j].trim();
            if (!(k in val)){
                val[k] = 1;
            }else{
                val[k] = val[k] + 1;
            }
        }
    }
    var final_val = {
        tag: val,
        total: this.value.total
    }
    emit(this._id, final_val);
  }else if("tag_cloud" in this.value){
    for (i in this.value.tag_cloud){
        k = this.value.tag_cloud[i].trim();
        if (!(k in val)){
            val[k] = 1;
        }else{
            val[k] = val[k] + 1;
        }
    }
    var final_val = {
        tag: val,
        total: this.value.total
    }
    emit(this._id, final_val);  
  }
}
var reduce = function(key, values){
    return values;
}

db.analysis_mid.mapReduce(map, reduce, 
        {
            out: "analysis_result"
        }
);

最后一段代码尚未经过测试。那就是我要做的。请帮忙

尼尔·伦恩

您的PHP背景似乎正在显示。您表示的数据结构未以典型的JSON表示法显示数组,但是在mapReduce代码中注意到了对“推”的调用,至少在“临时文档”中,这些值实际上是数组。您似乎已经以相同的方式“标注”了它们,因此假设它们是合理的。

实际阵列是在此处存储的最佳选择,特别是考虑到所需的结果。因此,即使没有,您的原始文档也应该像这样,因为它们将在shell中表示:

{
   "_id": ObjectId("53b394d6f9c747e33d19234d"),
   "autoUid": "ffc74819-c844-4d61-8657-b6ab09617271"
   "createDate": ISODate("2014-07-02T05:12:54.171Z"),
   "account_details": {
     "tag_cloud": [
       "FIFA World Cup 2014",
       "Brazil",
       "Football",
       "Argentina",
       "Belgium"
     ]
   }
}

使用类似的文档,或者如果您将其更改为类似的文档,那么执行此操作的正确工具就是聚合框架。它可以在本机代码中运行,并且不需要JavaScript解释,因此速度更快。

获得最终结果的聚合语句如下所示:

db.collection.aggregate([

    // Unwind the array to "de-normalize"
    { "$unwind": "$account_details.tag_cloud" },

    // Group by "autoUid" and "tag", summing totals
    { "$group": {
        "_id": {
            "autoUid": "$autoUid",
            "tag": "$account_details.tag_cloud"                
        },
        "total": { "$sum": 1 }
    }},

    // Sort the results to largest count per user
    { "$sort": { "_id.autoUid": 1, "total": -1 }

    // Group to a single user with an array of "tags" if you must
    { "$group": {
        "_id": "$_id.autoUid",
        "tags": { 
            "$push": {
                "tag": "$_id.tag",
                "total": "$total"
            }
        }
    }}
])

输出略有不同,但处理起来简单得多,速度也快得多:

{
    "_id": "ffc74819-c844-4d61-8657-b6ab09617271",
    "tags": [
        { "tag": "Narendra Modi", "total": 2 },
        { "tag": "Prakash Javadekar", "total": 1 },
        { "tag": "Shastri Bhawan", "total": 1 },
        { "tag": "Prime Minister's Office (PMO)", "total": 1 },  
        { "tag": "explosion", "total": 1 },
        { "tag": "GAIL", "total":  1 },
        { "tag": "Andhra Pradesh", "total": 1 },
        { "tag": "N Chandrababu Naidu", "total": 1 },
        { "tag": "Prime Minister", "total": 1 },
        { "tag": "Bharatiya Janata Party (BJP)", "total": 1 },
        { "tag": "Government", "total": 1 }
    ]
}

还可以根据用户的“标签相关性得分”对标签进行排序,以确保达到良好的效果,但是您可以根据实际情况考虑删除该标签,甚至删除最后两个阶段。

到目前为止,最好的选择仍然是。了解如何使用聚合框架。如果您的“输出”仍然是“大”(超过16MB),那么请尝试迁移到MongoDB 2.6或更高版本。聚合语句可以产生一个“游标”,该游标可以被迭代而不是一次提取所有结果。也有$out像mapReduce一样可以创建集合运算符。


如果您的数据实际上是子文档的“哈希”格式,则您要对此表示法表示(遵循数组的PHP“转储”约定),则您需要使用mapReduce,因为聚合框架无法遍历“散列键”的表示方式。不是最佳的结构,如果是这种情况,则应更改它。

您的方法仍然有一些更正,实际上,这实际上是对最终结果的一步操作。同样,最终输出将包含“标签”的“数组”,因为将“数据”用作“键”名称确实不是一个好习惯:

db.collection.mapReduce(
    function() {

        var tag_cloud = this.account_details.tag_cloud; 
        var obj = {};

        for ( var k in tag_cloud ) {
            obj[tag_cloud[k]] = 1; 
        }

        emit( this.autoUid, obj );

    },
    function(key,values) {

        var reduced = {};

        // Combine keys and totals
        values.forEach(function(value) {
            for ( var k in value ) {
                if (!reduced.hasOwnProperty(k))
                    reduced[k] = 0;
                reduced[k] += value[k];
            }
        });

        return reduced;
    },
    { 
        "out": { "inline": 1 }, 
        "finalize": function(key,value) {

            var output = [];

            // Mapped to array for output
            for ( var k in value ) {
                output.push({
                    "tag": k,
                    "total": value[k]
                });                    
            }

            // Even sorted just the same
            return output.sort(function(a,b) {
                return ( a.total < b.total ) ? -1 : ( a.total > b.total ) ? 1 : 0;
            });

        }
    }
)

或者,如果它实际上是原始文档中“标签”的“数组”,但是最终输出将太大,并且您无法升级到最新版本,那么初始数组处理将有所不同:

db.collection.mapReduce(
    function() {

        var tag_cloud = this.account_details.tag_cloud; 
        var obj = {};

        tag_cloud.forEach(function(tag) {
            obj[tag] = 1; 
        });

        emit( this.autoUid, obj );

    },
    function(key,values) {

        var reduced = {};

        // Combine keys and totals
        values.forEach(function(value) {
            for ( var k in value ) {
                if (!reduced.hasOwnProperty(k))
                    reduced[k] = 0;
                reduced[k] += value[k];
            }
        });

        return reduced;
    },
    { 
        "out": { "replace": "newcollection" },
        "finalize": function(key,value) {

            var output = [];

            // Mapped to array for output
            for ( var k in value ) {
                output.push({
                    "tag": k,
                    "total": value[k]
                });                    
            }

            // Even sorted just the same
            return output.sort(function(a,b) {
                return ( a.total < b.total ) ? -1 : ( a.total > b.total ) ? 1 : 0;
            });

        }
    }
)

一切基本上都遵循相同的原则以达到最终结果:

  1. 使用“用户”和分组密钥将其归一化为“用户”和“标签”组合
  2. 将每个用户的结果与“标记”值的总和相结合。

在这里的mapReduce方法中,除了比您看上去想的要干净以外,这里要考虑的另一个主要问题是reducer需要“输出”与映射器完全相同的“输入”。原因实际上是有据可查的,因为实际上可以多次调用“ reducer”,基本上是“ reducing”输出,而该输出已经通过reduce处理。

通常,这就是mapReduce处理“大输入”的方式,其中给定的“键”有很多值,而“归约器”一次只能处理这么多值。例如,一个缩减器实际上可能只获取使用同一密钥发出的30个左右的文档,将这30个文档中的两组缩减为2个文档,然后最终将单个密钥还原为单个输出。


这里的最终结果与上面显示的其他输出相同,但mapReduce的区别在于所有内容都在“值”键下,因为这就是它的工作方式。

因此,有两种方法可以根据您的数据进行操作。尽量使用聚合框架,因为它要快得多,现代版本可以消耗和输出与mapReduce一样多的数据。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

MongoDB-组后对内部数组进行安全排序

MongoDB - 使用聚合对内部数组进行排序

对内部密钥哈希Perl进行排序

在mongodb php中对mapReduce结果进行排序

对内连接的结果进行排序

根据列表中的十六进制地址对内部列表进行排序

Python是否在内部跟踪何时对内容进行了排序?

如何在Lua中按“分数”和“索引”对内部表进行排序?

如何对内部有多个数组的数组进行排序?(JavaScript)

移动选项卡或对内部Windows进行排序时,Visual Studio 2015崩溃

按字节大小对MongoDB文档进行排序

使用 javascript 对内容进行排序/过滤

按内部字段字符串对文档进行排序

MongoDb使用多个嵌套数组对文档进行排序

在MongoDB文档中对数组元素进行排序?

根据Go子文档中的字段对mongodb查询进行排序

MongoDB按数组中的值对文档进行排序

MongoDB按数组元素对文档进行排序

如何在 mongoose/mongodb 中对子文档数组进行排序?

Mongodb按复杂的计算值对文档进行排序

按字段/键名称对MongoDB文档进行排序

MongoDb查询,用于按值对文档进行排序

MongoDB (mongoose) - 查找文档并使用特定键值进行排序

使用Java对mongodb中的子文档数组进行排序

分组mongodb聚合框架后无法对文档进行排序

MongoDB:如何按数组字段对文档进行排序?

如何对通过使用文档ID检索的文档的内部数组进行排序

文档内部的mongoDB数组

Emberjs使用sortProperties按日期对内容进行排序