implement 2-stage mapReduce paginator

multiboardMapReduce
Thibault Duplessis 2018-11-28 10:51:12 +07:00
parent c25c4d9698
commit 4aacd776ca
2 changed files with 36 additions and 26 deletions

View File

@ -33,26 +33,40 @@ final class Adapter[A: BSONDocumentReader](
.list[A](length, readPreference)
}
/*
* because mongodb mapReduce doesn't support `skip`, slice requires to queries.
* The first one gets the IDs with `skip`.
* The second one runs the mapReduce on these IDs.
* This avoid running mapReduce on many unnecessary docs.
* NOTE: Requires string ID.
*/
final class MapReduceAdapter[A: BSONDocumentReader](
collection: Coll,
selector: Bdoc,
sort: Bdoc,
runCommand: RunCommand,
command: MapReduceAdapter.Command,
command: Bdoc,
readPreference: ReadPreference = ReadPreference.primary
) extends AdapterLike[A] {
def nbResults: Fu[Int] = collection.countSel(selector, readPreference)
def slice(offset: Int, length: Int): Fu[List[A]] =
runCommand(
command(offset) ++ $doc("limit" -> (offset + length)),
readPreference
) map { res =>
res.getAs[List[Bdoc]]("results").??(_ map implicitly[BSONDocumentReader[A]].read)
collection.find(selector, $id(true))
.sort(sort)
.skip(offset)
.list[Bdoc](length, readPreference)
.dmap { _ flatMap { _.getAs[BSONString]("_id") } }
.flatMap { ids =>
runCommand(
$doc(
"mapreduce" -> collection.name,
"query" -> $inIds(ids),
"out" -> $doc("inline" -> true)
) ++ command,
readPreference
) map { res =>
res.getAs[List[Bdoc]]("results").??(_ map implicitly[BSONDocumentReader[A]].read)
}
}
}
object MapReduceAdapter {
// offset -> doc
type Command = Int => Bdoc
}

View File

@ -36,27 +36,23 @@ final class StudyMultiBoard(
* return the last mainline node.
* Else, return the root node without its children.
*/
val command: MapReduceAdapter.Command = offset => $doc(
"mapreduce" -> chapterColl.name,
"map" -> """var node = this.root, child, result = {name:this.name,orientation:this.setup.orientation,tags:this.tags};
Paginator(
adapter = new MapReduceAdapter[ChapterPreview](
collection = chapterColl,
selector = selector,
sort = $sort asc "order",
runCommand = runCommand,
command = $doc(
"map" -> """var node = this.root, child, result = {name:this.name,orientation:this.setup.orientation,tags:this.tags};
if (this.tags.filter(t => t.indexOf('White:') === 0 || t.indexOf('Black:') === 0).length === 2) {
while(child = node.n[0]) { node = child };
}
result.fen = node.f;
result.uci = node.u;
emit(this._id, result)""",
"reduce" -> """function(key, values) { return key; }""",
"out" -> $doc("inline" -> true),
"query" -> selector,
"sort" -> $sort.asc("order"),
"jsMode" -> true
)
Paginator(
adapter = new MapReduceAdapter[ChapterPreview](
collection = chapterColl,
selector = selector,
runCommand = runCommand,
command = command
"reduce" -> """function(key, values) { return key; }""",
"jsMode" -> true
)
),
currentPage = page,
maxPerPage = maxPerPage