Combine scores from multi-match and date range


(Maryam Abdullah) #1

Hey there,

I want to consider the dates while calculating scores, meaning that a document score is a combination of both multi-match fields and date.

Here's my code:

var response = elasticClient.Search<Document>(s => s
                .From(0)
                .Size(20)
                .Query(q => q
                  .Term(tm => tm.Field(fd => fd.Client)
                        .Value(client)
                        )
                          &&
                   q.MultiMatch(m => m
                                .Fields(fs => fs
                                    .Field(f => f.Title, 2)
                                    .Field(f => f.Description)
                                    .Field(f => f.Tags)
                                    .Field(f => f.Terms, 2)
                                    .Field(f => f.Meta)
                                    .Field(f => f.Type, 3)
                                )
                                .Fuzziness(Fuzziness.Auto)
                                .Type(TextQueryType.BestFields)
                                .TieBreaker(0.3)
                                .Query(query)
                                )       
                ));

I tried adding the following line of code inside the Query(), but I haven't noticed any change in the retrieved results.

.DateRange(r => r.Field(f => f.Date).GreaterThanOrEquals(new DateTime(2018)).Boost(2))

Any thoughts?

Thanks in advance.


(Zachary Tong) #2

If you add all the queries into a compound query like a Boolean query, you can combine their scores.

You can't normally define a request that has multiple query components without some kind of compound query like a Boolean, so I'm not entirely sure how the client is letting you do that. Maybe it is doing that behind the scenes? Not sure.

In any case, try adding them all to a must or should clause of a Boolean query and see if that helps. You can play with boosting then, or wrap in constant_score, etc.


(Maryam Abdullah) #3

I added them as a compound query (bool), yet when I changed the boost value of the date range, the scores didn't change. (they change in case of multi-match)

var response = elasticClient.Search<Document>(s => s
                .From(offset)
                .Size(size)
                .Query(q => q
                    .Bool(b => b
                        .Should(m => m
                            .Term(tm => tm.Field(fd => fd.Client)
                                .Value(client)
                            ))
                        .Should(sh => sh
                            .DateRange(
                                r => r.Field(f => f.Date).GreaterThanOrEquals(new DateTime(2018)).Boost(3))
                        )
                        .Should(m => m
                            .MultiMatch(mm => mm
                                .Fields(fs => fs
                                    .Field(f => f.Title, 2)
                                    .Field(f => f.Description)
                                    .Field(f => f.Tags)
                                    .Field(f => f.Terms, 2)
                                    .Field(f => f.Meta)
                                    .Field(f => f.Type, 3)
                                )
                                .Fuzziness(Fuzziness.Auto)
                                .Type(TextQueryType.BestFields)
                                .TieBreaker(0.3)
                                .Query(query)
                                .Boost(1)
                            )
                        )
                    )
                ));

(Zachary Tong) #4

Do the unchanged documents match the date range query? Being in a should clause, they are technically optional so it's possible for docs to not match the range, meaning the boost won't be applied either.

If they are matching, you could try wrapping the date range in a constant_score with an applied boost to that. I was under the assumption that matching ranges had their boosts applied, but I may be wrong on that point (e.g. a range matches or doesn't, there's no sense of "better range match" so it may be a static boost).


(Maryam Abdullah) #5

It turned out I was using DateTime object instead of DateMath which was probably the cause of the problem. (It works with or without constant_score)

I replaced it with DateMath object, and it's working properly now.
But the term matching and multi-matching fields must be placed in a Must while the date range stays in a Should.

Thanks for the help.


(Maryam Abdullah) #6

Hey,
I switched to using cross fields and I have 2 groups of fields, each with a different analyzer.
I placed them all in a bool, however, when I add the multi-match query for the second group, the result becomes null when placed in a MUST clause.
when I placed them in a SHOULD clause (and date range is in a should clause as well), it returned some irrelevant results, for example, the new documents even though they don't match the query at all.

Here's my code:

  .Query(q => q
      .Bool(b => b
      .MustNot(mn => mn
        .Terms(t => t.Field(f => f.Client).Terms(other)))
      .Should(sh => sh
               .DateRange(
                    rr =>
                    rr.Field(fd => fd.Date)
                         .GreaterThanOrEquals(
                            DateMath.Now.Subtract(new DateMathTime(31556952000)))
                            .Boost(10)),
                            sh => sh
                             .DateRange(
                               rr =>
                               rr.Field(fd => fd.Date)
                                 .GreaterThanOrEquals(
                                 DateMath.Now.Subtract(new DateMathTime(63113904000))).LessThan(DateMath.Now.Subtract(new DateMathTime(31556952000)))
                                            .Boost(2))
                        )
      .Must(m => m
          .MultiMatch(mm => mm
           .Fields(fs => fs
           .Field(f => f.Title)
           .Field(f => f.Description)
           .Field(f => f.Tags)
           .Field(f => f.Terms)
           .Field(f => f.Type)
            )
               .Type(TextQueryType.CrossFields)
               .TieBreaker(1)
               .Operator(Operator.Or)
               .Query(query)
               .MinimumShouldMatch(1)))
                        ,
              m => m.MultiMatch(mm => mm
                  .Fields(fs => fs
                         .Field(f => f.Meta)
                         .Field(f => f.Relations)
                     )
                 .Type(TextQueryType.CrossFields)
                 .TieBreaker(1)
                 .Operator(Operator.Or)
                 .Query(query))
                               )
 )

Any thoughts?


(system) #7

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.