0

我有一个数据库,其中包含大致如下形式的文档:

{"created_at": some_datetime, "deleted_at": another_datetime, "foo": "bar"}

假设我们将来不需要处理“deleted_at”,那么获取数据库中未删除文档的计数是微不足道的。创建一个简化为以下内容的视图也很简单(使用 UTC):

[
  {"key": ["created", 2012, 7, 30], "value": 39},
  {"key": ["deleted", 2012, 7, 31], "value": 12}
  {"key": ["created", 2012, 8, 2], "value": 6}
]

...这意味着 39 个文档在 2012 年 7 月 30 日被标记为创建,12 个在 2012 年 7 月 31 日被标记为删除,依此类推。我想要的是一种有效的机制来获取 2012-08-01 (0+39-12 == 27) 上“存在”多少文档的快照。理想情况下,我希望能够以日期作为键或索引来查询视图或数据库(例如,已预先计算并保存到磁盘的东西),并将计数作为值或文档。例如:

[
  {"key": [2012, 7, 30], "value": 39},
  {"key": [2012, 7, 31], "value": 27},
  {"key": [2012, 8,  1], "value": 27},
  {"key": [2012, 8,  2], "value": 33}
]

这可以很容易地通过遍历视图中的所有行来计算,保持一个运行的计数器并在我每天进行时总结,但是随着数据集的增长,这种方法会变慢,除非我对缓存或存储结果。有没有更聪明的方法来解决这个问题?

4

2 回答 2

0

只是为了比较(我希望有人有更好的解决方案),这里(或多或少)我目前是如何解决它的(在未经测试的 ruby​​ 伪代码中):

require 'date'

def date_snapshots(rows)
  current_date  = nil
  current_count = 0
  rows.inject({}) {|hash, reduced_row|
    type, *ymd = reduced_row["key"]
    this_date  = Date.new(*ymd)
    if current_date
      # deal with the days where nothing changed
      (current_date.succ ... this_date).each do |date|
        key       = date.strftime("%Y-%m-%d")
        hash[key] = current_count
      end
    end
    # update the counter and deal with the current day
    current_date   = this_date
    current_count += reduced_row["value"] if type == "created_at"
    current_count -= reduced_row["value"] if type == "deleted_at"
    key       = current_date.strftime("%Y-%m-%d")
    hash[key] = current_count
    hash
  }
end

然后可以像这样使用它:

rows = couch_server.db(foo).design(bar).view(baz).reduce.group_level(3).rows
date_snapshots(rows)["2012-08-01"]

明显的小改进将是添加一个缓存层,尽管让该缓存层很好地播放增量更新(例如更改馈送)并不是那么简单。

于 2012-08-02T16:41:30.863 回答
0

我发现一种方法似乎比我原来的方法好得多,假设您只关心一个日期:

def size_at(date=Time.now.to_date)
  ymd = [date.year, date.month, date.day]
  added = view.reduce.
    startkey(["created_at"]).
    endkey(  ["created_at", *ymd, {}]).rows.first || {}
  deleted = view.reduce.
    startkey(["deleted_at"]).
    endkey(  ["deleted_at", *ymd, {}]).rows.first || {}
  added.fetch("value", 0) - deleted.fetch("value", 0)
end

基本上,让 CouchDB 为您进行缩减。我最初并没有意识到您可以将 reduce 与 startkey/endkey 混合搭配。

不幸的是,这种方法需要对数据库进行两次点击(尽管这些可以并行化或流水线化)。当您想一次获得很多这些尺寸时(例如,查看整个历史记录,而不是只查看一个日期),它就不起作用了。

于 2012-08-02T18:18:14.620 回答