From b1eb8916d3b2e05fe37040aa74fb53f793449892 Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 12:42:26 +0700 Subject: [PATCH 1/7] Use must when there are at least two sub queries --- modules/core/src/main/scala/game.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/scala/game.scala b/modules/core/src/main/scala/game.scala index a324fe83..ca262756 100644 --- a/modules/core/src/main/scala/game.scala +++ b/modules/core/src/main/scala/game.scala @@ -127,8 +127,9 @@ object GameQuery: toQueries(whiteUser, Fields.whiteUser), toQueries(blackUser, Fields.blackUser) ).flatten match - case Nil => matchAllQuery() - case queries => boolQuery().must(queries) + case Nil => matchAllQuery() + case List(query) => query + case queries => boolQuery().must(queries) case class Sorting(f: String, order: String): import com.sksamuel.elastic4s.requests.searches.sort.SortOrder From aa20f2d174a80e69d35361607fb6b4ca4d750bf3 Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 12:44:43 +0700 Subject: [PATCH 2/7] Only execute parsed Query once And some scala tweak --- modules/core/src/main/scala/forum.scala | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/modules/core/src/main/scala/forum.scala b/modules/core/src/main/scala/forum.scala index 8d70a92c..57090358 100644 --- a/modules/core/src/main/scala/forum.scala +++ b/modules/core/src/main/scala/forum.scala @@ -40,15 +40,13 @@ object ForumQuery: def countDef(query: Forum) = search(index).query(makeQuery(query)).size(0) - private def parsed(text: String) = QueryParser(text, List("user")) - - private def makeQuery(query: Forum) = boolQuery().must( - parsed(query.text).terms.map { term => - multiMatchQuery(term).fields(searchableFields*) - } ::: List( - parsed(query.text)("user").map { termQuery(Fields.author, _) }, - Option.when(!query.troll)(termQuery(Fields.troll, false)) - ).flatten - ) + private def makeQuery(query: Forum) = + val parsed = QueryParser(query.text, List("user")) + boolQuery().must( + parsed.terms.map(term => multiMatchQuery(term).fields(searchableFields*)) ::: List( + parsed("user").map(termQuery(Fields.author, _)), + Option.unless(query.troll)(termQuery(Fields.troll, false)) + ).flatten + ) private val searchableFields = List(Fields.body, Fields.topic, Fields.author) From 7c70dcb510d55c3dc292768dfa1ac149e3aa9883 Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 13:25:30 +0700 Subject: [PATCH 3/7] Only use must when necessary in forum search --- modules/core/src/main/scala/forum.scala | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/scala/forum.scala b/modules/core/src/main/scala/forum.scala index 57090358..0c53f374 100644 --- a/modules/core/src/main/scala/forum.scala +++ b/modules/core/src/main/scala/forum.scala @@ -42,11 +42,13 @@ object ForumQuery: private def makeQuery(query: Forum) = val parsed = QueryParser(query.text, List("user")) - boolQuery().must( - parsed.terms.map(term => multiMatchQuery(term).fields(searchableFields*)) ::: List( - parsed("user").map(termQuery(Fields.author, _)), - Option.unless(query.troll)(termQuery(Fields.troll, false)) - ).flatten - ) + List( + parsed.terms.map(term => multiMatchQuery(term).fields(searchableFields*)), + parsed("user").map(termQuery(Fields.author, _)).toList, + Option.unless(query.troll)(termQuery(Fields.troll, false)).toList + ).flatten.match + case Nil => matchAllQuery() + case x :: Nil => x + case xs => boolQuery().must(xs) private val searchableFields = List(Fields.body, Fields.topic, Fields.author) From b40f55144f7c96a6b0cf50cfea131ce4a0b7889d Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 13:43:27 +0700 Subject: [PATCH 4/7] Remove package object --- modules/core/src/main/scala/package.scala | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/modules/core/src/main/scala/package.scala b/modules/core/src/main/scala/package.scala index a3c8fb4c..db1b2457 100644 --- a/modules/core/src/main/scala/package.scala +++ b/modules/core/src/main/scala/package.scala @@ -1,10 +1,8 @@ -package lila +package lila.search -package object search: +object Date: + import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter } + val format = "yyyy-MM-dd HH:mm:ss" + val formatter: DateTimeFormatter = DateTimeFormat.forPattern(format) - object Date: - import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter } - val format = "yyyy-MM-dd HH:mm:ss" - val formatter: DateTimeFormatter = DateTimeFormat.forPattern(format) - - extension (self: Boolean) def fold[A](t: => A, f: => A): A = if self then t else f +extension (self: Boolean) def fold[A](t: => A, f: => A): A = if self then t else f From 1ebb89e0bc50994de2a5a85a5fdf9d734945bf43 Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 13:52:33 +0700 Subject: [PATCH 5/7] Add compile extension function for List[Query] This is to reduce code duplication --- modules/core/src/main/scala/forum.scala | 5 +---- modules/core/src/main/scala/game.scala | 5 +---- modules/core/src/main/scala/package.scala | 9 +++++++++ modules/core/src/main/scala/study.scala | 17 +++++++---------- modules/core/src/main/scala/team.scala | 4 +--- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/modules/core/src/main/scala/forum.scala b/modules/core/src/main/scala/forum.scala index 0c53f374..d0f22660 100644 --- a/modules/core/src/main/scala/forum.scala +++ b/modules/core/src/main/scala/forum.scala @@ -46,9 +46,6 @@ object ForumQuery: parsed.terms.map(term => multiMatchQuery(term).fields(searchableFields*)), parsed("user").map(termQuery(Fields.author, _)).toList, Option.unless(query.troll)(termQuery(Fields.troll, false)).toList - ).flatten.match - case Nil => matchAllQuery() - case x :: Nil => x - case xs => boolQuery().must(xs) + ).flatten.compile private val searchableFields = List(Fields.body, Fields.topic, Fields.author) diff --git a/modules/core/src/main/scala/game.scala b/modules/core/src/main/scala/game.scala index ca262756..a19f1347 100644 --- a/modules/core/src/main/scala/game.scala +++ b/modules/core/src/main/scala/game.scala @@ -126,10 +126,7 @@ object GameQuery: toQueries(analysed, Fields.analysed), toQueries(whiteUser, Fields.whiteUser), toQueries(blackUser, Fields.blackUser) - ).flatten match - case Nil => matchAllQuery() - case List(query) => query - case queries => boolQuery().must(queries) + ).flatten.compile case class Sorting(f: String, order: String): import com.sksamuel.elastic4s.requests.searches.sort.SortOrder diff --git a/modules/core/src/main/scala/package.scala b/modules/core/src/main/scala/package.scala index db1b2457..20a46b3a 100644 --- a/modules/core/src/main/scala/package.scala +++ b/modules/core/src/main/scala/package.scala @@ -1,8 +1,17 @@ package lila.search +import com.sksamuel.elastic4s.ElasticDsl.* +import com.sksamuel.elastic4s.requests.searches.queries.Query + object Date: import org.joda.time.format.{ DateTimeFormat, DateTimeFormatter } val format = "yyyy-MM-dd HH:mm:ss" val formatter: DateTimeFormatter = DateTimeFormat.forPattern(format) extension (self: Boolean) def fold[A](t: => A, f: => A): A = if self then t else f + +extension (queries: List[Query]) + def compile: Query = queries match + case Nil => matchAllQuery() + case q :: Nil => q + case _ => boolQuery().must(queries) diff --git a/modules/core/src/main/scala/study.scala b/modules/core/src/main/scala/study.scala index 81485cc7..d1881f7e 100644 --- a/modules/core/src/main/scala/study.scala +++ b/modules/core/src/main/scala/study.scala @@ -51,23 +51,20 @@ object StudyQuery: def countDef(query: Study) = search(index).query(makeQuery(query)).size(0) - private def parsed(text: String) = QueryParser(text, List("owner", "member")) - private def makeQuery(query: Study) = { + val parsed = QueryParser(query.text, List("owner", "member")) val matcher: Query = - if parsed(query.text).terms.isEmpty then matchAllQuery() + if parsed.terms.isEmpty then matchAllQuery() else multiMatchQuery( - parsed(query.text).terms.mkString(" ") + parsed.terms.mkString(" ") ).fields(searchableFields*).analyzer("english").matchType("most_fields") must { matcher :: List( - parsed(query.text)("owner").map { termQuery(Fields.owner, _) }, - parsed(query.text)("member").map { member => - boolQuery() - .must(termQuery(Fields.members, member)) - .not(termQuery(Fields.owner, member)) - } + parsed("owner").map(termQuery(Fields.owner, _)), + parsed("member").map(member => + boolQuery().must(termQuery(Fields.members, member)).not(termQuery(Fields.owner, member)) + ) ).flatten } should List( Some(selectPublic), diff --git a/modules/core/src/main/scala/team.scala b/modules/core/src/main/scala/team.scala index 949b5901..cbc3e704 100644 --- a/modules/core/src/main/scala/team.scala +++ b/modules/core/src/main/scala/team.scala @@ -38,9 +38,7 @@ object TeamQuery: private def parsed(query: Team) = QueryParser(query.text, Nil) private def makeQuery(team: Team) = must { - parsed(team).terms.map { term => - multiMatchQuery(term).fields(searchableFields*) - } + parsed(team).terms.map(term => multiMatchQuery(term).fields(searchableFields*)) } private val searchableFields = List(Fields.name, Fields.description) From 22463cdac6d448fc0f8fbaba0f35b5006199430e Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 14:15:11 +0700 Subject: [PATCH 6/7] Use compile for team --- modules/core/src/main/scala/team.scala | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/scala/team.scala b/modules/core/src/main/scala/team.scala index cbc3e704..97953e37 100644 --- a/modules/core/src/main/scala/team.scala +++ b/modules/core/src/main/scala/team.scala @@ -33,12 +33,9 @@ object TeamQuery: .start(from.value) .size(size.value) - def countDef(query: Team) = search(index).query(makeQuery(query)) size 0 + def countDef(query: Team) = search(index).query(makeQuery(query)).size(0) - private def parsed(query: Team) = QueryParser(query.text, Nil) - - private def makeQuery(team: Team) = must { - parsed(team).terms.map(term => multiMatchQuery(term).fields(searchableFields*)) - } + private def makeQuery(team: Team) = + QueryParser(team.text, Nil).terms.map(term => multiMatchQuery(term).fields(searchableFields*)).compile private val searchableFields = List(Fields.name, Fields.description) From 46fdb19a7e19c0e637e9cdb11f7c458d05ddf2df Mon Sep 17 00:00:00 2001 From: Thanh Le Date: Mon, 10 Jun 2024 14:19:18 +0700 Subject: [PATCH 7/7] Use filter instead of must https://stackoverflow.com/questions/43349044/what-is-the-difference-between-must-and-filter-in-query-dsl-in-elasticsearch --- modules/core/src/main/scala/package.scala | 2 +- modules/core/src/main/scala/study.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/scala/package.scala b/modules/core/src/main/scala/package.scala index 20a46b3a..9ca8a0d0 100644 --- a/modules/core/src/main/scala/package.scala +++ b/modules/core/src/main/scala/package.scala @@ -14,4 +14,4 @@ extension (queries: List[Query]) def compile: Query = queries match case Nil => matchAllQuery() case q :: Nil => q - case _ => boolQuery().must(queries) + case _ => boolQuery().filter(queries) diff --git a/modules/core/src/main/scala/study.scala b/modules/core/src/main/scala/study.scala index d1881f7e..eda6af30 100644 --- a/modules/core/src/main/scala/study.scala +++ b/modules/core/src/main/scala/study.scala @@ -59,7 +59,7 @@ object StudyQuery: multiMatchQuery( parsed.terms.mkString(" ") ).fields(searchableFields*).analyzer("english").matchType("most_fields") - must { + boolQuery().filter { matcher :: List( parsed("owner").map(termQuery(Fields.owner, _)), parsed("member").map(member =>