2

我在沙发上有一个数据库,里面有 55,000,000 个文档。许多文档对某些属性都有重复的值,我想只计算一个属性的唯一值。

我是 couchdb 的新手,看到了 list 函数,但这对于迭代超过 5500 万行和超时来说太慢了。

如果我做:

"map": "function(doc) { if (doc.property) { emit(doc.property, 1); } }" "reduce": "_count"

然后分组,我得到包括重复项在内的财产总数。我怎样才能把这个减少到唯一的?

谢谢。

4

4 回答 4

1

您的地图功能还可以 - 您不能在这里做得更好。让我们专注于减少。

function(keys, values) {
  var result = {};
  var counter = 0;
  keys.forEach(function(key) { 
    if (!result[key]) {
      result[key] = true; // or whatever
      counter++;
    }
  });

  return counter;
}
于 2014-11-09T11:06:08.720 回答
1

我希望没有人在这里使用 Mariusz 接受的答案,因为它不起作用,至少在 couchDB 中

CouchDB reduce 函数也需要执行 rereduce。那就是减少其他几个减少的输出。

典型解决方案 让你的map函数输出一个唯一的key,然后用_count做reduce。正是您在问题中提出的建议,除了 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-对象-us.html

需要注意的是,如果位图不够大,可能会出现小错误。但是,当您计算非常大的数量时,通常可以接受一个小的错误。

于 2016-03-31T03:40:59.827 回答
0
function(keys, values) {
  var result = [];
  keys.forEach(function(key) {
      if (result.indexOf(key[0]) == -1) {
          result.push(key[0]);
      }
  });

  return result.length;
}
于 2014-11-10T10:30:05.370 回答
0

使用较新的 JavaScript 功能,您可以使用 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
}
于 2020-07-23T17:13:38.110 回答