2

私はCouchbaseServerで遊んでいて、ローカルデータベースをCloudantに複製しようとしましたが、関連するプロジェクトで一意のタグのセットを構築するために、map/reduce関数のペアで競合する結果が得られています...

// map.js
function(doc) {
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], doc._id);
    }
  }
}

// reduce.js
function(key,values,rereduce) {
  if (!rereduce) {
    var res=[];
    for(var v in values) {
      res.push(values[v]);
    }
    return res;
  } else {
    return values.length;
  }
}

Cloudbaseサーバーでは、これは次のようなJSONを返します。

{"rows":[
{"key":"3d","value":["project1","project3","project8","project10"]},
{"key":"agents","value":["project2"]},
{"key":"fabrication","value":["project3","project5"]}
]}

それはまさに私が望んでいたことであり、期待していたことです。ただし、Cloudantレプリカに対する同じクエリは、次のように返します。

{"rows":[
{"key":"3d","value":4},
{"key":"agents","value":1},
{"key":"fabrication","value":2}
]}

したがって、どういうわけか、値の配列の長さのみが返されます...非常に混乱し、一部のM&R忍者による洞察に感謝しています...;)

4

2 に答える 2

4

これは、reduce関数で期待される動作とまったく同じように見えます。重要な部分はこれです:

else {
return values.length;
}

Cloudantでは、rereduceは常に呼び出されます(reduceは複数のシャードにまたがる必要があるため)。この場合、rereduceはvalues.lengthを呼び出します。これは、配列の長さのみを返します。

于 2011-05-19T00:01:16.807 に答える
2

rereduceパラメータに依存するのではなく、暗黙的にreduce/re-reduceする方が好きです。

function(doc) { // map
  if (doc.tags) {
    for(var t in doc.tags) {
      emit(doc.tags[t], {id:doc._id, tag:doc.tags[t]});
    }
  }
}

次に、同じタグからドキュメントIDを蓄積しているかどうか、または異なるタグをカウントしているだけかどうかのチェックを減らします。

function(keys, vals, rereduce) {
  var initial_tag = vals[0].tag;

  return vals.reduce(function(state, val) {
    if(initial_tag && val.tag === initial_tag) {
      // Accumulate ids which produced this tag.
      var ids = state.ids;
      if(!ids)
        ids = [ state.id ]; // Build initial list from the state's id.
      return { tag: val.tag, 
             , ids: ids.concat([val.id])
             };
    } else {
      var state_count = state.ids ? state.ids.length : state;
      var val_count   = val.ids   ? val.ids.length   : val;
      return state_count + val_count;
    } 
  })
}

(私はこのコードをテストしませんでしたが、あなたは考えを理解します。tag値が同じである限り、それがreduceであるかrereduceであるかは関係ありませんtag。異なるタグが一緒に減少し始めると、値が変化します。その時点で、蓄積を開始します。

私は以前にこのトリックを使用しましたが、IMOがそれだけの価値があることはめったにありません。

また、特定のケースでは、これは危険な削減機能です。タグが付いているすべてのドキュメントを表示するために、幅広いリストを作成しています。CouchDBは、ファットリストではなく、トールリストが好きです。タグが付いているすべてのドキュメントを表示したい場合は、それらをマップできます。

for(var a = 0; a < doc.tags.length; a++) {
  emit(doc.tags[a], doc._id);
}

これでクエリ/db/_design/app/_view/docs_by_tag?key="3d"を実行でき、取得する必要があります

{"total_rows":287,"offset":30,"rows":[
{"id":"project1","key":"3d","value":"project1"}
{"id":"project3","key":"3d","value":"project3"}
{"id":"project8","key":"3d","value":"project8"}
{"id":"project10","key":"3d","value":"project10"}
]}
于 2011-05-19T05:25:26.807 に答える