3

まず、Mongoは初めてです...

コンセプト:

  1. ユーザーは自然言語で画像を説明することができます。
  2. ユーザー入力を分割し、彼が説明した単語を単語と呼ばれるコレクションに保存します。
  3. ユーザーは、最もよく使用される単語を調べて、それらの単語を説明に追加できる必要があります。
  4. システムは(すべてのユーザーに対して)最もよく使用される単語を使用し、それらの単語を使用して画像を説明します。

私の言葉の文書(現在)は次のとおりです(例)

{
"date": "date it was inserted"
"reported": 0,
"image_id": "image id"
"image_name": "image name"
"user": "user _id"
"word": "awesome"
}

各単語をユーザーに関連付けることができるように、単語が複製されます...

問題:特定のユーザーによって作成されていない(画像を説明するために)最もよく使用される単語を知るために、Mongoクエリを実行する必要があります。(上記のポイント3を満たすため)

MapReduceアルゴリズムを見てきましたが、読んだところ、いくつかの問題があります。

  1. 結果を並べ替えることができません(使用頻度の高いものから使用頻度の低いものの順に並べ替えることができます)
  2. 何百万ものドキュメントでは、処理時間が長くなる可能性があります。
  3. 返される結果の数を制限することはできません

毎日特定の時間にタスクを実行して、特定のユーザーが特定の画像を説明するために使用していない単語のランクを(別のコレクションの)ドキュメントに保存することを考えました。これを300件の結果か何かに制限する必要があります(適切な制限に関するアイデアはありますか??)次のようなものです。

{
user_id: "the user id"
[
{word: test, count: 1000},
{word: test2, count: 980},
{word: etc, count: 300}
]
}

このソリューションで私が目にする問題は次のとおりです。

  1. 結果にはかなりの遅延があり、これは望ましくありません。
  2. すべてのユーザーに対してこのドキュメントを生成する際のサーバーの負荷が急増する可能性があります(実際、Mongoではこれについてほとんど知らないため、これは単なる仮定です)

たぶん、私のアプローチは意味がありません...そして、Mongoでの経験の欠如が、間違った「スキーマ設計」を指摘しているのかもしれません。

この種の問題に対する良いアプローチは何でしょうか?

大きな投稿をしてすみません、そしてあなたの時間と助けに感謝します!

João

4

2 に答える 2

3

すでに述べたように、使いやすいgroupコマンドを使用できますが、クライアント側で結果を並べ替える必要があります。また、結果は単一のBSONオブジェクトとして返されます。このため、キーは10,000未満とかなり小さくする必要があります。そうしないと、例外が発生します。

データ構造に基づくコード例:

db.words.group({
    key : {"word" : true},
    initial: {count : 0},
    reduce: function(obj, prev) { prev.count++},
    cond: {"user" :{ $ne : "USERNAME_TO_IGNORE"}}
})

もう1つのオプションは、2.2バージョンでリリースされる新しいAggregationフレームワークを使用することです。そのようなものが機能するはずです。

db.words.aggregate({
   $match : { "user" : { "$ne" : "USERNAME_TO_IGNORE"} },
   $group : {
     _id : "$word",
     count: { $sum : 1}
   }
})

または、MapReduceを引き続き使用できます。結果はコレクションであるため、実際には出力を制限して並べ替えることができます。出力で.sort()と.limit()を使用するだけです。また、増分map-reduce出力オプションを使用できます。これは、パフォーマンスの問題を解決するのに役立ちます。MapReduceのoutパラメーターを見てください。

以下は例です。インクリメンタル機能を使用して、words_usageコレクション内の既存のコレクションを新しいデータとマージします。

m = function() { 
   emit(this.word, {count: 1}); 
};


r = function( key , values ){
     var sum = 0;
     values.forEach(function(doc) {
          sum += doc.count;
     });
     return {count: sum};
 };

db.runCommand({
    mapreduce : "words", 
    map : m,
    reduce : r,
    out : { reduce: "words_usage"},
    query : <query filter object>
})

# retrieve the top 10 words
db.words_usage.find().sort({"value.count" : -1}).sort({"value.count" : -1}).limit(10)

上記のMapReduceコマンドをcronで数分/時間ごとに実行できると思いますが、必要な結果がどれだけ正確かによって異なります。更新クエリ基準には、ドキュメント作成日という単語を使用できます。

システムのトップワードコレクションを取得したら、ユーザーごとにトップワードを作成するか、リアルタイムで計算することができます(システムのサイズによって異なります)。

于 2012-06-25T06:39:43.377 に答える
1

このgroup関数は、のより単純なバージョンであると想定されていますMapReduce。このように使用して、各単語の合計を取得できます。

db.coll.group(
           {key: { a:true, b:true },
            cond: { active:1 },
            reduce: function(obj,prev) { prev.csum += obj.c; },
            initial: { csum: 0 }
            });
于 2012-06-25T00:05:00.653 に答える