2010-08-27 110 views
16

我有一些25k文件(原始json中有4 GB)的數據,我想對其執行一些JavaScript操作,以使其更容易訪問我的最終數據使用者(R)和I想通過爲每個更改添加一個新的集合來對這些更改進行「版本控制」排序,但是我不知道如何在沒有reduce的情況下如何執行map/reduce。我想要一個一對一的文檔映射 - 我從collection_1中的25,356個文檔開始,並且我想以collection_2結束25,356個文檔。mongoDB map/reduce減去減少

我可以用這個本事:

var reducer = function(key, value_array) { 
    return {key: value_array[0]} 
} 

然後調用它像:

db.flat_1.mapReduce(mapper, reducer, {keeptemp: true, out: 'flat_2'}) 

(我的映射器只在呼叫發射一次,用一個字符串作爲第一個參數,最後文件作爲第二個。它是我真正想要的那些第二個參數的集合。)

但是這似乎很尷尬,我不知道它爲什麼它甚至可以工作,因爲我的emit調用ar我的映射器中的聲明不等於我的reducer的返回參數。另外,我最終得到一份文件,如

{ 
    "_id": "0xWH4T3V3R", 
    "value": { 
     "key": { 
      "finally": ["here"], 
      "thisIsWhatIWanted": ["Yes!"] 
     } 
    } 
} 

這似乎是不必要的。

此外,執行其自己的插入的遊標甚至不是mapReduce的十分之一。我不太瞭解MongoDB以便進行基準測試,但我估計它會比較慢。有沒有辦法平行運行遊標?我不在乎我的collection_2中的文檔是否與collection_1中的文檔不同。

+0

它的工作原理的原因是因爲你的EMIT和減速機呼叫* *是相同的。既然你使用value [0]作爲你reducer的輸出,那麼它必須是完全相同的,因爲你沒有改變它(它只是通過你的reducer)。 – null 2010-08-30 23:47:53

回答

3

,但似乎尷尬,我不知道爲什麼它甚至還可以,因爲我在我的映射器調用emit論點是不等同於收益我的reducer的論點。

它們是等價的。 reduce函數接受一個T值的數組,並且應該返回同一個T格式的單個值。 T的格式由您的地圖功能定義。您的reduce函數只返回值數組中的第一個項目,它始終爲T。這就是爲什麼它的作品:)

你似乎是在正確的軌道上。我做了一些試驗,看起來你不能從地圖功能做db.collection.save(),但你可以通過做reduce函數。您的地圖功能應該簡單地構建您需要的文檔格式:

function map() { 
    emit(this._id, { _id: this.id, heading: this.title, body: this.content }); 
} 

地圖功能重用原始文檔的ID。這應該防止任何重新減少步驟,因爲沒有值將共享相同的密鑰。

減少功能可以簡單地返回null。但是,除此之外,您可以將的值寫入單獨的集合

function reduce(key, values) { 
    db.result.save(values[0]); 

    return null; 
} 

現在db.result應包含轉換文檔,而你不得不臨時集合中的任何附加的地圖,減少噪音。我沒有實際測試過大量數據,但這種方法應該利用map-reduce函數的並行執行。

+2

這種方式花了523s,最後收集了一個完全按照我想要的集合,而我在這個問題中描述的駭客方式需要319s。不幸的是,我不能只調用'db.coll.mapReduce(myMapperFunc,null,{'out':'output'})''。我認爲reduce可以批量保存/插入一整套物品;我認爲這裏的瓶頸是每個reduce都調用save()。 – chbrown 2010-08-28 18:24:56

+1

@chbrown:是的,'save()'爲每個文檔完成兩次;標準的reduce-save到臨時集合,並顯式保存到一個單獨的集合中。只是好奇,這個解決方案實際上比使用單個光標更快嗎? – 2010-08-28 19:49:23

+0

大家好,我們有一個類似的問題來處理大型數據集,並且由於數組連接和rtruning大文檔在reduce中不起作用,我們遵循上面提到的在獨立集合中保存文檔的方式,並從reduce中返回null。它的工作正常,但是當我們在運行mapreduce的時候進行任何其他操作時,db正在被吊死。有沒有比這更好的方法。 – MRK 2012-08-28 11:38:50

6

使用的map/reduce你將永遠與

{ "value" : { <reduced data> } } 

最終爲了去除value鍵,你將不得不使用一個finalize功能。

這裏是你可以做的將數據從一個集合複製到另一個簡單:

map = function() { emit(this._id, this); } 
reduce = function(key, values) { return values[0]; } 
finalize = function(key, value) { db.collection_2.insert(value); } 

然後,當你運行正常:

db.collection_1.mapReduce(map, reduce, { finalize: finalize }); 
+4

「Finalize函數不應以任何原因訪問數據庫。」 - [官方MongoDB文檔](http://docs.mongodb.org/manual/reference/command/mapReduce/#mapreduce-finalize-cmd) – bloudermilk 2014-01-28 22:01:24

+0

正確..但仍然有用,能夠這樣做。 – 2014-03-10 16:06:37

+0

這是一個完整的性能瓶頸,並且違背了Map-Reduce!請不要這樣做。 – 2017-10-24 09:51:07

0

我面臨同樣的情況。我能夠通過Mongo查詢和投影完成此任務。看到Mongo Query

1

當你有訪問蒙戈外殼,它接受一些JavaScript命令,然後它更簡單:

map = function(item){ 
     db.result.insert(item); 
} 

db.collection.find().forEach(map);