0

問題が発生しました。mongodb に次のようなデータがあります。

{"miejscowosci_str":"OneCity", "wojewodztwo":"FirstRegionName", "ZIP-Code" : "...", ...}
{"miejscowosci_str":"TwoCity", "wojewodztwo":"FirstRegionName", "ZIP-Code" : "...", ...}
{"miejscowosci_str":"ThreeCity", "wojewodztwo":"SecondRegionName", "ZIP-Code" : "...", ...}
{"miejscowosci_str":"FourCity", "wojewodztwo":"SecondRegionName", "ZIP-Code" : "...", ...}

私が欲しいのは、すべての地域(wojewodztwo)をリストし、地域ごとの郵便番号の平均数を数えることです。地域内のすべての郵便番号を数える方法を知っています:

var map = function() {
    emit(this.wojewodztwo,1);
};
var reduce = function(key, val) {
    var count = 0;
    for(i in val) {
        count += val[i];
    }
    return count;
};
db.kodypocztowe.mapReduce(
    map,
    reduce,
    { out : "result" }
);

しかし、都市の数 (miejscowosci_str) を数える方法がわからないので、地域の郵便番号の数を同じ地域の都市の数で割ることができます。1 つの都市に複数の郵便番号を指定できます。

何かアイデアはありますか?

4

1 に答える 1

2

ここでいくつかの仮定を立てています:

  1. 都市は複数の郵便番号を持つことができます
  2. 郵便番号は一意です
  3. M101P第 5 週の質問に対する答えを得ようとしているのではありません。

一度に都市を数えるのではなく、マップ フェーズで都市/zip オブジェクトのリストを作成し、マップ フェーズでこれを zip と一意の都市のリストに減らしてみませんか。その後、ファイナライズ フェーズを使用して平均を計算できます。

注 : データ セットが大きい場合は、代わりに集計フレームワークの使用を検討することをお勧めします。これは、map/reduce の例の後に示されています。

db.kodypocztowe.drop();
db.result.drop();

db.kodypocztowe.insert([
    {"miejscowosci_str":"OneCity", "wojewodztwo":"FirstRegionName", "ZIP-Code" : "1"},
    {"miejscowosci_str":"TwoCity", "wojewodztwo":"FirstRegionName", "ZIP-Code" : "2"},
    {"miejscowosci_str":"ThreeCity", "wojewodztwo":"SecondRegionName", "ZIP-Code" : "3"},
    {"miejscowosci_str":"FourCity", "wojewodztwo":"SecondRegionName", "ZIP-Code" : "4"},
    {"miejscowosci_str":"FourCity", "wojewodztwo":"SecondRegionName", "ZIP-Code" : "5"},
]);

// map the data to { region : [{citiy : name , zip : code }] } 
// Note : a city can be in multiple zips but zips are assumed to be unique
var map = function() {
    emit(this.wojewodztwo, {city:this.miejscowosci_str, zip:this['ZIP-Code']});
};

// 
// convert the data to :
//
//    {region : {cities: [], zips : []}}
//
// note : always add zips
// note : only add cities if they are not already there
//
var reduce = function(key, val) {
    var res = {zips:[], cities:[]}
    for(i in val) {
        var city = val[i].city;
        res.zips.push(val[i].zip);
        if(res.cities.indexOf(city) == -1) {
            res.cities.push(city);
        }
    }
    return res;
};

// 
// finalize the data to get the average number of zips / region
var finalize = function(key, res) {
    res.average  = res.zips.length / res.cities.length;
    delete res.cities;
    delete res.zips;
    return res;
}

print("==============");
print(" map/reduce")
print("==============");

db.kodypocztowe.mapReduce(
    map,
    reduce,
    { out : "result" , finalize:finalize}
);
db.result.find().pretty()


print("==============");
print(" aggregation")
print("==============");

db.kodypocztowe.aggregate( [
    // get the number of zips / [region,city]
    { "$group" :
      {
          _id : {"region" : "$wojewodztwo", city : "$miejscowosci_str"},
          zips:{$sum:1}
      }
    },
    // get the number of cities per region and sum the number of zips
    { "$group" :
      {
          _id : "$_id.region" ,
          cities:{$sum:1},
          zips:{$sum:"$zips"},
      }
    },
    // project the data into the same format that map/reduce generated
    { "$project" :
      {
          "value.average":{$divide: ["$zips","$cities"]}
      }
    }
]);

それが役立つことを願っています。

于 2013-05-16T16:41:32.047 に答える