仅计算唯一的couchdb行

snz8szmq  于 2022-12-09  发布在  CouchDB
关注(0)|答案(4)|浏览(149)

我有一个数据库在沙发上与55,000,000文档。许多文档有重复的值为某些属性,我想得到一个计数只有唯一的值为一个属性。
我是couchdb的新手,看到了list函数,但是对于迭代超过5500万行和超时来说,这太慢了。
如果我这样做:
"map": "function(doc) { if (doc.property) { emit(doc.property, 1); } }" "reduce": "_count"
和group,我得到了包括重复项的属性总数。我怎样才能把它减少到只有uniques?

  • 谢谢-谢谢
zvokhttg

zvokhttg1#

你的Map功能还可以--你在这里做得再好不过了。让我们把注意力集中在reduce上。

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

  return counter;
}
v9tzhpje

v9tzhpje2#

我希望这里没有人使用Mariusz的公认答案,因为它不起作用,至少在couchDB中不起作用
CouchDB reduce函数也需要执行rereduce。也就是减少其他几个reduce的输出。

典型的解决方案让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
一个警告是,如果位图不够大,可能会有一个小误差。然而,当你计算非常大的数量时,一个小误差通常是可以接受的。

wqsoz72f

wqsoz72f3#

function(keys, values) {
  var result = [];
  keys.forEach(function(key) {
      if (result.indexOf(key[0]) == -1) {
          result.push(key[0]);
      }
  });

  return result.length;
}
1cklez4t

1cklez4t4#

使用较新的JavaScript特性,你可以使用Set,它只允许一个值出现一次。这个例子使用了获取数据库中列出的所有唯一的水果。也不需要在map函数中发出一个值。

  • 示例文档布局 *:
{
    "type": "fruits",
    "item": "orange",
    ...whatever else
}
  • Map *:
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
}

相关问题