我在沙发上有一个拥有55,000,000个文档的数据库。 许多文档对于某些属性具有重复值,并且我希望仅计算属性的唯一值。
我是couchdb新手并看到了列表功能,但这对于迭代超过5500万行并超时来说太慢了。
如果我这样做:
"map": "function(doc) { if (doc.property) { emit(doc.property, 1); } }"
"reduce": "_count"
然后分组,我得到包括重复在内的财产总数。 我怎样才能将它简化为唯一的?
感谢。
答案 0 :(得分:1)
你的地图功能没问题 - 你不能在这里做得更好。让我们专注于减少。
function(keys, values) {
var result = {};
var counter = 0;
keys.forEach(function(key) {
if (!result[key]) {
result[key] = true; // or whatever
counter++;
}
});
return counter;
}
答案 1 :(得分:0)
function(keys, values) {
var result = [];
keys.forEach(function(key) {
if (result.indexOf(key[0]) == -1) {
result.push(key[0]);
}
});
return result.length;
}
答案 2 :(得分:0)
我希望没有人在这里使用Mariusz接受的答案,因为它不起作用,至少在couchDB中
CouchDB reduce函数也需要执行rereduces。那就是减少其他几个减少的输出。
典型解决方案 使map函数输出一个唯一的键,然后使用_count减少。正是你在问题中建议的,除了group = true。 这将计算您拥有的每个独特事物的实例数。每一行都代表一种独特的东西。您可以轻松计算列表函数中的总行数。
<强>替代地强> 您可能不希望使密钥唯一,例如您可能有时间序列数据,并希望在特定时间范围内查询唯一值,然后您必须在密钥中包含日期时间。 处理这种情况很棘手。
选项1: 天真的解决方案是不计算唯一值,只是创建一个很大的唯一值列表,然后在客户端或后面的列表函数中计算它们。
function (keys, values, rereduce) {
var unique = {};
var getUniqueValues = function(values) {
for (i = 0; i < values.length; i++) {
if (values[i] in unique) {
} else {
unique[values[i]] = null;
}
}
}
if (rereduce === true) {
for (j = 0; j < values.length; j++) {
getUniqueValues(values[j]);
};
return Object.keys(unique);
} else {
getUniqueValues(values);
return Object.keys(unique);
}
}
选项2: 另一种选择是根本不减少,只计算列表函数中的唯一值。正如你所说,当有很多值时,这可能会变慢。
选项3: 在计算大量独特的东西时避免使用过多的内存是棘手的。 可以通过将唯一值散列到位图上的位来完成。 然后计算最终位图中有多少1个。
这也允许您使用reduce函数,因为您可以组合位图来组合您的独特结果。然后最后在客户端或列表函数中计算位图中的1。
我还没有在couchdb中尝试过这个,但理论是合理的:http://highscalability.com/blog/2012/4/5/big-data-counting-how-to-count-a-billion-distinct-objects-us.html
唯一需要注意的是,如果位图不够大,可能会出现一个小错误。但是,当您计算非常大的数量时,通常可以接受一个小错误。
答案 3 :(得分:0)
使用新的JavaScript功能,您可以使用Set ,该Set只允许一个值出现一次。本示例使用获取数据库中列出的所有唯一水果的方法。不必在map函数中发出值。
示例文档布局:
{
"type": "fruits",
"item": "orange",
...whatever else
}
地图:
function (doc) {
if(doc.type === 'fruits') {
emit(doc.item, null)
}
}
减少:
function (keys, values) {
const fruits = new Set()
for(const key of keys)
if(!fruits.has(key)) fruits.add(key)
return fruits
}