3

CouchDBのドキュメント構造は次のようになります。

{
 "_id": "0a68cdbe4a7f3abf4046bc",
 "_rev": "1-1508",
 "score": {"math":90, "physics": 88, "chemistry": 60},
 "student_name": "Mike"
}

学生のプロファイルを設定するには、フロントエンドに以下の統計を表示する必要があります。

  • Student _idが与えられた場合、各コースでその学生のランクを取得するにはどうすればよいですか。
  • 学生の_idが与えられた場合、その学生の合計スコア(数学+物理学+化学)のランクを取得するにはどうすればよいですか。

生徒が2人しかいないとすると、2人目の生徒の記録は次のようになります。

{
 "_id": "0a68cdbe2344a3abf4046bc",
 "_rev": "1-1608",
 "score": {"math":80, "physics": 98, "chemistry": 90},
 "student_name": "Jane"
}

したがって、マイクのランクは次のようになります。

math: 1
physics: 2
chemistry: 2
total: 2

ジェーンのランクは

math: 2
physics: 1
chemistry: 1
total: 1

問題を明確に述べていない場合はお知らせください。

ランクを取得するためのビューを作成する方法がわかりませんでした。私が試したこと:

  • スコアを学生情報にマップするビューを作成します。次に、スコア範囲を照会して、スコアがその範囲内にあることを生徒に取得できます。

編集:ユーザー名によるクエリとランクの取得の機能は、ビューのみで実装する必要はありません。どんなアイデアでも大歓迎です!

Edit2:コース数は1Kから3Kになります。学生数は100万から200万人になります。

4

4 に答える 4

6

眺めだけではやりたいことはできないと思います。次のようなマップ関数を試します。

function(doc) {
  emit (["math", doc.score.math], doc.student_name);
  emit (["physics", doc.score.physics], doc.student_name);
  emit (["chemistry",doc.score.chemistry], doc.student_name);
  emit (["total",doc.score.math+doc.score.physics+doc.score.chemistry], doc.student_name);
}

それから私はもちろん質問します。これにより、スコア順に並べられた値の学生のリストが返されます。その後、プログラムでソフトウェアのランクを選択する必要があると思います。

削減関数は結果セットを縮小しないため、また学生名でクエリを実行すると同時に学生の全リストを取得する方法を思い付くことができないため、役に立たないと思います。また、リストに生徒の名前を知らせると同時に、結果に生徒のセット全体を含める方法がわからないため、リストも役に立たないと思います。

于 2012-11-18T19:51:55.557 に答える
2

ソートされたビューとリストの組み合わせが機能するかもしれません。

resultByChemistryScoreビューは次のようになります

function(doc) {
    emit(doc.score.chemistry, [doc._id, doc.student_name]);
}

その場合、GETリクエストは次のようになります。およびGETクエリパラメータhttp://localhost:5984/results/_design/results/_view/resultByChemistryScore?descending=trueを使用して、この時点でも常にページネーションを実装できます。offsetlimit

この時点listから、指定した生徒に届くまでカウントできます。

リスト関数「ランク」は次のようになります

function(head, req) {
    start({ "headers": { "content-type": "application/json" } } );
    var row, rank = 0; 
    while ( row = getRow() ) {
        if ( row.id == req.query.id ) break;
        // increment rank if not a tie
        if ( old_row != null && old_row.key != row.key ) 
           rank++;
        old_row = row;
    }; 
    send( JSON.stringify( { "rank" : rank } ) );
}

そして、あなたの要求は基本的にhttp://localhost:5984/results/_design/results/_list/rank/resultByChemistryScore?id=fet&descending=trueです。

あまりきれいではありません、それをあげましょう。あなたが言うなら、サーバーがリスト全体を通過するのにおそらくしばらく時間がかかるでしょう...1,000,000番目に優れた化学の学生。しかし、確かにサーバーはクライアントよりも簡単に実行できます。

編集 ネクタイハンドリングケースを追加

于 2012-11-21T01:10:49.250 に答える
2

したがって、CouchDBで完全に実行できるソリューションはないと思います。このソリューションでは、学生とサブジェクトのペアリングに対して単一の値を取得します。ただし、探しているものにほぼ近いマップ/リデュースビューを作成できます。次に、そのビューの結果を使用して、学生と被験者のペアのランクを見つけることができます。

まず、joscasによって提案されたものと非常によく似たマップを使用してビューを作成します。唯一の違いは、サブジェクト名がハードコーディングされていないことです。

map.js

function(doc) {
    var total = 0;
    for (var subject in doc.score)  {
        var score = doc.score[subject];
        emit([subject, score], doc.student_name);
        total += score;
    }
    emit(["total", total], doc.student_name);
}

