db.puzzle2_round (user,date) index, and a theme field

the round.user can be dropped after a year to keep the index small
puzzle
Thibault Duplessis 2020-12-19 16:25:31 +01:00
parent 967a664d5d
commit aa27d11787
10 changed files with 40 additions and 89 deletions

View File

@ -95,13 +95,11 @@ final class Puzzle(
ctx.me match {
case Some(me) =>
for {
isStudent <- env.clas.api.student.isStudent(me.id)
(round, perf) <- env.puzzle.finisher(
puzzle = puzzle,
theme = theme.key,
user = me,
result = Result(resultInt == 1),
isStudent = isStudent
result = Result(resultInt == 1)
)
newUser = me.copy(perfs = me.perfs.copy(puzzle = perf))
_ = env.puzzle.session.onComplete(round, theme.key)
@ -312,13 +310,11 @@ final class Puzzle(
).fuccess
case Some((puzzle, result)) =>
for {
isStudent <- env.clas.api.student.isStudent(me.id)
(round, perf) <- env.puzzle.finisher(
puzzle = puzzle,
theme = PuzzleTheme.mix.key,
user = me,
result = result,
isStudent = isStudent
result = result
)
_ = env.puzzle.session.onComplete(round, PuzzleTheme.mix.key)
} yield Ok(

View File

@ -1,5 +1,8 @@
// for puzzle v2
db.puzzle2_path.createIndex({min: 1, max: -1});
db.puzzle2_round.createIndex({p: 1}, {partialFilterExpression:{t:{$exists:true}}});
db.puzzle2_round.createIndex({u:1,d:-1},{partialFilterExpression:{u:{$exists:1}}});
db.puzzle2_puzzle.createIndex({day:1}, {partialFilterExpression:{day:{$exists:true}}});

View File

@ -3,7 +3,7 @@ package lila.activity
import reactivemongo.api.bson._
import scala.util.Success
import lila.common.Iso
import lila.common.{ Day, Iso }
import lila.db.dsl._
import lila.rating.BSONHandlers.perfTypeKeyIso
import lila.rating.PerfType

View File

@ -1,14 +1,15 @@
package lila.clas
import org.joda.time.{ DateTime, Period }
import lila.rating.PerfType
import lila.game.{ Game, GameRepo }
import lila.user.User
import lila.db.dsl._
import reactivemongo.api._
import reactivemongo.api.bson._
import lila.db.dsl._
import lila.game.{ Game, GameRepo }
import lila.puzzle.PuzzleRound
import lila.rating.PerfType
import lila.user.User
case class ClasProgress(
perfType: PerfType,
days: Int,
@ -84,8 +85,8 @@ final class ClasProgressApi(
import framework._
Match(
$doc(
"u" $in userIds,
"a" $gt (DateTime.now minusDays days)
PuzzleRound.BSONFields.user $in userIds,
PuzzleRound.BSONFields.date $gt DateTime.now.minusDays(days)
)
) -> List(
GroupField("u")(

View File

@ -1,46 +0,0 @@
package lila.puzzle
case class AggregateVote(up: Int, down: Int, nb: Int, ratio: Int) {
def add(v: Boolean) =
copy(
up = up + (if (v) 1 else 0),
down = down + (if (v) 0 else 1)
).computeNbAndRatio
def change(from: Boolean, to: Boolean) =
if (from == to) this
else
copy(
up = up + (if (to) 1 else -1),
down = down + (if (to) -1 else 1)
).computeNbAndRatio
def count = up + down
def sum = up - down
def computeNbAndRatio =
if (up + down > 0)
copy(
ratio = 100 * (up - down) / (up + down),
nb = up + down
)
else
copy(
ratio = 1,
nb = 0
)
}
object AggregateVote {
val default = AggregateVote(1, 0, 1, 100)
val disable = AggregateVote(0, 9000, 9000, -100).computeNbAndRatio
val minRatio = -50
val minVotes = 30
import reactivemongo.api.bson.Macros
implicit val aggregatevoteBSONHandler = Macros.handler[AggregateVote]
}

View File

@ -3,12 +3,12 @@ package lila.puzzle
import chess.format.{ FEN, Uci }
import reactivemongo.api.bson._
import scala.util.Success
import scala.util.Try
import lila.db.BSON
import lila.db.dsl._
import lila.game.Game
import lila.rating.Glicko
import scala.util.Try
private[puzzle] object BsonHandlers {
@ -64,20 +64,18 @@ private[puzzle] object BsonHandlers {
import PuzzleRound.BSONFields._
def reads(r: BSON.Reader) = PuzzleRound(
id = r.get[PuzzleRound.Id](id),
date = r.date(date),
win = r.bool(win),
date = r.date(date),
vote = r.intO(vote),
themes = r.getsD[PuzzleRound.Theme](themes),
weight = r.intO(weight)
themes = r.getsD[PuzzleRound.Theme](themes)
)
def writes(w: BSON.Writer, r: PuzzleRound) =
$doc(
id -> r.id,
date -> r.date,
win -> r.win,
date -> r.date,
vote -> r.vote,
themes -> w.listO(r.themes),
weight -> r.weight
themes -> w.listO(r.themes)
)
}

View File

@ -26,8 +26,8 @@ final class PuzzleActivity(
def stream(config: Config): Source[String, _] =
Source futureSource {
colls.round.map {
_.find($doc("_id" $startsWith s"${config.user.id}${PuzzleRound.idSep}"))
.sort($sort desc "_id")
_.find($doc(PuzzleRound.BSONFields.user -> config.user.id))
.sort($sort desc PuzzleRound.BSONFields.date)
.batchSize(config.perSecond.value)
.cursor[PuzzleRound](ReadPreference.secondaryPreferred)
.documentSource()
@ -46,13 +46,8 @@ final class PuzzleActivity(
colls.puzzle {
_.primitiveMap[Puzzle.Id, Double](
ids = rounds.map(_.id.puzzleId),
field = "perf.gl.r",
fieldExtractor = obj =>
for {
perf <- obj.child("perf")
gl <- perf.child("gl")
rating <- gl.double("r")
} yield rating
field = s"${Puzzle.BSONFields.glicko}.r",
fieldExtractor = _.child("glicko").flatMap(_ double "r")
) map { ratings =>
rounds flatMap { round =>
ratings get round.id.puzzleId map { puzzleRating =>

View File

@ -1,6 +1,7 @@
package lila.puzzle
import cats.implicits._
import org.joda.time.DateTime
import scala.concurrent.duration._
import lila.db.AsyncColl
@ -33,10 +34,12 @@ final private[puzzle] class PuzzleApi(
def find(user: User, puzzleId: Puzzle.Id): Fu[Option[PuzzleRound]] =
colls.round(_.byId[PuzzleRound](PuzzleRound.Id(user.id, puzzleId).toString))
def upsert(r: PuzzleRound, studentUserId: Option[User.ID]): Funit = {
val roundDoc = RoundHandler.write(r) ++ studentUserId.?? { userId =>
$doc(PuzzleRound.BSONFields.user -> userId)
}
def upsert(r: PuzzleRound, theme: PuzzleTheme.Key): Funit = {
val roundDoc = RoundHandler.write(r) ++
$doc(
PuzzleRound.BSONFields.user -> r.id.userId,
PuzzleRound.BSONFields.theme -> theme.some.filter(_ != PuzzleTheme.mix.key)
)
colls.round(_.update.one($id(r.id), roundDoc, upsert = true)).void
}
}

View File

@ -25,8 +25,7 @@ final private[puzzle] class PuzzleFinisher(
puzzle: Puzzle,
theme: PuzzleTheme.Key,
user: User,
result: Result,
isStudent: Boolean
result: Result
): Fu[(PuzzleRound, Perf)] =
api.round.find(user, puzzle.id) flatMap { prevRound =>
val now = DateTime.now
@ -65,7 +64,8 @@ final private[puzzle] class PuzzleFinisher(
.some
.filter(puzzle.glicko !=)
.filter(_.sanityCheck)
val round = PuzzleRound(id = PuzzleRound.Id(user.id, puzzle.id), date = now, win = result.win)
val round =
PuzzleRound(id = PuzzleRound.Id(user.id, puzzle.id), win = result.win, date = DateTime.now)
val userPerf =
user.perfs.puzzle.addOrReset(_.puzzle.crazyGlicko, s"puzzle ${puzzle.id}")(userRating, now) pipe {
p =>
@ -75,7 +75,7 @@ final private[puzzle] class PuzzleFinisher(
}
(round, newPuzzleGlicko, userPerf)
}
api.round.upsert(round, isStudent option user.id) zip
api.round.upsert(round, theme) zip
colls.puzzle {
_.update
.one(

View File

@ -2,15 +2,15 @@ package lila.puzzle
import org.joda.time.DateTime
import lila.common.Day
import lila.user.User
case class PuzzleRound(
id: PuzzleRound.Id,
date: DateTime,
win: Boolean,
date: DateTime,
vote: Option[Int] = None,
themes: List[PuzzleRound.Theme] = Nil,
weight: Option[Int] = None
themes: List[PuzzleRound.Theme] = Nil
) {
def userId = id.userId
@ -49,12 +49,13 @@ object PuzzleRound {
object BSONFields {
val id = "_id"
val date = "d"
val win = "w"
val vote = "v"
val themes = "t"
val puzzle = "p" // only if themes is set!
val weight = "e"
val user = "u" // student denormalization
val user = "u"
val date = "d"
val theme = "t"
}
}