【问题标题】:Counting unique keys in Couchbase views计算 Couchbase 视图中的唯一键
【发布时间】:2014-06-25 16:17:38
【问题描述】:

我正在尝试找出一种方法来计算存储桶中非主键的唯一值的数量。 Couchbase 2.5 提供了一个 n1ql 方法来做到这一点。如果我们使用他们的啤酒样本,您可以发出以下命令:

从啤酒样本中选择计数(独特风格)

返回标量值 68。

我使用的是 couchbase 2.2.0,它在技术上没有 n1ql。如果可能的话,我想利用 map/reduce/rereduce 功能。原因是我有 100 条数百万条记录,并且临时查询可能需要几天时间才能运行。有这样的方法吗?

对于地图功能,我有以下内容:

function (doc, meta) {
     if ( doc.type == "beer")
       emit(doc.style, doc.style);
}

对于reduce,我有以下内容:

function(key, values, rereduce) {
    var u = {}, a = [];
    var results = {};

    if (rereduce) {

      for (var i = 0; i < values.length; i ++ ) {
        for ( var j = 0; j < values[i].length; j ++ ) {
          if (u.hasOwnProperty(values[i][j])) {
            continue;
          }

          a.push(values[i][j]);
          u[values[i][j]] = 1;
        }
      }
      return (a); 
    } else {  
      for(var i = 0; i < values.length; i++) {
        if (u.hasOwnProperty(values[i])) {
          continue;
        }

        a.push(values[i]);
        u[values[i]] = 1;
      } 
      return(a);  
  }
}

这将返回一个具有唯一值但不是标量计数的数组。有什么办法可以得到独特啤酒风格的标量计数?谢谢。

【问题讨论】:

    标签: map unique couchbase reduce scalar


    【解决方案1】:

    解决方案相对简单(至少对于视图而言)。

    首先,不需要将文档/啤酒样式输出为值,因此您的地图功能会更好:

    function (doc, meta) {
        if (doc.type == "beer") {
            emit(doc.style, null)
        }
    }
    

    接下来,只需使用内置的_countreduce函数即可。

    默认情况下,这将简单地输出您正在计数的存储桶中所有文档的计数,但是通过调用 map 函数并将过滤器参数 group 设置为 truegroup level 设置为 1(具体方法将根据您的客户端 SDK 有所不同)。这样做会返回一个类似如下的对象数组:

    {"rows":[
    {"key":null,"value":1111},
    {"key":"American Rye Ale or Lager","value":11},
    {"key":"American-Style Amber/Red Ale","value":219},
    {"key":"American-Style Barley Wine Ale","value":32},
    {"key":"American-Style Brown Ale","value":187},
    {"key":"American-Style Cream Ale or Lager","value":12},
    {"key":"American-Style Dark Lager","value":1},
    {"key":"American-Style Imperial Stout","value":55},
    {"key":"American-Style India Black Ale","value":1},
    {"key":"American-Style India Pale Ale","value":230},
    {"key":"American-Style Lager","value":370},
    {"key":"American-Style Light Lager","value":39},
    {"key":"American-Style Pale Ale","value":393},
    {"key":"American-Style Stout","value":241},
    {"key":"American-Style Strong Pale Ale","value":8}
    …
    …
    ]
    }
    

    可以使用key 过滤器参数使该数组更小(在这种情况下,键是特定样式(或您希望计算的任何内容)),或者类似地,您可以从该客户端中选择一边。

    【讨论】:

    • value 等于该值的文档数)
    • _count reduce 也得到了高度优化,因此即使是数百万个文档,它也不会使用过多的资源。查询命中索引,因此唯一的问题可能是该索引的读取/查询次数。索引更新是增量的,因此即使在添加/更新文档时,除非一次更新数百万,否则在初始索引构建后也不应该产生太多开销(请参阅here)。
    • 为了进一步澄清“读取/查询”可能是一个潜在问题,这意味着这里唯一的问题是通常的数据库读取瓶颈(磁盘 I/O 和空间、带宽和RAM 没有被 Couchbase 使用)。
    • @Mwuk ...感谢您的输入,但这并不能回答原始问题。我需要所有独特啤酒风格的标量值计数,而不是每种风格计数的列表。在我的情况下,过滤密钥没有帮助,也无法完成。还有其他想法吗?谢谢。
    • @user3775720 经过一些修补后,我认为要做的事情是执行我上面详述的分组计数,然后计算在您的 SDK 中返回客户端的行(您将使用哪个 SDK using - 如果您告诉我您(打算)使用哪种特定语言,我可以尝试并详细说明。
    【解决方案2】:

    如果不同组的数量不会太大,请尝试在 reduce 函数中传递关联数组。

    在啤酒样品桶中:

    /**
     * Map function
     */
    function (doc, meta) {
      if (doc.type == "beer" && doc.style)
        emit(doc.style, null);
    }
    
    /**
     * Reduce function
     */
    function (keys, values, rereduce) {
      count_by_key = {};
      if (rereduce) {
        for (i in values) {
          _count_by_key = values[i];
          for (key in _count_by_key) {
            count_by_key[key] = _count_by_key[key] + (count_by_key[key] || 0);
          }
        }
      } else {
        if (keys)
          for (i in keys) {
            key = keys[i];
            count_by_key[key] = 1 + (count_by_key[key] || 0);
          }
      }
      return count_by_key; 
    }
    

    结果值中的键数将是独特啤酒风格的标量计数。它也适用于关键过滤器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-06
      • 1970-01-01
      • 2019-05-05
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      • 2013-04-04
      相关资源
      最近更新 更多