group=trueこれをreduce関数と組み合わせて、aとを与えられた各サブジェクトのランキングを生成します。grouping_level=1

reduce.js

function(keys, values) {
    var rankings = {};              // In order to return ties, a simple array can't be used.
    var rank = 0;
    var place = 0;
    var last_score = -1;
    for (var i = 0; i < values.length; i++) {
        var name = values[i];
        var score = keys[i][0][1];  // The 0th element of the key is the [subject, score] array.
        if (score == last_score) {
            // Tie, add another student to this rank.
            place++;
        } else {
            // Not a tie, create a new rank.
            rank += (place + 1);
            rankings[rank] = new Array();
            place = 0;
            last_score = score;
        }
        rankings[rank][place] = name;
    }
    return rankings;
}

データ

データセットに3人目の生徒を追加し、それを面白くするためにいくつかの関係を作成しました。使用したデータは次のとおりです。

{
    "_id": "ce6b2cd97e73258014679ab7bb9e7cdc",
    "_rev": "2-b62581d22c186bfc8ebe1703a2dfb506",
    "score": {
        "chemistry": 60,
        "math": 90,
        "physics": 88
    },
    "student_name": "Mike"
}

{
    "_id": "ce6b2cd97e73258014679ab7bb9e8ada",
    "_rev": "5-94d6cfbd3cf22f903ebc306570d1f1af",
    "score": {
        "chemistry": 90,
        "math": 90,
        "physics": 98
    },
    "student_name": "Jane"
}

{
    "_id": "ce6b2cd97e73258014679ab7bb9e960b",
    "_rev": "1-d8c7fe88de63cf3d6e9743696f96aad0",
    "score": {
        "chemistry": 61,
        "math": 89,
        "physics": 88
    },
    "student_name":
    "Charlie"
}

結果

ビューはランクとして保存され、次のようにクエリできます。

http://127.0.0.1:5984/atest/_design/atest/_view/rank?group=true&group_level=1

これにより、次の結果が得られます。

{
    "rows":[
        {"key":["chemistry"],"value":{"1":["Jane"],"2":["Charlie"],"3":["Mike"]}},
        {"key":["math"],"value":{"1":["Jane","Mike"],"3":["Charlie"]}},
        {"key":["physics"],"value":{"1":["Jane"],"2":["Charlie","Mike"]}},
        {"key":["total"],"value":{"1":["Jane"],"2":["Charlie","Mike"]}}
    ]
}

ビューは、次のようにサブジェクトによってクエリできます(最低スコアが0で、最高スコアが100であると想定)。

http://127.0.0.1:5984/atest/_design/atest/_view/rank?group=true&group_level=1&startkey=%5B%22math%22,0%5D&endkey=%5B%22math%22,100%5D

(URLエンコードなし):

http://127.0.0.1:5984/atest/_design/atest/_view/rank?group=true&group_level=1&startkey=["math",0]&endkey=["math",100]

これにより、次の結果が得られます。

{
    "rows":[
        {"key":["math"],"value":{"1":["Jane","Mike"],"3":["Charlie"]}}
    ]
}

結果の辞書は、Javascript(または他のクライアント側テクノロジー)を使用して検索し、単一(またはすべて)の科目での学生のランクを決定できます。

于 2012-11-26T16:27:52.400 に答える
1

@joscasの答えに基づいたアイデアがあります。次のようなビューを作成できます。

key         -> value
---------------------
("math", 0) -> 2
("math", 1) -> 3
("math", 2) -> 5
....
("math", 100) -> 50

各コースのスコア範囲は0〜100であると仮定しました。アイデアは次のとおりです。

  • コースごとに、スコアがそのスコアバケットに含まれる学生の数を集計します(コースごとに101バケット、つまりfrombucket0からbucket100)。
  • 次に、@ joscasが指摘したような連鎖ビューを使用するか、別の外部プログラムを使用して、以下のようなスコアヒストグラムの累積分布を取得します。

key         -> accumulative value
------------------------------------
("math", 0) -> 2
("math", 1) -> 5
("math", 2) -> 10
....
("math", 99) -> 32324
("math", 100)-> 32374

コース名cとスコアが与えられるとs、この2番目のビューhow many students play not as good as you in this courseから、を使用してランクを導き出すことができますn-#s。ここで、はn登録されている学生の総数であり、スコアが。よりも低い学生の数です。たとえば、のクエリは32374-32324 = 50を返します。これは、「数学」で99を取得した学生のランクです。c#ss"math", 99

質問の合計スコア部分については、同様のアイデアを使用できますが、バケットのサイズと数を変更します。

于 2012-11-29T23:13:56.217 に答える