2010-08-27 135 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);