したがって、インデックス内の位置に基づいてインデックスキーでドキュメントを取得するmongodbコマンドがいくつかあると思います。ポイントは、次のようにカバーされた複合インデックスを作成できることです。
いいえ、MongoDB にはそのような関数はありませんが、結果セットをランダム化できるのは良い考えです。それまでの間、ここに JIRA があります: https://jira.mongodb.org/browse/SERVER-533
インデックスを使用できるようにインデックスの位置から選択する方法がないため、結果として単一のラウンドトリップを使用することはできないため、複数のカーソルを開くしかありません。
現在の解決策は、結果セットに含まれるドキュメントの数によって異なります。
結果セットに少数のドキュメントがある場合、これは簡単skip(rand())
に解決できますが、インデックスを効果的に使用していないことにlimit(1)
注意する必要があります。skip()
limit()
これは、Btree 全体をスキャンするという意味ではありませんskip()
。
これは、結果セットが大きくなり、結果セットが多数にrand()
なると、多くの場合と同様に深刻なパフォーマンスの問題が発生することを意味します。
これを解決する良い方法の 1 つは、次のいずれかを維持することです。
そして、その新しいフィールドを使用して、クエリの残りの部分を次のように「スキップ」します。
var arr = db.articles.find({topic: 3, rand: rand()}, {_id:1}).limit(7).toArray();
0
to1
アイデアを使用して 7 つのランダムな行を取得します。
このランダムソート機能は、常に変化するデータセットに依存して、ソート内でランダム性を作成するのに役立ちます。もちろん、結果セットが継続的に静的である場合、これは機能しません。
batchSize の使用に関しては、ここでは関係ありません。たとえば、BatchSize を使用してすべての結果を取得するというロジックは、通常、BatchSize の絶対最大サイズが 16MB であるため、完全には意味がありません。これは、ドキュメントが大きい場合、思ったとおりの 1 回の往復が得られない可能性があることを意味します。
これはまた、サーバーがこのすべてのデータを一度に送信することを指示するだけであり、サーバーに配置される作業の量を示すのではなく、ネットワーク上で一度に送信されるデータの量を示します。
したがって、複数のカーソルでこれを行う必要があることを考えると(私が推奨する方法)、実行するだけです:
var arr = db.articles.find({topic: 3, rand: {$gte:rand()}}).sort({rand:1}).limit(1);
数回、または必要に応じて何度でも。これは、カーソルの通常の反復とあまり変わらず、適切なインデックスがあれば非常に高速です。
もう1つの方法がありますが、お勧めしません。_id
たとえば、MR を 1 時間に 1 回実行するか、別のコレクションを作成する何かをrand()
実行できます。これは、最初に示したクエリを実行できることを意味します。
var arr = db.articles.find({topic: 3, rand: rand()}, {_id:1}).limit(7).toArray();
rand()
もちろん、異なるため、実際には7つのランダムレコードを取得します。しかし、これはリアルタイムではなく、大規模なデータセット上のサーバーにとってはあまり良いことではないので、そのようなことはお勧めしません.
編集
もう1つの方法があります。自動インクリメント ID を使用すると、一度に$or
7 秒を選択するステートメントを実行できます。rand()
ただし、これにより、削除という別の問題が発生します。
行を削除rand()
すると、存在しない a にヒットする可能性があるため、行は返されません。サーバー側の削除に対抗するために自動インクリメントIDが維持されないため、これを自分で行う必要があります。これは、簡単なことでもスケーラブルなことでもありません。
この$or
ステートメントに追加するにlimit()
は、句で編集することはできません。つまり、サブ選択タイプ$or
を実行して、MongoDB が を$or
使用して句ごとに 1 つの結果のみを選択するようにすることで、これを回避することはできません$gte
。
rand()
同じことが と の間0
にも当てはまります1
。これは、$or
句を制限できる場合に機能します。