2012-08-02 81 views
0

我有那些的大致形式文檔的數據庫:CouchDB的歷史觀快照

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

這是小事來獲得在DB非刪除的文件的計數,假設我們不需要在將來處理「deleted_at」。這也是微不足道的創建,降低到類似下面的(使用UTC)一個觀點:

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

...這意味着,在創建2012-07-30 39個文件被標記,12標記爲刪除在2012-07-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} 
] 

這可以計算很輕鬆地通過所有視圖中的行的迭代,保持運行計數器,每天總結,因爲我去,但這種方法減慢隨着數據集增長較大,除非我聰明地緩存或存儲結果。有沒有更聰明的方法來解決這個問題?

回答

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的爲你做的減少。我最初並沒有意識到你可以用startkey/endkey混合和匹配reduce。

不幸的是,這種方法需要兩個命中數據庫(雖然這些可以並行或流水線)。當你想要一次獲得大量的這些尺寸時(例如,查看整個歷史,而不是看一個日期),它不會奏效。

0

只是爲了比較的緣故(我希望有人有更好的解決方案),這裏是(或多或少)我如何解決目前它(在未經測試的紅寶石僞代碼):

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"] 

明顯小的改進是添加一個緩存層,但它是不是很瑣碎,使該緩存層發揮很好的增量更新(如改變飼料)。