CouchDBの主な「意見」の1つは、分散型のクラスター化された設定でも可能なことのみを実行するというものです。実際には、これは最初は不便であり、後でコードを変更せずに大きなスケーラビリティが得られることを意味します。
言い換えれば、「参加」の質問に対する完全な答えはありません。しかし、私は2つのかなり良いオプションがあると思います。
私はこのデータセットを使用しています:
$ curl localhost:5984/so/_bulk_docs -XPOST -Hcontent-type:application/json -d @-
{"docs":[
{"type":"customer","name":"Jason"},
{"type":"customer","name":"Hunter"},
{"type":"customer","name":"Smith"},
{"type":"order", "for":"Jason", "desc":"Hat"},
{"type":"order", "for":"Jason", "desc":"Shoes"},
{"type":"order", "for":"Smith", "desc":"Pan"}
]}
^D
[{"id":"4cb766ebafda06d8a3a7382f74000b46","rev":"1-8769ac2fffb869e795c347e7b8c653bf"},
{"id":"4cb766ebafda06d8a3a7382f74000b7d","rev":"1-094eff3e3a5967d974fcd7b3cfd7e454"},
{"id":"4cb766ebafda06d8a3a7382f740019cb","rev":"1-5cda0b61da4c045ff503b57f614454d5"},
{"id":"4cb766ebafda06d8a3a7382f7400239d","rev":"1-50642a9809f15283a9d938c8fe28ef27"},
{"id":"4cb766ebafda06d8a3a7382f74002778","rev":"1-d03d883fb14a424e3db022350b38c510"},
{"id":"4cb766ebafda06d8a3a7382f74002c5c","rev":"1-e9612f5d267a8442d3fc2ae09e8c800d"}]
そして私のマップ機能は
function(doc) {
if(doc.type == 'customer')
emit([doc.name, 1], "");
if(doc.type == 'order')
emit([doc.for, 2], doc.desc);
}
フルビューをクエリすると、次のように表示されます。
{"total_rows":6,"offset":0,"rows":[
{"id":"4cb766ebafda06d8a3a7382f74000b7d","key":["Hunter",1],"value":""},
{"id":"4cb766ebafda06d8a3a7382f74000b46","key":["Jason",1],"value":""},
{"id":"4cb766ebafda06d8a3a7382f7400239d","key":["Jason",2],"value":"Hat"},
{"id":"4cb766ebafda06d8a3a7382f74002778","key":["Jason",2],"value":"Shoes"},
{"id":"4cb766ebafda06d8a3a7382f740019cb","key":["Smith",1],"value":""},
{"id":"4cb766ebafda06d8a3a7382f74002c5c","key":["Smith",2],"value":"Pan"}
]}
オプション1:結果を収集するためのリスト機能
利点は、10行を要求した場合、確実に10行になることです(もちろん十分なデータがない場合を除く)。
ただし、コストは、すべてのクエリに対してサーバー側の処理を実行する必要があることです。必要なデータはディスク上にあり、ストリーミングする準備ができていましたが、これでこのボトルネックを乗り越えました。
_list
ただし、個人的には、パフォーマンスの問題が実証されていない限り、それは素晴らしいことだと感じています。
function(head, req) {
start({'headers':{'Content-Type':'application/json'}});
send('{"rows":');
var customer = null, orders = [], count = 0;
var prefix = '\n[ ';
function show_orders() {
if(customer && orders.length > 0) {
count += 1;
send(prefix);
prefix = '\n, ';
send(JSON.stringify({'customer':customer, 'orders':orders}));
}
}
function done() {
send('\n]}');
}
var row;
while(row = getRow()) {
if(row.key[1] == 2) {
// Order for customer
orders.push(row.value);
}
if(row.key[1] == 1) {
// New customer
show_orders();
if(req.query.lim && count >= parseInt(req.query.lim)) {
// Reached the limit
done();
return;
} else {
// Prepare for this customer.
customer = row.key[0];
orders = [];
}
}
}
// Show the last order set seen and finish.
show_orders();
done();
}
この関数は単に行をループし、map
すべての情報が収集された後にのみ完全なcustomer+orders行を出力します。もちろん、出力するJSON形式は変更できます。また、パラメータを使用するとマップクエリが妨害される?lim=X
ため、パラメータがあります。limit
危険なのは、この関数がメモリ内に無制限の応答を構築することです。顧客が10,000件の注文をした場合はどうなりますか?または100,000?最終的に、orders
アレイの構築は失敗します。これが、CouchDBがそれらを「トール」リストに保持する理由です。顧客ごとに10,000件の注文を受け取らない場合は、これは問題ではありません。
$ curl 'http://localhost:5984/so/_design/ex/_list/ex/so?reduce=false&lim=2'
{"rows":
[ {"customer":"Jason","orders":["Hat","Shoes"]}
, {"customer":"Smith","orders":["Pan"]}
]}
オプション2:卑劣な削減
関数を使って似たようなことをすることができますreduce
。ここで、これはディスクに応答を蓄積するため、技術的にスケーラブルではないことを警告しますが、コードが単純であり、後処理なしでディスクからデータを直接読み取ることがわかっているため、個人的には_listではなくそれを好みます。
function(keys, vals, re) {
// If all keys are the same, then these are all
// orders for the same customer, so accumulate
// them. Otherwise, return something meaningless.
var a;
var first_customer = keys[0][0][0];
for(a = 0; a < keys.length; a++)
if(keys[a][0][0] !== first_customer)
return null;
var result = [];
for(a = 0; a < vals.length; a++)
if(vals[a]) {
// Accumulate an order.
result.push(vals[a]);
}
return result;
}
結果を顧客ごとにセグメント化するこのビューを常に照会?group_level=1
します(顧客名がmap
キーの最初の項目であったため)。
削減フェーズ中にデータを蓄積することは想定されていないため、これは法律に違反します。それが彼らがそれをreduceと呼ぶ理由です。
ただし、CouchDBはリラックスしており、巨大なリストを作成しない限り、機能するはずであり、はるかにエレガントです。
$ curl 'localhost:5984/so/_design/ex/_view/so?group_level=1&limit=3'
{"rows":[
{"key":["Hunter"],"value":[]},
{"key":["Jason"],"value":["Shoes","Hat"]},
{"key":["Smith"],"value":["Pan"]}
]}
幸運を!