How to apply filters in elasticsearch NEST functionscore function

To control the score of documents based on a field value, I am using filter with function_score in my DSL query and this gets the results ordered as I expect.

However on implementing this in NEST, the results are different; the score is not applied to the filter value. From further investigation I find that some versions of C# NEST Filter is not supported with ScoreFunctionsDescriptor. Is this still the case? Can you please assist with a working option to implement this with NEST? (I am new to Elastic Search and C# so please excuse if its a noob question).

I am currently using Elasticsearch v7.6, and NEST v7.5.1.

Thanks!

DSL query

GET /help/_search
{
  "query":{
   "function_score": {
     "query": {
     "bool": {
      "must": [
        {
          "multi_match": {
            "query": "AGC",
            "fields": [
              "title^2",
              "description^1"
            ],
            "type":"most_fields",
            "fuzziness": "AUTO:4,8",
            "prefix_length": 2,
            "boost": 5            
          }
        }
        ]
  }
  },
  **"functions": [**
**   { **
**    "filter": {**
**     "term":{**
**       "product":"A"**
**            }**
**              },**
**        "weight": 45**
**    },**
**   { **
**    "filter": {**
**     "term":{**
**       "product":"B"**
**            }**
**              },**
**        "weight": 20**
**    },**
**   { **
**    "filter": {**
**     "term":{**
**       "product":"C"**
**            }**
**              },**
**        "weight": 10**
**    }**
**       ],**
    "score_mode": "max",
    "boost_mode": "multiply"    
}
}
}

I answered your same question on Stack Overflow; will add here for completeness.

The function you're looking for is a weight function with a filter applied. This has been supported for a long time in the client.

The client equivalent would be something like

var response = client.Search<object>(s => s
	.Query(q => q
		.FunctionScore(fs => fs
			.Query(fsq => fsq
				.Bool(b => b
					.Must(mu => mu
						.MultiMatch(mm => mm
							.Query("AGC")
							.Fields(new[] { "title^2", "description^1" })
							.Type(TextQueryType.MostFields)
							.Fuzziness(Fuzziness.AutoLength(4,8))
							.PrefixLength(2)
							.Boost(5)
						)
					)
				)
			)
			.Functions(fu => fu
				.Weight(w => w
					.Filter(f => f
						.Term("product", "A")
					)
					.Weight(45)
				)
				.Weight(w => w
					.Filter(f => f
						.Term("product", "B")
					)
					.Weight(20)
				)
				.Weight(w => w
					.Filter(f => f
						.Term("product", "C")
					)
					.Weight(10)
				)
			)
			.ScoreMode(FunctionScoreMode.Max)
			.BoostMode(FunctionBoostMode.Multiply)
		)
	)
);

There's a couple of things that you may want to look at:

  1. description^1 can be replaced with simply description as the default boost is 1
  2. This may be better expressed as a bool query with should clauses for each of the queries in each weight function, with a boost applied similar to how weight is being used. Something like
var response = client.Search<object>(s => s
	.Query(q => q
		.Bool(b => b
			.Must(mu => mu
				.MultiMatch(mm => mm
					.Query("AGC")
					.Fields(new[] { "title^2", "description^1" })
					.Type(TextQueryType.MostFields)
					.Fuzziness(Fuzziness.AutoLength(4, 8))
					.PrefixLength(2)
					.Boost(5)
				)
			)
			.Should(
				sh => sh.Term(t => t
					.Field("product")
					.Value("A")
					.Boost(45)
				),
				sh => sh.Term(t => t
					.Field("product")
					.Value("B")
					.Boost(20)
				),
				sh => sh.Term(t => t
					.Field("product")
					.Value("C")
					.Boost(10)
				)
			)
		)
	)
);

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