Function Score Functions with Nested Objects and Score Replace

I have tried various approaches to combine function_score with a nested field inside "functions" in order to override the relevance _score.
The "query" within the function_score works perfectly, as intended. However, the score always defaults to 1 as shown within the "_explanation" object (see below).

I simplified the query removing all aggregations and most filters to exemplify the issue:
Query:

{
  "_source": true,
  "from": 0,
  "size": 60,
  "query": {
    "function_score": {
      "boost_mode": "replace",
      "query": {
        "bool": {
          "filter": [
            {
              "terms": {
                "brand_product": [
                  "false"
                ]
              }
            },
            {
              "nested": {
                "path": "color_data",
                "query": {
                  "function_score": {
                    "boost_mode": "sum",
                    "score_mode": "multiply",
                    "functions": [
                      {
                        "linear": {
                          "color_data.density": {
                            "offset": 5,
                            "origin": 100,
                            "scale": 10
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.h": {
                            "offset": 2,
                            "origin": 226,
                            "scale": 4
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.s": {
                            "offset": 4,
                            "origin": 62,
                            "scale": 8
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.l": {
                            "offset": 4,
                            "origin": 41,
                            "scale": 8
                          }
                        }
                      }
                    ],
                    "query": {
                      "bool": {
                        "must": [
                          {
                            "range": {
                              "color_data.density": {
                                "gte": 40,
                                "lte": 100
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.h": {
                                "gte": 200,
                                "lte": 254
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.s": {
                                "gte": 41,
                                "lte": 84
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.l": {
                                "gte": 24,
                                "lte": 58
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          ],
          "must": [
            {
              "match_all": {}
            }
          ]
        }
      },
      "score_mode": "sum",
      "functions": [
        {
          "script_score": {
            "script": "_score"
          }
        }
      ]
    }
  }
}

This is what I get on the explanation object:

{
  "_explanation": {
    "value": 1,
    "description": "sum of:",
    "details": [
      {
        "value": 1,
        "description": "min of:",
        "details": [
          {
            "value": 1,
            "description": "script score function, computed with script:\"Script{type=inline, lang='painless', idOrCode='_score', options={}, params={}}\"",
            "details": [
              {
                "value": 1,
                "description": "_score: ",
                "details": [
                  {
                    "value": 1,
                    "description": "ConstantScore(#ConstantScore(brand_product:F) #ToParentBlockJoinQuery (+function score (+color_data.density:[40 TO 100] +color_data.hsl.h:[200 TO 254] +color_data.hsl.s:[41 TO 84] +color_data.hsl.l:[24 TO 58], functions: [{org.elasticsearch.index.query.functionscore.DecayFunctionBuilder$NumericFieldDataScoreFunction@2acaad3f}{org.elasticsearch.index.query.functionscore.DecayFunctionBuilder$NumericFieldDataScoreFunction@547c3b41}{org.elasticsearch.index.query.functionscore.DecayFunctionBuilder$NumericFieldDataScoreFunction@127c3b4c}{org.elasticsearch.index.query.functionscore.DecayFunctionBuilder$NumericFieldDataScoreFunction@127c3b45}]) #_nested_path:color_data))",
                    "details": []
                  }
                ]
              }
            ]
          },
          {
            "value": 3.4028235e+38,
            "description": "maxBoost",
            "details": []
          }
        ]
      },
      {
        "value": 0,
        "description": "match on required clause, product of:",
        "details": [
          {
            "value": 0,
            "description": "# clause",
            "details": []
          },
          {
            "value": 1,
            "description": "DocValuesFieldExistsQuery [field=_primary_term]",
            "details": []
          }
        ]
      }
    ]
  }
}

All of the hits end up w/ a "score": 1 as if the nested field wasn't found. The Query with the combination of function_score, bool and nested field works perfectly and returns results meeting all the filters and color_data range requirements.

Any help is greatly appreciated!

you want replace? Only function score is used, the query score is ignored.

I may combine it later for a more balanced scoring, either via sum or multiply.
However, at this moment I do want "replace" to see the full effects of the Decay Functions. I am not interested in the Query Score yet.

Hi @RabBit_BR , do you have any advise based on the reply?
Thank you very much.

Hi.
I'm not sure how your query should work but I would remove the "nested" from the "filter" clause because filter does not impact the score calculation.

Maybe this:

{
  "_source": true,
  "from": 0,
  "size": 60,
  "query": {
    "function_score": {
      "boost_mode": "replace",
      "query": {
        "bool": {
          "filter": [
            {
              "terms": {
                "brand_product": [
                  "false"
                ]
              }
            }
          ],
          "must": [
              {
              "nested": {
                "path": "color_data",
                "query": {
                  "function_score": {
                    "boost_mode": "sum",
                    "score_mode": "multiply",
                    "functions": [
                      {
                        "linear": {
                          "color_data.density": {
                            "offset": 5,
                            "origin": 100,
                            "scale": 10
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.h": {
                            "offset": 2,
                            "origin": 226,
                            "scale": 4
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.s": {
                            "offset": 4,
                            "origin": 62,
                            "scale": 8
                          }
                        }
                      },
                      {
                        "exp": {
                          "color_data.hsl.l": {
                            "offset": 4,
                            "origin": 41,
                            "scale": 8
                          }
                        }
                      }
                    ],
                    "query": {
                      "bool": {
                        "must": [
                          {
                            "range": {
                              "color_data.density": {
                                "gte": 40,
                                "lte": 100
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.h": {
                                "gte": 200,
                                "lte": 254
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.s": {
                                "gte": 41,
                                "lte": 84
                              }
                            }
                          },
                          {
                            "range": {
                              "color_data.hsl.l": {
                                "gte": 24,
                                "lte": 58
                              }
                            }
                          }
                        ]
                      }
                    }
                  }
                }
              }
            },
            {
              "match_all": {}
            }
          ]
        }
      },
      "score_mode": "sum",
      "functions": [
        {
          "script_score": {
            "script": "_score"
          }
        }
      ]
    }
  }
}
1 Like

Hi @terzano, did you find the solution?

That is it, thanks @RabBit_BR !!
Filters do not affect score calculations and consequently it needs to be removed from it.
I thought it would since it was wrapped in a function_score but it obviously does not.
I think I have enough to proceed and solve the problem.
Thanks a million!

1 Like

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