3

キーワードでタグ付けされたドキュメントのデータベースがあります。一緒に使用されている一意のタグを見つけようとしています(そして数えようとしています)。したがって、特定のタグについて、そのタグと一緒に使用されているタグを知りたいと思います。

たとえば、タグが付いたドキュメントが1つある場合、[fruit, apple, plant]クエリ[apple]を実行すると、を取得する必要があります[fruit, plant]。別のドキュメントにタグがある場合[apple, banana]は、のクエリで代わりに表示され[apple]ます[fruit, plant, banana]

これは、すべてのタグとその隣接タグを出力する私のマップ関数です。

function(doc) {
  if(doc.tags) {
    doc.tags.forEach(function(tag1) {
      doc.tags.forEach(function(tag2) {
        emit(tag1, tag2);
      });
    });
  }
}

したがって、上記の私の例では、

apple -- fruit
apple -- plant
apple -- banana
fruit -- apple
fruit -- plant
...

私の質問は:私のreduce関数はどうあるべきですか?削減機能は、基本的に重複を除外し、それらをすべてグループ化する必要があります。

さまざまな試行を試みましたが、データベースサーバー(CouchDB)からエラーが発生し続けます:reduce_overflow_error。削減出力はより急速に縮小する必要があります。


編集:うまくいくように見えるものを見つけましたが、理由はわかりません。reduce関数呼び出しにオプションの「rereduce」パラメーターがあることがわかります。これらの特殊なケースを無視すると、reduce_overflow_errorsのスローが停止します。誰かが理由を説明できますか?そしてまた、私はこれらを無視するべきですか、それとも後でお尻に噛み付くのでしょうか?

function(keys, values, rereduce) {
  if(rereduce) return null; // Throws error without this.

  var a = [];
  values.forEach(function(tag) {
    if(a.indexOf(tag) < 0) a.push(tag);
  });
  return a;
}
4

2 に答える 2

4

あなたの答えは素晴らしいです、そして私がコメントで言ったように、それがあなたのために働くならば、それはあなたが気にかけるべきすべてです。これは、パフォーマンスの問題に遭遇した場合の代替実装です。

CouchDBは、ファットリストではなく、トールリストが好きです。このソリューションでは、ビュー行がこれまでに表示されたすべてのタグと配列を保持する代わりに、ビュー行のキーに「兄弟」タグを保持し、それらをグループ化して、行ごとに1つの一意の兄弟タグを保証します。すべての行は2つのタグだけですが、数千または数百万の行が存在する可能性があります。CouchDBが好む背の高いリストです。

主なアイデアは、タグペアの2つの配列を発行することです。タグ付きのドキュメントが1つあるとしfruit, apple, plantます。

// Pseudo-code visualization of view rows (before reduce)
// Key         , Value
[apple, fruit ], 1
[apple, plant ], 1 // Basically this is every combination of 2 tags in the set.
[fruit, apple ], 1
[fruit, plant ], 1
[plant, apple ], 1
[plant, fruit ], 1

次に、何かにタグを付けますapple, banana

// Pseudo-code visualization of view rows (before reduce)
// Key         , Value
[apple, banana], 1 // This is from my new doc
[apple, fruit ], 1
[apple, plant ], 1 // This is also from my new doc
[banana, apple], 1
[fruit, apple ], 1
[fruit, plant ], 1
[plant, apple ], 1
[plant, fruit ], 1

なぜ値は常に1ですか?非常に単純な組み込みのreduce関数を作成できるため、_sumすべてのタグペアの数を教えてください。次に、?group_level=2CouchDBを使用してクエリを実行すると、合計数を含む一意のペアが得られます。

この種のビューを生成するマップ関数は、次のようになります。

function(doc) {
  // Emit "sibling" tags, keyed on tag pairs.
  var tags = doc.tags || []
  tags.forEach(function(tag1) {
    tags.forEach(function(tag2) {
      if(tag1 != tag2)
        emit([tag1, tag2], 1)
    })
  })
}
于 2012-05-03T00:27:35.973 に答える
1

私は私がはるかに満足している正しい解決策を見つけました。秘訣は、CouchDBをに設定しreduce_limit = falseて、クエリに対するヒューリスティックのチェックを停止する必要があることでした。

値をダブルクリックすると、http:// localhost:5984 / _utils/config.htmlquery_server_config設定でFutonを介してこれを設定できます。

それが完了したら、reduce関数の「re-reducing」部分でより適切に機能する新しいmap関数を次に示します。

function(doc) {
  if(doc.tags) {
    doc.tags.forEach(function(tag1) {
      doc.tags.forEach(function(tag2) {
        emit(tag1, [tag2]); // Array with single value
      });
    });
  }
}

そしてここにreduce関数があります:

function(keys, values) {
  var a = [];
  values.forEach(function(tags) {
    tags.forEach(function(tag) {
      if(a.indexOf(tag) < 0) a.push(tag);
    });
  });
  return a;
}

これが誰かに役立つことを願っています!

于 2012-05-02T10:59:26.640 に答える