2

さまざまな独自のソースからステータスの更新を受け入れるシステムがあり、ステータスの更新ごとに次の構造で新しいドキュメントが作成されます。

{
 "type": "status_update",
 "source_id": "truck1231",
 "timestamp": 13023123123,
 "location": "Boise, ID"
}

データは純粋に例ですが、アイデアを理解します。

現在、これらのドキュメントは 1 時間に 1 回程度の間隔で生成されます。1 時間後、次のように挿入します。

{
 "type": "status_update",
 "source_id": "truck1231",
 "timestamp": 13023126723,
 "location": "Madison, WI"
}

私が興味を持っているのは、それぞれの独自のソースからの最新の更新を見ることだけです。現在、次のマップを取得してこれを行っています。

function(doc) {
  if (doc.type == "status_update") {
    emit(doc.source_id, doc);
  }
}

そして以下の削減:

function(keys, values, rereduce) {
  var winner = values[0];
  var i = values.length;
  while (i--) {
    var val = values[i];
    if (val.timestamp > winner.timestamp) winner = val;
  }
  return winner;
}

そして、reduce でデータをクエリしますgroup=true。これは期待どおりに機能し、最新の更新のみのキー付き結果を提供します。

問題は、それが非常に遅くreduce_limit=false、CouchDB の設定を変更する必要があることです。

これを行うためのより効率的な方法が必要であると感じています。同じドキュメントを更新するという選択肢はありません。今回は必要ありませんが、履歴は重要です。これはCouchAppであり、システム内のドキュメントの量は実際には非常に大きく、それらをネットワーク全体に送信するのは現実的ではないため、クライアント側でデータを処理することもできません。

前もって感謝します。

4

3 に答える 3

3

CouchDB の map/reduce はインクリメンタルです。これは基本的に、結果が常にキャッシュされることを意味します。そのため、同じビューに対する後続のリクエスト (検索パラメーターが異なっていても) は「無料」で (または対数時間で) 実行されます。

ただし、reduce グループでは厳密にはそうではありません。部分的な結果をその場で再削減する必要がある場合があります。多分それはあなたが打っているものです。

代わりに、キーとして配列を使用して、次のような行を発行するマップ ビュー (つまり、reduce 関数なし) はどうでしょうか。

// Row diagram (pseudo-code, just to show the concept).
// Key                    , Value
// [source_id, timestamp] , null // value is not very important in this example
["truck1231", 13023123123], null
["truck1231", 13023126723], null
["truck5555", 13023126123], null
["truck6666", 13023000000], null

ソースのすべてのタイムスタンプが「ひとまとめ」になっていることに注目してください。(実際には、それらは を照合します。) の最新のタイムスタンプを見つけるには"truck1231"、その「塊」の最後の行を要求するだけです。これを行うには、limit=1引数を使用して、最後から降順のクエリを実行します。"end" を指定するには{}、キーの 2 番目の要素として "high key" 値を使用します (詳細については、照合リンクを参照してください)。

?descending=true&limit=1&startkey=["truck1231",{}]

(実際には、タイムスタンプは整数であるため、たとえば などの否定を発行できます-13023123123。これにより、クエリが少し簡素化されますが、わかりませんが、私には火遊びのように思えます。)

これらの種類の行を生成するには、次のような map 関数を使用します。

function(doc) {
  // Emit rows sorted first by source id, and second by timestamp
  if (doc.type == "status_update" && doc.timestamp) {
    emit([doc.source_id, doc.timestamp], null) // Using `doc` as the value would be fine too
  }
}
于 2012-05-01T01:20:38.473 に答える
3

_stats組み込みの reduce 関数を使用してすべてのソースの最新のタイムスタンプを取得し、別のクエリを実行してドキュメントを取得できます。ビューは次のとおりです。

"views": {
  "latest_update": {
    "map": "function(doc) { if (doc.type == 'status_update') emit(doc.source_id, doc.timestamp); }",
    "reduce": "_stats"
  },
  "status_update": {
    "map": "function(doc) { if (doc.type == 'status_update') emit([doc.source_id, doc.timestamp], 1); }"
  }
}

最初に を使用してクエリを実行latest_updategroup=true、次にstatus_update(適切に URL エンコードされた) 次のようなものを使用してクエリを実行します。

keys=[["truck123",TS123],["truck234",TS234],...]&include_docs=true

ここで、TS123 と TS234 はmaxによって返されるの値ですlatest_update

于 2012-05-01T08:02:47.300 に答える
1

ドキュメント全体を発行するためだけに遅いのではないかと思います。つまり、最終的な値を計算するには、多くのデータを保存して移動する必要があります。代わりにタイムスタンプを出力してみてください:

function(doc) {
  if (doc.type == "status_update") {
    emit(doc.source_id, [doc._id,doc.timestamp]);
  }
}

function(keys, values, rereduce) {
  var winner = values[0];
  var i = values.length;
  while (i--) {
    var val = values[i];
    if (val[1] > winner[1]) winner = val;
  }
  return winner;
}

これにより、[id,timestamp]遅すぎたり、ビューに大量のデータを保存したりすることなく、すべてのキーのペアを取得できます。

クライアントで識別子のリストを取得したら、bulk GET API を使用して 2 番目のリクエストを送信します。

_all_docs?keys=[id1,id2,id3,...,idn]&include_docs=true 

これにより、1 回の要求ですべてのドキュメントが取得されます。

于 2012-04-30T21:28:30.507 に答える