我正在设计能够处理数百万个文档并以不同方式报告它们的系统。 mongoDb map \ reduce task是我正在尝试实现的(目前正在对此进行一些调查)。 最基本的文档结构是
db.test.insert(
{
"_id" : ObjectId("4f6063601caf46303c36eb27"),
"verbId" : NumberLong(1506281),
"sentences" : [
{
"sId" : NumberLong(2446630),
"sentiment" : 2,
"categories" : [
NumberLong(3257),
NumberLong(3221),
NumberLong(3291)
]
},
{
"sId" : NumberLong(2446631),
"sentiment" : 0,
"categories" : [
NumberLong(2785),
NumberLong(2762),
NumberLong(2928),
NumberLong(2952)
]
},
{
"sId" : NumberLong(2446632),
"sentiment" : 0,
"categories" : [
NumberLong(-2393)
]
},
{
"sId" : NumberLong(2446633),
"sentiment" : 0,
"categories" : [
NumberLong(-2393)
]
}
]
})
这样每个文档都包含可能属于不同类别的句子。 我想要得到的报告是类别中的句子数量(以动词的百分比表示)。
我正在使用 finalize 方法执行下一个map-reduce作业,以计算不同的平均值。
var map = function() {
var docCategories = new Array();
var catValues = new Array();
for (var i = 0; i < this.sentences.length; i++) { //iterate over sentences.
sentence = this.sentences[i];
for (var j = 0; j < sentence.categories.length; j++) {//iterate over categories
catId= sentence.categories[j].toNumber();
if (docCategories.indexOf(catId) < 0) {
docCategories.push(catId);
catValues.push({sentiment : sentence.sentiment, sentenceCnt: 1});
} else {
categoryIdx = docCategories.indexOf(catId);
catValue = catValues[categoryIdx];
catValue.sentiment = catValue.sentiment + sentence.sentiment;
catValue.sentenceCnt = catValue.sentenceCnt + 1;
}
}
}
totalCount++; //here we do try to count distinctCases see scope.
for (var i = 0; i < docCategories.length; i ++) {
emit(docCategories[i], {count: 1, sentenceCnt: catValues[i].sentenceCnt, sentiment: catValues[i].sentiment, totalCnt : totalCount});
}
};
var reduce = function(key, values) {
var res = {count : 0, sentenceCnt : 0, sentiment : 0};
for ( var i = 0; i < values.length; i ++ ) {
res.count += values[i].count;
res.sentenceCnt += values[i].sentenceCnt;
res.sentiment += values[i].sentiment;
}
return res;
};
var finalize = function(category, values) {
values.sentimentAvg = values.sentiment / values.sentenceCnt;
values.percentOfVerbatim = values.count / totalCount //scope variable (global)
return values;
};
var res = db.runCommand( { mapreduce:'test',
map:map,
reduce:reduce,
out: 'cat_volume',
finalize:finalize,
scope:{totalCount : 0},
});
这里最有趣的部分是我正在使用totalCount - 来计算我正在发出的数字。 totalCount是范围(全局)变量。 在一个mongoDb安装上一切顺利,但是当进入分片实例时我为 percentOfVerbatim 获得“无限”。
实际上在那种情况下 totalCount 只是 db.test.count()(文件数量)但是将来我会为文件添加不同的条件值得数。 执行任何其他查询是非常不受欢迎的,因为db非常繁重。
在多实例mongodb安装中是否还有其他方法可以使用全局(范围)变量?或者我应该使用其他东西吗?
答案 0 :(得分:2)
范围变量不在分片之间共享。您可以将其视为全局常量。对于映射或减少在不同分片上运行的函数,将无法看到对值的更新。
答案 1 :(得分:0)
最后,我找到了如何计算我发出的文件数量的方法。 对我有用的唯一方法是发出documentId,并在reduce上将id放入数组中。 在客户端(我正在编写java程序)我必须计算所有不同的ID。 所以,在做地图时我会发出
emit(docCategories[i], {verbIds : [this.verbId.toNumber()], count: 1, sentenceCnt: catValues[i].sentenceCnt, sentiment: catValues[i].sentiment, totalCnt : totalCount});
减少功能如下:
var reduce = function(key, values) {
var res = {verbIds : [], count : 0, sentenceCnt : 0, sentiment : 0};
for ( var i = 0; i < values.length; i ++ ) {
// res.verbIds = res.verbIds.concat(values[i].verbIds); //works slow
for ( var j = 0; j < values[i].verbIds.length; j ++ ) {
res.verbIds.push(values[i].verbIds[j]);
}
res.count += values[i].count;
res.sentenceCnt += values[i].sentenceCnt;
res.sentiment += values[i].sentiment;
}
return res;
};
Java端程序只计算所有结果的不同ID。
实际上,1.1M文件的执行速度明显减慢