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 multiMatch query #305

Merged
merged 7 commits into from
Aug 29, 2023

Conversation

milicns
Copy link
Contributor

@milicns milicns commented Aug 17, 2023

Part of #91

Fields parameter is made optional so implementation of this query is a bit different than others.

And should type parameter be included and made optional? https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-multi-match-query.html#multi-match-types

*/
final def multiMatch(value: String): MultiMatchQuery[Any] =
MultiMatch(fields = None, value = value)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because fields are optional and type-safe method is now in HasFields trait, i suppose we don't need multiMatch type-safe method?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you change fields inside of query, this will then be: fields=Chunk.empty

@@ -584,6 +585,25 @@ private[elasticsearch] final case class MatchPhrase[S](field: String, value: Str
)
}

sealed trait MultiMatchQuery[S] extends ElasticQuery[S] with HasFields[MultiMatchQuery[S]]

private[elasticsearch] final case class MultiMatch[S](fields: Option[Chunk[String]], value: String)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would also add minimum_should_match and boost parameters, as they are already implemented, and can be applied to this query.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, @arnoldlacko @drmarjanovic, what do you think, do we need Types of multi_match query as additional parameter?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it could make sense to allow something like .matchingType(MultiMatchType.Phrase).
If it's more complex, it could also be a separate PR.

Comment on lines 595 to 596
def fields[S1: Schema](fields: Field[S1, String]*): MultiMatchQuery[S] =
self.copy(fields = Some(Chunk.fromIterable(fields.map(_.toString))))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm thinking maybe we should just have fields without option, as it is list, it can always be empty, and that way we will cover need for option.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So here, we can have method which only adds new field to the list of fields.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, some sort of restrictions should be discussed, as (I think) we can not have both type-safe and raw fields. @arnoldlacko what do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think given that we use _.toString here, the resulting query is the same regardless of being constructed using Field or raw strings, so it does not need to be an issue if they are mixed.
What I wonder is why we have a S1 type here with no defined relation to S, and why it does not affect the type of the resulting query. We might want to aim for something like:

   fields[S1 <: S: Schema](fields: Field[S1, String]*): MultiMatchQuery[S1]

@mvelimir any thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

We'll definitely need S1 to be a subtype of S, to narrow the type which will always start from Any based on the constructor method. Also, I think mixing both type-safe fields and plain strings should be allowed, since strings in this case can be used as wildcards, and having type-safe fields will still be useful in inferring the type of the document. Also, the type-safe method should definitely contain at least one field as to not clash with the strings method when the argument list is empty. With all this in mind, I think the method signature should be:

def fields[S1 <: S: Schema](field: Field[S1, String], fields: Field[S1, String]*): MultiMatchQuery[S1]

title: "Multi Match Query"
---

The `MultiMatch` query builds on the `match` query to allow multi-field queries:
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seems to be unfinished?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Omit :.

val query: MultiMatchQuery = multiMatch(value = "test")
```

You can create a `MultiMatch` query with fields that will be searched using the `multiMatch` method this way:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's use existing syntax:
If you want to change fields, you can use the fields method:

*/
final def multiMatch(value: String): MultiMatchQuery[Any] =
MultiMatch(fields = None, value = value)

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you change fields inside of query, this will then be: fields=Chunk.empty

def fields(fields: String*): Q

/**
* Sets the `fields` parameter for this [[zio.elasticsearch.query.ElasticQuery]]. The `fields` parameter is the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Sets the `fields` parameter for this [[zio.elasticsearch.query.ElasticQuery]]. The `fields` parameter is the
* Sets the type-safe `fields` parameter for this [[zio.elasticsearch.query.ElasticQuery]]. The `fields` parameter is the


private[elasticsearch] object MultiMatchType extends Enumeration {
type MultiMatchType = String
val BestFields = "best_fields"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please sort this:

BestFields
BoolPrefix
CrossFields
MostFields
Phrase
PhrasePrefix

private[elasticsearch] final case class MultiMatch[S](
fields: Chunk[String],
value: String,
matchingType: Option[MultiMatchType],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's put boost before matchingType.

title: "Multi Match Query"
---

The `MultiMatch` query builds on the `match` query to allow multi-field queries:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Omit :.

val query: MultiMatchQuery = multiMatch(value = "test").fields("stringField1", "stringField2")
```

If you want to change the [type-safe](https://lambdaworks.github.io/zio-elasticsearch/overview/overview_zio_prelude_schema) `fields` that will be searched, you can use the `fields` method this way:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
If you want to change the [type-safe](https://lambdaworks.github.io/zio-elasticsearch/overview/overview_zio_prelude_schema) `fields` that will be searched, you can use the `fields` method this way:
If you want to change the `fields` that will be searched, you can use the `fields` method with the [type-safe](https://lambdaworks.github.io/zio-elasticsearch/overview/overview_zio_prelude_schema) parameters this way:

val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2)
```

If you want to change the `type` of `MultiMatch` query, you can use the `matchingType` method:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
If you want to change the `type` of `MultiMatch` query, you can use the `matchingType` method:
If you want to change the `type`, you can use the `matchingType` method:

```scala
import zio.elasticsearch.query.MultiMatchType

val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).matchingType(MultiMatchType.MostFields)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).matchingType(MultiMatchType.MostFields)
val queryWithType: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).matchingType(MultiMatchType.MostFields)


