Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(dsl): Support constantScore query #307

Merged
merged 3 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/overview/queries/elastic_query_constant_score.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
id: elastic_query_constant_score
title: "Constant Score Query"
---

The `ConstantScore` query wraps a filter query and returns every matching document with a relevance score equal to the boost parameter value.

In order to use the `ConstantScore` query import the following:
```scala
import zio.elasticsearch.query.ConstantScoreQuery
import zio.elasticsearch.ElasticQuery._
```

You can create a `ConstantScore` query with arbitrary query(`MatchPhrase` in this example) using the `constantScore` method in the following manner:
```scala
val query: ConstantScoreQuery = constantScore(matchPhrase(field = "name", value = "test"))
```

You can create a [type-safe](https://lambdaworks.github.io/zio-elasticsearch/overview/overview_zio_prelude_schema) `ConstantScore` query with arbitrary [type-safe](https://lambdaworks.github.io/zio-elasticsearch/overview/overview_zio_prelude_schema) query(`MatchPhrase` in this example) using the `constantScore` method in the following manner:
```scala
val query: ConstantScoreQuery = constantScore(matchPhrase(field = Document.name, value = "test"))
```

If you want to change the `boost`, you can use `boost` method:
```scala
val queryWithBoost: ConstantScoreQuery = constantScore(matchPhrase(field = Document.name, value = "test")).boost(2.2)
```

You can find more information about `ConstantScore` query [here](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-constant-score-query.html).

dbulaja98 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,32 @@ object HttpExecutorSpec extends IntegrationSpec {
)
),
suite("searching for documents")(
test("search for a document using a constant score query") {
checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument) {
(firstDocumentId, firstDocument, secondDocumentId, secondDocument) =>
for {
_ <- Executor.execute(ElasticRequest.deleteByQuery(firstSearchIndex, matchAll))
document = firstDocument.copy(stringField = "this is a test")
_ <-
Executor.execute(ElasticRequest.upsert[TestDocument](firstSearchIndex, firstDocumentId, document))
_ <- Executor.execute(
ElasticRequest
.upsert[TestDocument](firstSearchIndex, secondDocumentId, secondDocument)
.refreshTrue
)
query = constantScore(
matchPhrase(
field = TestDocument.stringField,
value = "test"
)
).boost(2.1)
res <- Executor.execute(ElasticRequest.search(firstSearchIndex, query)).documentAs[TestDocument]
} yield (assert(res)(Assertion.contains(document)) && assert(res)(!Assertion.contains(secondDocument)))
}
} @@ around(
Executor.execute(ElasticRequest.createIndex(firstSearchIndex)),
Executor.execute(ElasticRequest.deleteIndex(firstSearchIndex)).orDie
),
test("search for first 2 documents using range query") {
checkOnce(genDocumentId, genTestDocument, genDocumentId, genTestDocument, genDocumentId, genTestDocument) {
(firstDocumentId, firstDocument, secondDocumentId, secondDocument, thirdDocumentId, thirdDocument) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,36 @@ import zio.schema.Schema

object ElasticQuery {

/**
* Constructs a type-safe instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query.
* [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a
* relevance score equal to the boost parameter value.
*
* @param query
* query to be wrapped inside of constant score query
* @tparam S
* document for which field query is specified for. An implicit `Schema` instance must be provided in the scope
* @return
* an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query
* that must satisfy the criteria to be performed.
*/
final def constantScore[S: Schema](query: ElasticQuery[S]): ConstantScoreQuery[S] =
ConstantScore[S](query = query, boost = None)

/**
* Constructs an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] with a specified query.
* [[zio.elasticsearch.query.ConstantScoreQuery]] wraps a filter query and returns every matching document with a
* relevance score equal to the boost parameter value.
*
* @param query
* query to be wrapped inside of constant score query
* @return
* an instance of [[zio.elasticsearch.query.ConstantScoreQuery]] that represents the constant score query with query
* that must satisfy the criteria to be performed.
*/
final def constantScore(query: ElasticQuery[Any]): ConstantScoreQuery[Any] =
ConstantScore[Any](query = query, boost = None)

/**
* Constructs a type-safe instance of [[zio.elasticsearch.query.WildcardQuery]] using the specified parameters.
* [[zio.elasticsearch.query.WildcardQuery]] is used for matching documents containing a value that contains the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,22 @@ private[elasticsearch] final case class Bool[S](
}
}

sealed trait ConstantScoreQuery[S] extends ElasticQuery[S] with HasBoost[ConstantScoreQuery[S]]

private[elasticsearch] final case class ConstantScore[S](query: ElasticQuery[S], boost: Option[Double])
extends ConstantScoreQuery[S] { self =>

def boost(value: Double): ConstantScoreQuery[S] =
self.copy(boost = Some(value))

private[elasticsearch] def toJson(fieldPath: Option[String]): Json =
Obj(
"constant_score" -> (Obj("filter" -> query.toJson(fieldPath)) merge boost.fold(Obj())(b =>
Obj("boost" -> b.toJson)
))
)
}

sealed trait ExistsQuery[S] extends ElasticQuery[S] with HasBoost[ExistsQuery[S]]

private[elasticsearch] final case class Exists[S](field: String, boost: Option[Double]) extends ExistsQuery[S] { self =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,36 @@ object ElasticQuerySpec extends ZIOSpecDefault {
)
}
),
test("constantScore") {
val query = constantScore(terms("stringField", "a", "b", "c"))
val queryTs = constantScore(terms(TestDocument.stringField, "a", "b", "c"))
val queryWithBoost = constantScore(terms(TestDocument.stringField, "a", "b", "c")).boost(2.2)

assert(query)(
equalTo(
ConstantScore[Any](
Terms(field = "stringField", values = Chunk("a", "b", "c"), boost = None),
boost = None
)
)
) &&
assert(queryTs)(
equalTo(
ConstantScore[TestDocument](
Terms(field = "stringField", values = Chunk("a", "b", "c"), boost = None),
boost = None
)
)
) &&
assert(queryWithBoost)(
equalTo(
ConstantScore[TestDocument](
Terms(field = "stringField", values = Chunk("a", "b", "c"), boost = None),
boost = Some(2.2)
)
)
)
},
test("contains") {
val query = contains("testField", "test")
val queryTs = contains(TestDocument.stringField, "test")
Expand Down Expand Up @@ -1873,6 +1903,41 @@ object ElasticQuerySpec extends ZIOSpecDefault {
assert(queryWithAllParams.toJson(fieldPath = None))(equalTo(expectedWithAllParams.toJson))
}
),
test("constantScore") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some parameters are named, some are not.

val query = constantScore(matchPhrase("stringField", "test"))
val queryTs = constantScore(matchPhrase(TestDocument.stringField, "test"))
val queryWithBoost = constantScore(matchPhrase(TestDocument.stringField, "test")).boost(1.5)

val expected =
"""
|{
| "constant_score": {
| "filter": {
| "match_phrase": {
| "stringField": "test"
| }
| }
| }
|}
|""".stripMargin
val expectedWithBoost =
"""
|{
| "constant_score": {
| "filter": {
| "match_phrase": {
| "stringField": "test"
| }
| },
| "boost": 1.5
| }
|}
|""".stripMargin

assert(query.toJson(fieldPath = None))(equalTo(expected.toJson)) &&
assert(queryTs.toJson(fieldPath = None))(equalTo(expected.toJson)) &&
assert(queryWithBoost.toJson(fieldPath = None))(equalTo(expectedWithBoost.toJson))
},
test("contains") {
val query = contains(TestDocument.stringField, "test")
val queryWithBoost = contains(TestDocument.stringField, "test").boost(3.14)
Expand Down
1 change: 1 addition & 0 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = {
items: [
'overview/elastic_query',
'overview/queries/elastic_query_bool',
'overview/queries/elastic_query_constant_score',
'overview/queries/elastic_query_exists',
'overview/queries/elastic_query_function_score',
'overview/queries/elastic_query_geo_distance',
Expand Down