2012-03-14 29 views
18

Basit bir prosedür olduğunu düşündüğüm şeyi yapmak için MongoDB'de MapReduce kullanmaya çalışıyorum. Bu doğru bir yaklaşım olup olmadığını bilmiyorum, eğer MapReduce kullanıyor olsam bile. Hangi anahtar kelimeleri düşündüğümü araştırdım ve en çok başarıya ulaşacağımı düşündüğüm dokümanları vurmaya çalıştım - ama hiçbir şey. Belki bu konuda çok fazla düşünüyorum? details ve gpasMongoDB'de iki koleksiyon birleştirme

details belgelerin sürü (3+ milyon) oluşur:

İki koleksiyonları var. studentid öğe, aşağıdaki gibi, iki kez, her biri için bir tane year tekrar edilebilir:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640100"), "classes" : [1,17,19,21], "studentid" : "12345a", "year" : 1} 
{ "_id" : ObjectId("4d76b7oij7s2d8372v640100"), "classes" : [2,12,19,22], "studentid" : "98765a", "year" : 1} 
{ "_id" : ObjectId("4d49b7oij7s2d8372v640100"), "classes" : [32,91,101,217], "studentid" : "12345a", "year" : 2} 
{ "_id" : ObjectId("4d76b7rty7s2d8372v640100"), "classes" : [1,11,18,22], "studentid" : "24680a", "year" : 1} 
{ "_id" : ObjectId("4d49b7oij7s2d8856v640100"), "classes" : [32,99,110,215], "studentid" : "98765a", "year" : 2} 
... 

gpasdetails aynı studentid 's elemanları vardır. Böyle studentid başına yalnızca bir giriş,:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "overall" : 97, "subscore": 1} 
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "overall" : 85, "subscore": 5} 
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "overall" : 76, "subscore": 2} 
... 

ben bu biçimde her öğrenci için bir satır ile bir koleksiyona sahip istiyorum Sonunda:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "classes_1": [1,17,19,21], "classes_2": [32,91,101,217], "overall" : 97, "subscore": 1} 
{ "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "classes_1": [2,12,19,22], "classes_2": [32,99,110,215], "overall" : 85, "subscore": 5} 
{ "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "classes_1": [1,11,18,22], "classes_2": [], "overall" : 76, "subscore": 2} 
... 

yolu Bunu yapacaktım böyle mapreduce çalıştırarak oldu:

var mapDetails = function() { 
    emit(this.studentid, {studentid: this.studentid, classes: this.classes, year: this.year, overall: 0, subscore: 0}); 
}; 

var mapGpas = function() { 
    emit(this.studentid, {studentid: this.studentid, classes: [], year: 0, overall: this.overall, subscore: this.subscore}); 
}; 

var reduce = function(key, values) { 
    var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; 

    values.forEach(function(value) { 
     if (value.year == 0) { 
      outs.overall = value.overall; 
      outs.subscore = value.subscore; 
     } 
     else { 
      if (value.year == 1) { 
       outs.classes_1 = value.classes; 
      } 
      if (value.year == 2) { 
       outs.classes_2 = value.classes; 
      } 

      outs.studentid = value.studentid; 
     } 
    }); 

    return outs; 

}; 

res = db.details.mapReduce(mapDetails, reduce, {out: {reduce: 'joined'}}) 
res = db.gpas.mapReduce(mapGpas, reduce, {out: {reduce: 'joined'}}) 

Ama bunu çalıştırdığınızda, bu benim çıkan koleksiyon:

{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 97, "subscore" : 1 } } 
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 85, "subscore" : 5 } } 
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } } 

Sınıf dizilerini kaçırıyorum.

Ayrıca bir kenara olarak, nasıl MapReduce value elemanı çıkan öğeler erişebilirim? MapReduce her zaman value'a mı yoksa adı neye verirseniz verilsin mi? yalnızca bir koleksiyonu uygulamak için tasarlanmıştır beri

cevap

41

Bu MongoDB kullanıcılar Google Grupları üzerinde sorulan bir soruya benzer.
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1

cevabı örneğe benzer bir on-line öğretici başvuruyor: orada, Ek http://www.mongodb.org/display/DOCS/MapReduce

: MongoDB içinde MapReduce hakkında daha fazla bilgi için http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