If you want to change the `boost`, you can use the `boost` method:
```scala
val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).boost(2.2)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).boost(2.2)
val queryWithBoost: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).boost(2.2)

Comment on lines 630 to 631
* @param matchingType
* the [[zio.elasticsearch.query.MultiMatchType]] value of 'type' parameter
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain possible values for matchingType.
You can lookup for other places with similar @param.

* @param matchingType
* the [[zio.elasticsearch.query.MultiMatchType]] value of 'type' parameter
* @return
* a new instance of the [[zio.elasticsearch.query.ElasticQuery]] with the `type` parameter set.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same as above (an instance..).

Comment on lines +649 to +650
def fields(field: String, fields: String*): MultiMatchQuery[S] =
self.copy(fields = Chunk.fromIterable(field +: fields))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it make sense to add fields to chunk instead of setting it? @drmarjanovic

val queryWithMinimumShouldMatch = multiMatch("this is a test").minimumShouldMatch(2)
val queryWithAllParams = multiMatch("this is a test")
.fields(TestDocument.stringField)
.matchingType(MultiMatchType.BestFields)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you omit MultiMatchType? (everywhere in file)

@@ -2505,13 +2608,120 @@ object ElasticQuerySpec extends ZIOSpecDefault {
| "stringField": {
| "query" : "test"
| }
| }
| }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Was this on purpose?


package zio.elasticsearch.query

private[elasticsearch] object MultiMatchType extends Enumeration {
Copy link
Collaborator

@dbulaja98 dbulaja98 Aug 24, 2023

Choose a reason for hiding this comment

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

Please refer to the existing classes that represent enumerations.

@milicns milicns requested a review from dbulaja98 August 24, 2023 08:40
Comment on lines 29 to 39
If you want to change the `type`, you can use the `matchingType` method:
```scala
import zio.elasticsearch.query.MultiMatchType
import zio.elasticsearch.query.MultiMatchType._

val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).matchingType(MultiMatchType.MostFields)
val queryWithType: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).matchingType(MultiMatchType.MostFields)
```

If you want to change the `boost`, you can use the `boost` method:
```scala
val query: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).boost(2.2)
val queryWithBoost: MultiMatchQuery = multiMatch(value = "test").fields(Document.stringField1, Document.stringField2).boost(2.2)
```
Copy link
Collaborator

Choose a reason for hiding this comment

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

Put boost first, then minimum_should_match, then type.

case object CrossFields extends MultiMatchType { def value: String = "cross_fields" }
case object MostFields extends MultiMatchType { def value: String = "most_fields" }
case object Phrase extends MultiMatchType { def value: String = "phrase_fields" }
case object PhrasePrefix extends MultiMatchType { def value: String = "phrase_prefix" }
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Put empty line at the end.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you mean at the end of file, sbt prepare removes it

Comment on lines 19 to 22
sealed trait MultiMatchType {
def value: String
override def toString: String = value
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe this is overkill, also, I think value should not be visible to users.
My advice is this: put only override def toString: String = value to each case object.

*/
def fields(field: String, fields: String*): MultiMatchQuery[S]

/**
* Sets the type-safe `fields` parameter for this [[zio.elasticsearch.query.ElasticQuery]]. The `fields` parameter is
* the type-safe array of fields that will be searched.
* the array of type-safe fields that will be searched.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Omit the.

Comment on lines 629 to 635
* the [[zio.elasticsearch.query.MultiMatchType]] value of 'type' parameter, possible values are:
* - [[zio.elasticsearch.query.MultiMatchType.BestFields]]
* - [[zio.elasticsearch.query.MultiMatchType.BoolPrefix]]
* - [[zio.elasticsearch.query.MultiMatchType.CrossFields]]
* - [[zio.elasticsearch.query.MultiMatchType.MostFields]]
* - [[zio.elasticsearch.query.MultiMatchType.Phrase]]
* - [[zio.elasticsearch.query.MultiMatchType.PhrasePrefix]]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please, provide short explanation for each value. You can see scaladoc for scoreMode def.

Comment on lines 669 to 671
.map(
"minimum_should_match" -> _.toJson
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this be in one line? Or better formatted?

@milicns milicns requested a review from dbulaja98 August 28, 2023 15:18
case object MostFields extends MultiMatchType { def value: String = "most_fields" }
case object Phrase extends MultiMatchType { def value: String = "phrase_fields" }
case object PhrasePrefix extends MultiMatchType { def value: String = "phrase_prefix" }
case object BestFields extends MultiMatchType { override def toString: String = "best_fields" }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please put defs to new line inside of objects?

@milicns milicns requested a review from dbulaja98 August 29, 2023 08:53
@dbulaja98 dbulaja98 merged commit 512740f into lambdaworks:main Aug 29, 2023
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants