0

Let's say I have a collection of objects. I have another collection of likes, each one by a specific user and toward a specific object. Thus, over time through user ratings, each object has a variable amount of likes (all greater than 0).

I want to choose an object from this collection. Objects with more likes should be chosen more frequently, but objects with lower likes should also be sometimes chosen to give them a chance.

The algorithm I have in mind now is to order the objects by likes, and generate a random number, and use the number to choose a random object within a range. Assuming I had a hundred objects, 50% of the time objects from 0-10 are chosen, 25% of the time 10-15, and 25% of the time 15-100.

The obvious problem with this algorithm is scalability. When theirs 1000000s of objects, returning an array of all of them takes time. Does anyone have a better solution? THe database is implemented in mongodb.

4

1 に答える 1

1

私は少し非正規化し、「いいね」カウンターフィールドを「いいね」されているオブジェクトに追加します。オブジェクトが高く評価されたときにインクリメントし、オブジェクトが高く評価されていないときにデクリメントします。

db.test.insert({
    stuff: "likable stuff",
    likes: 7
})

次に、いいねの結果としてオブジェクトが入っているバケットを表す別のフィールドもあります。したがって、たとえば、オブジェクトはこのフィールドを「通常」に設定して開始し、誰かが10のいいねを取得すると、「エリート」になります。(または必要なものは何でも)そのしきい値に達したときに更新します。ここでの考え方は、書き込みで作業を行うと、読み取りがはるかに簡単になるということです。

db.test.insert({
    stuff: "likable stuff",
    likes: 7,
    status: "ordinary/elite",
})

さて、いいねの数に基づいて定義したグループに含まれるオブジェクトのセットを選択するのは簡単ですよね? db.collection.find({ status: 'elite' })

これらのセット内のドキュメント選択をランダム化するには、特定の量のレコードをランダムにスキップできますが、それはひどいパフォーマンスにつながり、スケーリングされません。

ただし、ランダムに生成された数値をドキュメント自体に保存するというトリックがあります。

これらの人の1人をテストデータベースに挿入してチェックしてみましょう

db.test.insert({
    stuff: "likable stuff",
    likes: 7,
    status: "ordinary/elite",
    random: Math.random()
})

今すぐドキュメントを見てみましょう:

{
    stuff: "likable stuff",
    likes: 7,
    status: "ordinary/elite",
    random: 0.9375813045563468
}

さて、これが本当にクールになるところです。findOne()クエリを実行します。ここで、status:eliteおよびrand_num:$gt{別のランダムに生成された数値btw0および1}。

db.collection.find({ status: "elite", random: { "$gt": new_rand_num } })

findOne()クエリが結果を返さない場合は、少なくとも1つの方向でドキュメントが確実に見つかるように、$ltを使用して再度実行します。

次に、ステータスとランダムにインデックスを付けます。

db.collection.ensureIndex({ status: 1, random: 1} })

どう思いますか?

于 2011-12-09T02:05:31.753 に答える