【问题标题】:How do you write a SELECT COUNT(DISTINCT field) query in CouchDB?如何在 CouchDB 中编写 SELECT COUNT(DISTINCT field) 查询?
【发布时间】:2011-11-15 07:15:14
【问题描述】:

有没有一种好方法可以模拟 CouchDB 中 SELECT COUNT(DISTINCT field) 的行为?

假设我们有以下文档,它记录了用户播放某首歌曲的时间:

{
  song_id: "happy birthday",
  user_id: "boris",
  date_played: [2011, 11, 14, 00, 12, 55],
  _id: ...
}

我想知道我们的用户“boris”播放过的不同歌曲的数量。如果我们的用户已经听了 20 次“生日快乐”,那首歌曲应该仍然只为总歌曲数贡献 +1。

在 MySQL 中,我会简单地执行 SELECT COUNT(DISTINCT song_id) FROM plays WHERE user_id = "boris",但在 CouchDB 中编写它时,我是在画一个空白。

解决方法 1: 如果我更改架构并将所有歌曲播放存储在单个用户文档中以供“boris”使用,那么我可以编写一个地图以仅发出不同的值。但是,如果我想在 last.fm 的规模上构建一些东西,我担心随着“boris”文档大小(播放次数)的持续增长,更新将开始花费很长时间。 (我最终可能会达到最大文档大小)。

解决方法 2: 我还可以编写一个映射函数来返回 所有 不同的记录,我的 Python 脚本可以自行总结这些记录;但同样有数十万首不同的歌曲,这也会变得非常缓慢。

我还缺少哪些其他选项?

【问题讨论】:

  • 我也考虑过简单地将这些信息写成一个单独的文档:检查 (user_id, song_id) 是否已经存在,如果存在则更新时间戳,否则插入新文档。但我希望我可以使用 CouchDB 的增量 map/reduce 更新来为我构建这个缓存​​。

标签: couchdb


【解决方案1】:

此答案由 zachary Zolton 在 couchdb 邮件列表中提供:

http://mail-archives.apache.org/mod_mbox/couchdb-user/201111.mbox/%3CCAGnHtbJ-1-YeLWMLivKzWub98HZY7%2BesnPOHU4pEYgWAsxaszA%40mail.gmail.com%3E

既然您已经获得了一个可以为您提供 Boris 的 50k 独特的视图 歌曲,您可以使用 _list 函数返回行数。

这样的事情应该可以解决问题:

function() {
 var count = 0;
 while(getRow()) count++;
 return JSON.stringify({count: count});
}

如果查询此列表函数,具有相同的视图、键范围和 组级别,它只会响应一些 JSON,例如:{"count":"50612"}

您可以在这里阅读更多内容:

【讨论】:

    【解决方案2】:

    假设我正确解释了您的问题;

    地图:

    function(doc) {
      emit([doc.user_id, doc.song_id], null);
    }
    

    减少:

    _count
    

    查询:

    ?startkey=[<userid>]&endkey=[<userid>,{}]&group=true
    

    样本输出:

    http://127.0.0.1:5984/foo/_design/a/_view/b?group=true&
    startkey=[%22foo%22]&endkey=[%22foo%22,{}]
    
    {"rows":[
      {"key":["foo","bar"],"value":2},
      {"key":["foo","bazbar"],"value":1}
    ]}
    

    【讨论】:

    • 这个 map/reduce 会给你 (["boris", "happybirthday"], 20), (["boris", "yesterday"], 14), ...,但是如果用户已听过 50,000 首不同的歌曲,则此查询将返回 50,000 条不同的行。基本上我想要返回的只是标量值 50,000。
    【解决方案3】:

    我一直在为同样的事情苦苦挣扎(见http://mail-archives.apache.org/mod_mbox/couchdb-user/201410.mbox/browser

    当您只需要一个标量值时,获得所有这些输出感觉并不合适。尽管列表函数是一种无法获得完整结果流的解决方法,但这种方法感觉很奇怪。

    有其他方法吗?

    【讨论】:

      【解决方案4】:

      在最新版本的 CouchDB (>2.2) 中,您可以使用 _approx_count_distinct reduce 函数。你的看法是:

      地图:

      function(doc) {
          emit([doc.user_id, doc.song_id], 1);
      }
      

      减少:

      _approx_count_distinct
      

      获取用户“boris”的歌曲 ID 计数的查询将是:

      /db/_design/_myddoc/_view/myview?group_level=1&key=["boris"]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-02
        • 1970-01-01
        • 2016-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-28
        相关资源
        最近更新 更多