2013-03-13 17 views
11

私は約90kの文書を持つデータベース(couchDB)を持っています。ドキュメントは次のように非常にシンプルです:非常にゆっくりとしたフィルターcoulderであっても

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

私はこのデータベースをモバイルデバイスと同期させたいと思います。明らかに90kのドキュメントは一度にすべて電話に送られるべきではありません。これがフィルター関数を書いた理由です。これらは "productName"でフィルタリングされています。 Javascriptで最初はErlangでパフォーマンスを得る。これらのフィルタ機能は、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;}}" 
    } 
} 

とErlangの中にこのような

{ 
    "_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で最初にJavaでテストプログラムを書いて、ドキュメントをフィルタリングするのにかかる時間をテストしました。ここで私のPerlスクリプトの1つ:

$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フィルタの時代に驚いていません)。

EDIT: pgrasが指摘しているように、これが遅い理由はthis質問の回答に掲載されています。 erlangフィルターをより速く動かすには、以下の「レイヤー」に行き、erlangを_design文書ではなくデータベースに直接プログラムする必要があります。しかし、私はどこで始めるべきか、これをどうやって行うのか本当に知りません。あらゆるヒントが役立ちます。

+0

_changesをsinceパラメータなしで使用すると、最初の同期後にDBのすべてのコンテンツがフィルタリングされます後続の同期にsinceパラメータを使用する予定ですか?あなたは、ビューを使用して言及すると、あなたの他のニーズを解決するキー= "ファンタ"とのファーストビューですか? – pgras

+0

後でデータベースをモバイルデバイスに複製するためにフィルタを使用したいが、私はフィルタをテストするためだけにhttp要求を使用した。私はレプリケーションのためにフィルタを使ってみましたが、同様の結果が得られました。私は後でそこにフィルタを使ったクエリがあるはずだから、ビューが助けになるとは思わない。 –

+0

同じことをやっています。 Erlangをフィルタリングされた複製に使用すると約55%の改善が得られましたが、それでもなお痛みを伴います。 – ryan1234

答えて

3

そして、見つかったドキュメントIDを持つレプリケーションを開始...。しかし、私はそれに戻り、これを解決するためにやったことを分かち合うと思った。

したがって、短い答えはフィルタの速度が本当に改善できないということです。

理由はフィルターが機能するためです。あなたのデータベースの変更をチェックする場合。それらはここにあります:

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

私が間違っていることが、フィルタ関数はブール値を返す必要がありますので、1つを変更しようとする場合があります。それはあなたのパフォーマンスの問題を解決することがあり

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

...

編集:

Hereなぜ低速であるかについての説明です(少なくともJavaScriptを使用)...

解決策の1つは、を選択して同期するドキュメントのIDを選択し、同期するdoc_idsを指定して同期を開始することです。

たとえばビューは次のようになります。

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

あなたは_design /ドキュメント/ _VIEW/by_producNameでビューを呼び出すことができますか?キー=「ファンタ」私はこの質問をしたので、これはしばらくされている

+0

これはjavaScript関数だけですが、erlangはブール値を返します。 –

+0

@ArneFischer、はい私は答えた後にそれを見ました...私はいくつか質問がありますが、最初の質問のコメントで尋ねます... – pgras

+0

ビューを使用してドキュメントリストを作成してから、レプリケーションに渡します。 clunkyと思われますが、うまくいきます。誰かがこのアプローチについてスピードテストを行っていますか? –

0

一般的に、couchDBフィルタは遅いです。他の人は、なぜ彼らが遅いのかを説明しています。私が見つけたのは、フィルターを使用する唯一の妥当な方法は、 "以来"を使用することでした。そうでなければ、合理的に大規模なデータベース(私は47k文書を持っており、それらは複雑な文書です)ではフィルタが機能しません。私たちは、開発者から数百のドキュメントを〜47kドキュメントに移行することで、これを難しい方法で学びました。また、デザインをクエリのビューに変更したので、Springの@Scheduledを使用しました。

関連する問題