我在制定问题的标题方面遇到了麻烦,所以我的前提可能有些歪曲,但这就是这个想法。
我有一个看起来像这样的Mongoose架构,我对rating
感兴趣:
var playerSchema = mongoose.Schema({
playerName: {
type: String,
required: true,
validate: dataFormatValidator.playerNameValidator,
index: {
unique: true,
collation: {
locale: 'en',
strength: 2,
caseLevel: false // 'AbC' == 'abc'
}
}
},
email: {
type: String,
validate: dataFormatValidator.emailValidator,
index: {
unique: true,
sparse: true,
collation: {
locale: 'en',
strength: 1,
caseLevel: false
}
}
},
rating: {
type: Number,
default: 1200
}
});
我想告诉玩家他们在整个玩家群中的位置,根据他们的等级,例如"你排在前31%和#34;。为了避免过多的数据库查询,我考虑每天一次通过数据库中的玩家,并将每个百分位的当前评级保存在一个看起来像这样的数组中,那么接近它的速度超快球员位置:
[1810, 1800, 1790 ... 420, 410]
答案 0 :(得分:1)
如果我理解正确,您的目标是:
rating
。你实现这一目标的计划是:
rating
rating
,创建一个可用作查找表的阵列,以显示玩家彼此的相对位置。对我而言,这个计划听起来似乎有道理。这假设您不需要实时显示百分比评分,而您的夜间任务可以处理您必须经历的玩家数量。如果你有数以百万计的玩家,这可能是一个挑战。
您可以做的一个可能的改进是创建一个"预先汇总的报告"通过将数组存储在单独的文档/集合中,并更新此报告" (即阵列)在您更新播放器rating
的同时。有关此技术的详细信息,请参阅https://docs.mongodb.com/ecosystem/use-cases/pre-aggregated-reports-mmapv1/。
使用预先汇总的报告的一个好处是,您不需要运行夜间任务(因此从长远来看可能更具可伸缩性),以及玩家的百分比数字可以实时显示(因为您每次在rating
更新时都会更新数组)。此技术的一个缺点是,您需要为每次rating
更新执行两次更新,而不是一次。
注意:上面链接的预聚合报告用例包含MMAPv1存储引擎的详细信息,并且预先分配的部分不再与WiredTiger存储引擎相关。但是,基本思想可以应用于任一存储引擎。
答案 1 :(得分:0)
我通过定义每20分排名的“关键点”来解决这个问题,并节省了每个点数以上的玩家数量。我有一个看起来像这样的数组:
[
{ rating: 2000, playersAbove: 10 },
{ rating: 1980, playersAbove: 21 },
...
{ rating: 100, playersAbove: 128336 }
]
然后,每当玩家遇到其中一个限制时,我只需要更新数组中的一个值。例如,如果一个玩家从1990年到2001年的评级,我将数组中第一个对象的“playersAbove”增加一个。
要获得玩家的相对排名,我会检查有多少玩家比玩家上方和下方的“关键点”更好,并假设它们之间的曲线是线性的。然后我可以非常准确地估计有多少玩家比他更好。