12

約 90k のドキュメントを含むデータベース (couchDB) があります。ドキュメントは次のように非常に単純です。

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

いつかこのデータベースをモバイル デバイスと同期させたいと思っています。明らかに、90,000 件のドキュメントが一度に電話に送られるべきではありません。これが、フィルター関数を作成した理由です。これらは「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."       
   }
}

簡単にするために、クエリはまだありませんが、「ハードコードされた」文字列です。フィルターはすべて機能します。問題は、彼らが遅くなることです。ドキュメントのフィルタリングにかかる​​時間をテストするために、最初に Java で、後に Perl でテストプログラムを作成しました。ここに私の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)

ところで、これらは分:秒です。数字はフィルターによって返された要素の数で、データベースには 90k 要素が含まれていました。大きな驚きは、Erlang フィルターがまったく高速ではないことでした。

すべての要素をリクエストするのにかかる時間はわずか 9 秒です。約 15 のビューを作成します。ただし、電話で使用してすべてのドキュメントを転送することはできません (ボリュームとセキュリティ上の理由から)。

ビューをフィルタリングしてパフォーマンスを向上させる方法はありますか? または、私の erlang フィルター関数に何か問題があります (JavaScript フィルターの時間に驚かないでください)。

編集: pgras で指摘されているように、これが遅い理由は、この質問への回答に掲載されています。erlang フィルターをより高速に実行するには、下の「レイヤー」に移動し、erlang を _design ドキュメントとしてではなく、データベースに直接プログラムする必要があります。しかし、どこから始めて、どのようにこれを行うべきか本当にわかりません。どんなヒントも役に立ちます。

4

3 に答える 3

4

この質問をしてからしばらく経ちました。しかし、私はそれに戻って、これを解決するために私たちが最終的に何をしたかを共有すると思いました.

簡単に言えば、フィルター速度を実際に改善することはできません。

その理由は、フィルターの動作の背後にあります。データベースの変更を確認した場合。それらはここにあります:

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 はビューの名前です。機能は自明だと思います。これが私たちがしたことです。誰かが同様の問題に遭遇した場合に役立つことを願っています.

于 2014-03-27T17:24:03.147 に答える
1

私は間違っているかもしれませんが、フィルター関数はブール値を返す必要があるため、次のように変更してみてください。

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

それはあなたのパフォーマンスの問題を解決するかもしれません...

編集:

これが遅い理由についての説明です(少なくともJavaScriptでは)...

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

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

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

_design/docs/_view/by_producName?key="Fanta" でビューを呼び出すことができます

そして、見つかったドキュメント ID でレプリケーションを開始します...

于 2013-03-13T15:36:36.930 に答える
1

一般に、couchDB フィルターは低速です。他の人は、なぜ遅いのかをすでに説明しています。私が見つけたのは、フィルターを使用する唯一の合理的な方法は「since」を使用することであるということでした。それ以外の場合、かなり大きなデータベース (私のドキュメントには 47,000 個のドキュメントがあり、それらは複雑なドキュメントです) では、フィルターは機能しません。これは、開発から製品への移行 [数百のドキュメントから最大 47,000 ドキュメント] までの困難な方法で学びました。また、ビューをクエリするように設計を変更し、動作のような継続的なフィードが必要だったため、Spring の @Scheduled を使用しました。

于 2016-02-21T10:01:41.440 に答える