mongodb使用map reduce从其他集合中插入嵌入文档海量集合
Posted
技术标签:
【中文标题】mongodb使用map reduce从其他集合中插入嵌入文档海量集合【英文标题】:mongodb insert embedded documents from other collections massive collections using map reduce 【发布时间】:2014-12-05 00:51:05 【问题描述】:我将获得的这些文件每个至少有一百万行,最多 15 亿行。当我得到它时,数据是标准化的。我需要一种将其存储在 one 文档中的方法。在大多数情况下,我不是 100% 将如何将数据提供给我。它可以是 csv、固定宽度文本文件或 tsv 或其他。
目前我有一些从一些示例 csv 导入的集合。
下面是我的数据缺失字段的小表示
在我的 beneficaries.csv 中,数据重复
beneficaries.csv 超过 600 万条记录
record # 1
"userid":"a9dk4kJkj",
"gender":"male",
"dob":20080514,
"start_date":20000101,
"end_date":20080227
record # 2
"userid":"a9dk4kJkj",
"gender":"male",
"dob":20080514,
"start_date":20080201,
"end_date":00000000
same user different start and end dates
claims.csv 超过 2 亿条记录
"userid":"a9dk4kJkj",
"date":20080514,
"code":"d4rd3",
"blah":"data"
lab.csv 超过 1000 万条记录
"userid":"a9dk4kJkj",
"date":20080514,
"lab":"mri",
"blah":"data"
根据我有限的知识,我有三个选择
对文件进行排序,从数据文件中读取我们的 c++ 成员对象中的 x 数量,在 y 处停止,将成员插入 mongodb,继续从 y 开始为 x 个成员,直到我们完成。这是测试过并且工作,但是对如此大量的文件进行排序会导致我们的机器好几个小时。
加载数据到sql,一一读入c++成员对象,批量加载mongo中的数据。经过测试并且可以工作,但是我非常想避免这种情况。
在单独的集合中加载 mongo 中的文档,并执行不带参数的映射缩减以写入集合。我在每个文件自己的集合中加载了文档(如上所示)。不幸的是,我是 mongo 的新手,并且在截止日期前。减少地图的概念对我来说很难理解和实施。我已阅读文档并尝试在堆栈溢出时使用此答案MongoDB: Combine data from multiple collections into one..how?
输出 member 集合应如下所示。
"userid":"aaa4444",
"gender":"female",
"dob":19901225,
"beneficiaries":["start_date":20000101,
"end_date":20080227,
"start_date":20008101,
"end_date":00000000],
"claims":["date":20080514,
"code":"d4rd3",
"blah":"data",
"date":20080514,
"code":"d4rd3",
"blah":"data"],
"labs":["date":20080514,
"lab":"mri",
"blah":"data"]
将数据加载到 sql、用 c++ 读取并插入 mongodb 的性能是否会超过 map reduction?如果是这样,我会坚持这种方法
【问题讨论】:
【参考方案1】:恕我直言,您的数据是 map-reduce 的良好候选者,因此最好选择选项 3:在 3 个单独的集合中加载 mongo 中的文档:beneficiaries
、claims
、labs
并执行 map-减少每个集合上的 userid
键。最后,使用 userid
键上的 find 和 insert 将 3 个集合中的数据整合到单个集合中。
假设您将beneficiaries.csv
加载到集合beneficiaries
中,这是受益人的map-reduce 示例代码:
mapBeneficiaries = function()
var values =
start_date: this.start_date,
end_date: this.end_date,
userid: this.userid,
gender: this.gender,
dob: this.dob
;
emit(this.userid, values);
;
reduce = function(k, values)
list = beneficiaries: [], gender : '', dob: '';
for(var i in values)
list.beneficiaries.push(start_date: values[i].start_date, end_date: values[i].end_date);
list.gender = values[i].gender;
list.dob = values[i].dob;
return list;
;
db.beneficiaries.mapReduce(mapBeneficiaries, reduce, "out": "reduce": "mr_beneficiaries");
mr_beneficiaries
中的输出将是这样的:
"_id" : "a9dk4kJkj",
"value" :
"beneficiaries" : [
"start_date" : 20080201,
"end_date" : 0
,
"start_date" : 20080201,
"end_date" : 0
],
"gender" : "male",
"dob" : 20080514
做同样的事情来获得mp_claims
和mp_labs
。然后融入singledocuments
:
db.mr_beneficiaries.find().forEach(function(doc)
var id = doc._id;
var claims = db.mr_claims.findOne("_id":id);
var labs = db.mr_lab.findOne("_id":id);
db.singledocuments.insert("userid":id,
"gender":doc.value.gender,
"dob":doc.value.dob,
"beneficiaries":doc.value.beneficiaries,
"claims":claims.value.claims,
"labs":labs.value.labs);
);
【讨论】:
我不能使用地图缩减来插入声明和实验室?那不会跑得更快 我也会发现一个人不会这样做,有多个索赔和多个实验室 mapreduce 之后,每个用户 ID 都会有一个声明/实验室列表,所以 findOne 没问题 您可以使用 mapreduce 通过设置相同的 "out" 将索赔和实验室插入到 mr_beneficiaries 的同一文档中。但是输出格式不是你想要的 我认为对我来说最好的解决方案是将每个 csv 放在一个集合中,然后使用 map reduce by id 并形成新的集合。由于用户 id 被全部使用,这应该可以正常工作。感谢您提供了有效的受益示例并演示了我如何在这些数据上使用 map reduce。在我对我熟悉的数据运行您的工作示例之前,我很难从文档中掌握这个概念以上是关于mongodb使用map reduce从其他集合中插入嵌入文档海量集合的主要内容,如果未能解决你的问题,请参考以下文章