在MongoDB mapreduce中,如何展平值对象?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在MongoDB mapreduce中,如何展平值对象?相关的知识,希望对你有一定的参考价值。
我正在尝试使用MongoDB来分析Apache日志文件。我从Apache访问日志中创建了一个receipts
集合。以下是我的模型外观的精简摘要:
db.receipts.findOne()
{
"_id" : ObjectId("4e57908c7a044a30dc03a888"),
"path" : "/videos/1/show_invisibles.m4v",
"issued_at" : ISODate("2011-04-08T00:00:00Z"),
"status" : "200"
}
我写了一个MapReduce function,它按照issued_at
日期字段对所有数据进行分组。它总结了请求的总数,并提供了每个唯一路径的请求数的细分。以下是输出结果的示例:
db.daily_hits_by_path.findOne()
{
"_id" : ISODate("2011-04-08T00:00:00Z"),
"value" : {
"count" : 6,
"paths" : {
"/videos/1/show_invisibles.m4v" : {
"count" : 2
},
"/videos/1/show_invisibles.ogv" : {
"count" : 3
},
"/videos/6/buffers_listed_and_hidden.ogv" : {
"count" : 1
}
}
}
}
如何使输出看起来像这样:
{
"_id" : ISODate("2011-04-08T00:00:00Z"),
"count" : 6,
"paths" : {
"/videos/1/show_invisibles.m4v" : {
"count" : 2
},
"/videos/1/show_invisibles.ogv" : {
"count" : 3
},
"/videos/6/buffers_listed_and_hidden.ogv" : {
"count" : 1
}
}
}
目前还不可能,但我建议投票支持这个案例:https://jira.mongodb.org/browse/SERVER-2517。
从以前的答案和评论中获取最佳效果:
db.items.find().hint({_id: 1}).forEach(function(item) {
db.items.update({_id: item._id}, item.value);
});
来自http://docs.mongodb.org/manual/core/update/#replace-existing-document-with-new-document
“如果update
参数仅包含字段和值对,则update()
方法将现有文档替换为update
参数中的文档,但_id
字段除外。”
所以你既不需要$unset value
,也不需要列出每个字段。
来自https://docs.mongodb.com/manual/core/read-isolation-consistency-recency/#cursor-snapshot“在某些情况下,MongoDB游标可以多次返回同一文档。...在此字段或这些字段上使用唯一索引,以便查询将返回每个文档不超过一次。使用提示()查询强制查询使用该索引。“
AFAIK,按照设计Mongo的map reduce会在“值元组”中吐出结果,而我没有看到任何可以配置“输出格式”的东西。也许可以使用finalize()方法。
您可以尝试运行将使用重新整形数据的后处理
results.find({}).forEach( function(result) {
results.update({_id: result._id}, {count: result.value.count, paths: result.value.paths})
});
是的,看起来很难看。我知道。
您可以使用集合参考来执行Dan的代码:
function clean(collection) {
collection.find().forEach( function(result) {
var value = result.value;
delete value._id;
collection.update({_id: result._id}, value);
collection.update({_id: result.id}, {$unset: {value: 1}} ) } )};
与@ljonas类似的方法,但不需要硬编码文档字段:
db.results.find().forEach( function(result) {
var value = result.value;
delete value._id;
db.results.update({_id: result._id}, value);
db.results.update({_id: result.id}, {$unset: {value: 1}} )
} );
所有提出的解决方案都远非最佳。到目前为止,你能做到的最快的是:
var flattenMRCollection=function(dbName,collectionName) {
var collection=db.getSiblingDB(dbName)[collectionName];
var i=0;
var bulk=collection.initializeUnorderedBulkOp();
collection.find({ value: { $exists: true } }).addOption(16).forEach(function(result) {
print((++i));
//collection.update({_id: result._id},result.value);
bulk.find({_id: result._id}).replaceOne(result.value);
if(i%1000==0)
{
print("Executing bulk...");
bulk.execute();
bulk=collection.initializeUnorderedBulkOp();
}
});
bulk.execute();
};
然后称之为:flattenMRCollection("MyDB","MyMRCollection")
这比顺序更新更快。
在尝试Vincent的回答时,我发现了一些问题。基本上,如果在foreach循环中执行更新,则会将文档移动到集合的末尾,并且光标将再次到达该文档(example)。如果使用$snapshot,可以规避这一点。因此,我在下面提供一个Java示例。
final List<WriteModel<Document>> bulkUpdate = new ArrayList<>();
// You should enable $snapshot if performing updates within foreach
collection.find(new Document().append("$query", new Document()).append("$snapshot", true)).forEach(new Block<Document>() {
@Override
public void apply(final Document document) {
// Note that I used incrementing long values for '_id'. Change to String if
// you used string '_id's
long docId = document.getLong("_id");
Document subDoc = (Document)document.get("value");
WriteModel<Document> m = new ReplaceOneModel<>(new Document().append("_id", docId), subDoc);
bulkUpdate.add(m);
// If you used non-incrementing '_id's, then you need to use a final object with a counter.
if(docId % 1000 == 0 && !bulkUpdate.isEmpty()) {
collection.bulkWrite(bulkUpdate);
bulkUpdate.removeAll(bulkUpdate);
}
}
});
// Fixing bug related to Vincent's answer.
if(!bulkUpdate.isEmpty()) {
collection.bulkWrite(bulkUpdate);
bulkUpdate.removeAll(bulkUpdate);
}
注意:此代码段平均需要7.4秒才能在我的计算机上执行,包含100k条记录和14个属性(IMDB数据集)。没有批处理,平均需要25.2秒。
以上是关于在MongoDB mapreduce中,如何展平值对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Hive/Pig/MapReduce 展平递归层次结构
MongoDB MapReduce - 发出一个键/一个值不调用reduce