2013-03-13 72 views
11

我有一個數據庫(couchDB),其中包含約90k的文檔。這些文件都是這樣非常簡單:非常緩慢的couchDB過濾器甚至與erlang

{ 
    "_id": "1894496e-1c9e-4b40-9ba6-65ffeaca2ccf", 
    "_rev": "1-2d978d19-3651-4af9-a8d5-b70759655e6a", 
    "productName": "Cola" 
} 

現在我想有一天這個數據庫與移動設備同步。很明顯,90k文檔不應該一次全部打到手機上。這就是我寫過濾器功能的原因。這些應該由「productName」過濾。最初在Javascript中使用Javascript來獲得性能。這些過濾器的功能看起來像這樣在JavaScript:

{ 
    "_id": "_design/local_filters", 
    "_rev": "11-57abe842a82c9835d63597be2b05117d", 
    "filters": { 
     "by_fanta": "function(doc, req){ if(doc.productName == 'Fanta'){ return doc;}}", 
     "by_wasser": "function(doc, req){if(doc.productName == 'Wasser'){ return doc;}}", 
     "by_sprite": "function(doc, req){if(doc.productName == 'Sprite'){ return doc;}}" 
    } 
} 

像這樣在二郎:

{ 
    "_id": "_design/erlang_filter", 
    "_rev": "74-f537ec4b6508cee1995baacfddffa6d4", 
    "language": "erlang", 
    "filters": { 
     "by_fanta": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Fanta\">> -> true; _ -> false end end.", 
     "by_wasser": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Wasser\">> -> true; _ -> false end end.", 
     "by_sprite": "fun({Doc}, {Req}) -> case proplists:get_value(<<\"productName\">>, Doc) of <<\"Sprite\">> -> true; _ -> false end end."  
    } 
} 

爲了簡單起見沒有查詢又而是一個「硬編碼」字符串。過濾器都可以工作。問題是他們正在慢下來。我後來在Perl中首先編寫了一個測試程序,用於測試過濾文檔所需的時間。這裏是我的一個Perl腳本:

$dt = DBIx::Class::TimeStamp->get_timestamp(); 

$content = get("http://127.0.0.1:5984/mobile_product_test/_changes?filter=local_filters/by_sprite"); 

$dy = DBIx::Class::TimeStamp->get_timestamp() - $dt; 
$dm = $dy->minutes(); 
$dz = $dy->seconds(); 

@contArr = split("\n", $content); 

$arraysz = @contArr; 
$arraysz = $arraysz - 3; 

$\="\n"; 
print($dm.':'.$dz.' with '.$arraysz.' Elements (JavaScript)'); 

而現在這個可悲的部分。這些是我得到的時間:

2:35 with 2 Elements (Erlang) 
2:40 with 10000 Elements (Erlang) 
2:38 with 30000 Elements (Erlang) 
2:31 with 2 Elements (JavaScript) 
2:40 with 10000 Elements (JavaScript) 
2:51 with 30000 Elements (JavaScript) 

btw這些是分鐘:秒。數字是過濾器返回的元素數量,數據庫中有90k個元素。令人驚訝的是,Erlang過濾器一點都不快。

要請求所有元素只需要9秒。並創建約15的意見。但我不可能在手機上使用傳輸所有文件(音量和安全原因)。

有沒有辦法在視圖上過濾以獲得性能提升? 或者我的erlang過濾器函數有問題(我對JavaScript過濾器的時間並不感到驚訝)。

編輯: 正如pgras指出的,爲什麼這是緩慢的原因發佈在this問題的答案中。爲了讓erlang過濾器運行得更快,我需要下面的「圖層」,並將erlang直接編程到數據庫中,而不是_design文檔。但我真的不知道從哪裏開始以及如何做到這一點。任何提示將有所幫助。

+0

你,因爲參數使用_changes沒有,所以它會過濾數據庫的所有內容,一旦第一同步你打算使用since參數進行後續同步嗎?你提到使用視圖,用快捷鍵「Fanta」快速查看解決你的其他需求? – pgras 2013-03-13 16:06:10

+0

我想稍後使用過濾器將數據庫複製到移動設備,我只使用http請求來測試過濾器。我嘗試使用過濾器進行復制,並得到了類似的結果。我不認爲一個視圖會有幫助,因爲稍後會有一個過濾器查詢。 – 2013-03-13 16:32:49

+0

經歷同樣的事情。使用Erlang進行過濾複製時,我獲得了大約55%的提升,但仍然非常緩慢。 – ryan1234 2013-03-14 23:01:08

回答

3

這已經有一段時間,因爲我問這個問題。但我想我會回到它並分享我們最終做的解決方案。

那麼簡單的答案是過濾速度不能真正得到改善。

原因在於過濾器的工作方式。如果你檢查你的數據庫更改。他們在這裏:

http://<ip>:<port>/<databaseName>/_changes 

本文檔包含屬於您的數據庫的所有更改。如果您在數據庫中執行任何操作,只需添加新行。當一個人現在想要使用過濾器時,過濾器將從json解析爲指定的語言,並用於該文件中的每一行。要清楚,據我所知,解析也是爲每一行完成的。這不是非常有效率,不能改變。

所以我個人認爲對於大部分使用情況過濾器是緩慢而無法使用。這意味着我們必須找到解決辦法。我並不意味着我有一個通用的解決方案。我只能說,對我們來說,可以使用視圖而不是過濾器。視圖在內部生成樹木,與過濾器相比,它與光線一樣快。一個簡單的過濾器還存儲的設計文檔中,可能是這樣的:

{ 
"_id": "_design/all", 
"language": "javascript", 
"views": { 
    "fantaView": { 
     "map": "function(doc) { \n if (doc.productName == 'Fanta') \n emit(doc.locale, doc)\n} " 
    } 
} 
} 

哪裏fantaView是該視圖的名稱。我想這個函數是自我解釋的。所以這就是我們所做的,我希望如果他遇到類似的問題,它可以幫助別人。

0

我可能是錯的,但濾鏡功能應該返回布爾值,從而試圖改變之一:

function(doc, req){ return doc.productName === 'Fanta';} 

它可以解決您的性能問題...

編輯:

Here是一個解釋爲什麼它很慢(至少在JavaScript中)...

一種解決方案是使用視圖選擇要同步的文檔的ID,然後通過指定要同步的doc_ids來啓動同步。

例如觀點是:

function(doc){ 
    emit(doc.productName, doc._id) 
} 

你可以打電話與_design /文檔/ _view/by_producName的看法?關鍵=「芬達」

,然後開始與發現文檔IDS複製...

+0

好吧,這只是javaScript函數,erlang不會返回布爾值。 – 2013-03-13 15:48:40

+0

@ArneFischer,是的,我看到它後回答......我有一些問題,但我在最初的問題... – pgras 2013-03-13 16:03:05

+0

的意見要求使用視圖創建文檔列表,然後傳遞給複製我們做什麼。它看起來笨重,但工作正常。有人對此方法進行過任何速度測試嗎? – 2013-08-16 14:17:57

0

一般couchDB濾鏡很慢。其他人已經解釋了爲什麼他們很慢。我發現,使用過濾器的唯一合理方法是使用「since」。否則,在一個相當大的數據庫中(我的文檔爲47k,而且它們是複雜的文檔)過濾器不起作用。我們通過從開發移植到產品(幾百個文檔到47K文檔),以艱苦的方式瞭解到了這一點。我們也改變了設計的查詢的視圖,因爲我們需要一個連續進樣的行爲,我們使用了Spring的@Scheduled