10

CouchDBを使用しています。クエリ時に指定できる日付範囲内の特定のフィールドの値の発生をカウントできるようにしたいと思います。私はこれの一部を行うことができるようですが、それをすべてまとめる最良の方法を理解するのに苦労しています。

タイムスタンプフィールドと別のフィールドを持つドキュメントを想定します。例:

{ date: '20120101-1853', author: 'bart' }
{ date: '20120102-1850', author: 'homer'}
{ date: '20120103-2359', author: 'homer'}
{ date: '20120104-1200', author: 'lisa'}
{ date: '20120815-1250', author: 'lisa'}

柔軟な日付範囲でドキュメントをフィルタリングするビューを簡単に作成できます。これは、以下のようなビューを使用して実行できます。たとえば、キー範囲パラメータを使用して呼び出されます_view/all-docs?startkey=20120101-0000&endkey=20120201-0000

all-docs / map.js:

function(doc) {
    emit(doc.date, doc);
}

上記のデータを使用すると、最初の4つのドキュメント(日付範囲内の唯一のドキュメント)のみを含むCouchDBビューが返されます。

このように、グループ化して呼び出される、特定のフィールドの発生をカウントするクエリを作成することもできます_view/author-count?group=true

author-count / map.js:

function(doc) {
  emit(doc.author, 1);
}

author-count / reduce.js:

function(keys, values, rereduce) {
  return sum(values);
}

これにより、次のようになります。

{
    "rows": [
        {"key":"bart","value":1},
        {"key":"homer","value":2}
        {"key":"lisa","value":2}
     ]
}

ただし、日付でフィルタリングし、発生をカウントするための最良の方法を見つけることができません。たとえば、上記のデータを使用して、次のような範囲パラメータを指定し、次startkey=20120101-0000&endkey=20120201-0000のような結果を取得できるようにしたいと思います。最後のドキュメントは、指定された日付範囲外であるため、カウントから除外されます。

{
    "rows": [
        {"key":"bart","value":1},
        {"key":"homer","value":2}
        {"key":"lisa","value":1}
     ]
}

これを行うための最もエレガントな方法は何ですか?これは単一のクエリで達成できますか?別のCouchDB構造を使用する必要がありますか、それともビューで十分ですか?

4

3 に答える 3

2

リストを使用すると、目的の結果にかなり近づくことができます。

{
  _id: "_design/authors",
  views: {
    authors_by_date: {
      map: function(doc) {
        emit(doc.date, doc.author);
      }
    }
  },
  lists: {
    count_occurrences: function(head, req) {
      start({ headers: { "Content-Type": "application/json" }});

      var result = {};
      var row;
      while(row = getRow()) {
        var val = row.value;
        if(result[val]) result[val]++;
        else result[val] = 1;
      }
      return result;
    }
  }
}

このデザインは次のようにリクエストできます。

http://<couchurl>/<db>/_design/authors/_list/count_occurrences/authors_by_date?startkey=<startDate>&endkey=<endDate>

これは、通常の map-reduce よりも遅くなりますが、ちょっとした回避策です。残念ながら、多次元クエリを実行するにはこれが唯一の方法であり、「これには CouchDB は適していません」

このデザインをリクエストした結果は次のようになります。

{
  "bart": 1,
  "homer": 2,
  "lisa": 2
}

私たちがしていることは、基本的に多くの要素を発行し、リストを使用してそれらを必要に応じてグループ化することです。リストを使用して、任意の方法で結果を表示できますが、多くの場合、処理が遅くなります。通常の map-reduce はキャッシュされ、差分に従ってのみ変更される可能性がありますが、リストは要求されるたびに新しく作成する必要があります。

マップの結果としてすべての要素を取得するのと同じくらい遅くなります (データを調整するオーバーヘッドはほとんど無視できます)。reduce の結果を取得するよりもはるかに遅くなります。

リストを別のビューで使用したい場合は、要求した URL でリストを交換するだけです。

http://<couchurl>/<db>/_design/authors/_list/count_occurrences/<view>

リストの詳細については、couchdb wiki を参照してください。

于 2015-06-19T14:24:38.380 に答える
0

結合されたビューを作成する必要があります:

結合/map.js:

function(doc) {
    emit([doc.date, doc.author], 1);
}

結合/reduce.js:

_sum

このようにして、開始日/終了日でドキュメントをフィルタリングできます。

startkey=[20120101-0000, "a"]&endkey=[20120201-0000, "a"]
于 2012-10-18T06:50:40.203 に答える
0

あなたの問題は一般的に解決するのは難しいですが、可能なクエリに対するいくつかの制限を知っておくと、大いに役立ちます。たとえば、完全な日/月をカバーする範囲で検索することがわかっている場合は[year, month, day, time]、文字列の代わりに配列を使用できます。

emit([doc.date_year, doc.date_month, doc.date_day, doc.date_time, doc.author] doc);

考えられるすべてのクエリがこのキー タイプに基づくグループ化に適合すると予測できない場合でも、キーを分割すると、範囲クエリを最適化し、必要なルックアップの数を減らすことができます (余分なスペースが必要になります)。

于 2012-10-21T18:07:37.723 に答える