【问题标题】:How to convert this map reduce in aggregate framework?如何在聚合框架中转换此地图减少?
【发布时间】:2014-08-17 23:41:59
【问题描述】:

我仍然使用 mongoDB 完成了这个 map/reduce/finalize 函数。

这就是我需要 mongoDB 执行聚合的方式:

db.house_results.mapReduce(function(){
    emit(this.house_name.toLowerCase(),this);
    },function(key,values){
        var house = {name:key,address:"",description:"",photo:[],lat:0,lng:0,rooms:[]};
        values.forEach(function(house_val) {
           /*Address*/
            if(house.address=="")
              house.address = house_val.house_address;

           /*Photo*/
           if(!house_val.photo in house.photo)
              house.photo.push(house_val.house_photo);       

           /*Description*/
           if(house.description=="")
              house.description = house_val.house_description;


           /*LAT - LNG*/
           if(house.lat==0 || house.lng==0){
              var house_position = house_val.house_position;
              if(house_position && house_position.lat && house_position.lng){
                 house.lat = house_position.lat; 
                 house.lng = house_position.lng;
              }
           }
           if(house.lat==0 || house.lng==0){
              if(house_val.house_lat && house_val.house_lng){
                 house.lat = house_val.house_lat; 
                 house.lng = house_val.house_lng;
              }
           }

           if(house_val.rooms)
                house.rooms.push(house_val.rooms);  
        });

        return house;
    },
    { 
        out   : "map_reduce_house_test",
        finalize:function(key,house_val){
            if(house_val.address==undefined){ // JUST ONE RESULT IN MAP FUNCTION -> REDUCE FUNCTION IS IGNORED -> FINALIZE IS SOLUTION
               var house = {name:key,address:"",description:"",photo:[],lat:0,lng:0,rooms:[]};
               /*Address*/
               if(house.address=="")
                 house.address = house_val.house_address;

               /*Photo*/
               if(!house_val.photo in house.photo)
                  house.photo.push(house_val.house_photo);       

               /*Description*/
               if(house.description=="")
                  house.description = house_val.house_description;


               /*LAT - LNG*/
               if(house.lat==0 || house.lng==0){
                  var house_position = house_val.house_position;
                  if(house_position && house_position.lat && house_position.lng){
                     house.lat = house_position.lat; 
                     house.lng = house_position.lng;
                  }
               }
               if(house.lat==0 || house.lng==0){
                  if(house_val.house_lat && house_val.house_lng){
                     house.lat = house_val.house_lat; 
                     house.lng = house_val.house_lng;
                  }
               }

               if(house_val.rooms)
                  house.rooms.push(house_val.rooms);

               return house; 
            }else
               return house_val;

        }
    }
);

有没有办法简化这些功能和/或更好地使用聚合 mongodb 的功能?

哪种方法可能是最快和更简单的方法?

谢谢!

【问题讨论】:

    标签: mongodb mapreduce aggregation-framework


    【解决方案1】:

    在这个 mapReduce 中除了从不同字段中获取第一个值作为公共分组键并将其他一些值推送到数组中之外,实际上并没有发生太多事情。

    因此,聚合的一切都非常相似:

    db.house_results.aggregate([
        { "$group": {
            "_id": { "$toLower": "$house_name" },
            "name": { "$first": { "$toLower": "$house_name" } },
            "photo": { "$push": "$house_photo" },
            "address": { "$first": "$house_address" },
            "description": { "$first": "$house_description" },
            "lat": {
                "$max": {
                    "$cond": [
                       { "$gt": [ "$house_lat", "$house_position.lat" } },
                       "$house_lat",
                       "$house_position.lat"
                }
            },
            "lng": {
                "$max": {
                    "$cond": [
                       { "$gt": [ "$house_lng", "$house_position.lng" } },
                       "$house_lng",
                       "$house_position.lng"
                }
            },
            "rooms": { "$push": "$house_rooms" }
        }}
    ])
    

    唯一真正的区别是“lat”和“lng”输出的条件处理主要使用$cond 运算符。

    注意“_id”和“name”在其中有相同的东西,但这就是 map reduce 正在做的事情。

    仔细查看 aggregation operators 以供参考,但实际上您的数据应该是这样的,而不是现在的形式,这似乎是来自某个地方的非规范化转储。

    也供参考,在这种情况下它可能不会影响您,但这是编写 mapReduce 的错误方法。 “map”函数的输出与“reduce”函数的输出不同,尤其是数组。

    即使它们中只有一个元素,它们也“应该”作为数组元素从“map”函数中发出,并被视为它们已经是“reduce”函数的数组元素。

    这是因为使用较大的“分组”,并非所有匹配的键值都会立即发送到reduce函数,并且可以调用reducer将“map”发出的其他值与之前的reduce组合到“reduce”函数中输出。这就是处理大数据的方式,使用数组时,您冒着这样的输出风险,数组中意外嵌入了数组:

    [ [4,5,6], 7, 8, 9 ]
    

    但这在the documentation 中有介绍,请仔细阅读。

    无论如何,聚合管道(一个阶段)的执行速度将比当前操作快得多。但要尽快更改您的数据。

    【讨论】:

      猜你喜欢
      • 2017-06-05
      • 1970-01-01
      • 2016-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 2017-03-25
      • 1970-01-01
      相关资源
      最近更新 更多