, belgelere bakın bir MapReduce operasyonu "sürümlü Belgeler Max Ve Min Değerler bulma" başlıklı MongoDB Cookbook makalenin "Ekstralar" bölümünde nasıl çalıştığını kullanışlı adım adım açıklaması geçerli: http://cookbook.mongodb.org/patterns/finding_max_and_min/

Zaten başvurulan bazı belgeleri okudum beni affet.Bu gönderiyi okuyan ve MongoDB

'da yeni olanları kullanmaları için yeni kullanıcıları buraya dahil ettim. Harita işlevlerindeki 'yayma' ifadelerinden gelen çıktıların Küçültme işlevinin çıktılarıyla eşleşmesi önemlidir . Harita işlevi tarafından yalnızca bir belge çıktısı varsa, Azaltma işlevi hiç çalıştırılamayabilir ve çıktı koleksiyonunuz eşleşmemiş belgelere sahip olacaktır.

İki ayrı "sınıf" dizisiyle, istediğiniz çıktı biçiminde belgeleri yayınlamak için harita ifadelerinizi biraz değiştirdim.
Ayrıca, sınıflar_1 ve classes_2 dizilerine yeni sınıflar eklemek için azaltma ifadenizi yeniden çalıştırmıştım.

> db.joined.find() 
{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ 1, 17, 19, 21 ], "classes_2" : [ 32, 91, 101, 217 ], "overall" : 97, "subscore" : 1 } } 
{ "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ 1, 11, 18, 22 ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } } 
{ "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ 2, 12, 19, 22 ], "classes_2" : [ 32, 99, 110, 215 ], "overall" : 85, "subscore" : 5 } } 
> 

MapReduce hep {_ID şeklinde belgeleri verir: İstediğiniz biçimi ile eşleşen aşağıdaki toplama, iki MapReduce operasyonlarının sonuç Koşu

var mapDetails = function(){ 
    var output = {studentid: this.studentid, classes_1: [], classes_2: [], year: this.year, overall: 0, subscore: 0} 
    if (this.year == 1) { 
     output.classes_1 = this.classes; 
    } 
    if (this.year == 2) { 
     output.classes_2 = this.classes; 
    } 
    emit(this.studentid, output); 
}; 

var mapGpas = function() { 
    emit(this.studentid, {studentid: this.studentid, classes_1: [], classes_2: [], year: 0, overall: this.overall, subscore: this.subscore}); 
}; 

var r = function(key, values) { 
    var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; 

    values.forEach(function(v){ 
     outs.studentid = v.studentid; 
     v.classes_1.forEach(function(class){if(outs.classes_1.indexOf(class)==-1){outs.classes_1.push(class)}}) 
     v.classes_2.forEach(function(class){if(outs.classes_2.indexOf(class)==-1){outs.classes_2.push(class)}}) 

     if (v.year == 0) { 
      outs.overall = v.overall; 
      outs.subscore = v.subscore; 
     } 
    }); 
    return outs; 
}; 

res = db.details.mapReduce(mapDetails, r, {out: {reduce: 'joined'}}) 
res = db.gpas.mapReduce(mapGpas, r, {out: {reduce: 'joined'}}) 

"id", değeri: "değeri Eğer MapReduce t çıkışını isterseniz http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

: Nokta Notasyon '(Nesneleri uzanarak) "} fazla bilgi başlıklı belgede alt belgelerle çalışma geçerli yok' o farklı bir formatta görünür, programınızda programınızda bunu yapmak zorunda kalacaksınız.

Bu, MapReduce anlayışınızı geliştirecek ve istediğiniz çıktı koleksiyonunu üretmeye bir adım daha yaklaştıracaktır. İyi şanslar!

+0

Bu, çok yardımcı oldu. Bu yazıya verdiğiniz her zaman için minnettarım. Tekrar teşekkürler! – TFX

+0

Benim için zevk! Yardım edebildiğim için mutluyum! Saygılarımla, Marc – Marc

2

Bunun için m/r kullanamaz. Birden fazla koleksiyondan okumak, okuma uyumluluğunu kıracaktır ve bu nedenle izin verilmez. İstediğiniz şeyi yeni toplama çerçevesiyle (2.1+) yapabilir veya bunu uygulamanızın içinde yapabilirsiniz.

İlgili konular