_score doesn't update in a function score query with script


(Maarten Koopmans) #1

I'm trying to get some basic working by setting the _score of a document, using function scores and/or painless scripts. I plan to use the basic block to find the mechanism to build out my final use case. Sadly it already fails. My data looks like this:

{
    "brand": "Apple",
    "flavourScore": 1.1,
    "price": 6.5
}

I have 9 items (3 Apples, 3 Bananas, 3 Tomatoes, differing in flavourScore and price). I've created 1 mapping for the index where they are in (couldn't post messages otherwise).

All documents have a _score of 1 by default. Mildly strange, but as I want to recompute the _score I don't care that much. I had tried a few examples found here and there, adapted them, but there is little in the form of debugging you can do. So I decided ny first test would be to just reset all the _score values to a different constant (as they are all 1 now as well). However.....nothing gets updated on ES64 (Docker image). Any clues why the GET on the _search endpoint for this index fails:

{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang": "painless",
              "inline": "_score = 0.18;"
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  },
  "sort": [
    "_score"
  ]
}

I'd expect all _score values to be 0.18 when I do a match_all query, but they stay 1.

Any insights, examples, clues are highly appreciated - especially as my next step will to have the script compute the value for _score

Thanks,

Maarten


(Maarten Koopmans) #3

Let me try to simplify: I want to be able to change the score of my document based on field values (boost_mode: replace).

As first use case I tried to set all my 9 test documents to the same score (to prevent script errors from getting a result). But can't even get that to work.


(Maarten Koopmans) #4

Stange, copying and pasting a doc example (the third example) to sort doesn't work - and I just use the value of one field; doc['brand'].value

It's almost as if my index is "frozen" and does not allow any changes.


(Maarten Koopmans) #5

OK, so POSTing and returning a constant from the script sets the _score.

Now I added params['_source']['flavourScore']* and get:

"caused_by": {

* "type": "script_exception",
* "reason": "compile error",
* "script_stack": [
  * "params['_source']['price' ..."
,  * "^---- HERE"],
* "script": "params['_source']['price']; return 0.2",
* "lang": "painless",
* "caused_by": {
  * "type": "illegal_argument_exception",
  * "reason": "Not a statement."}

So once I figure out how to access the price parameter in the document I might be able to close in.


(Ryan Ernst) #6

"inline": "_score = 0.18;"

This isn't a valid score script. It is unfortunate it compiles. Score scripts return the score. Here you are overriding the _score variable, but nothing reads this outside of the script. If you want the score to be 0.18, then your script should be return 0.18.


(Maarten Koopmans) #7

Yes, I got that working. However, I can't find a way to take the next step, using document variables to compute a new score. If I use either_source.varname or doc['varname'].value the script won't load and gives a null pointer exception at that location :frowning:

--Maarten


(Ryan Ernst) #8

Can you show the exact request you are using?


(Maarten Koopmans) #9

Sure. I use POST, otherwise nothing happens. The only thing I did was testing a minimal step forward, just reading a doc parameter in two ways. I've also added the mapping (first):

{
  "mappings": {
    "_doc": {
      "properties": {
        "brand": {
          "type": "text"
        },
        "flavourType": {
          "type": "double"
        },
        "price": {
          "type": "double"
        }
      }
    }
  }
}

query 1:

{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang": "painless",
              "inline": "_source.price; return 0.2"
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  },
  "sort": [
    "_score"
  ]
}

query 2:
    {
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang": "painless",
              "inline": "params['_source']['flavourScore']; return 0.2"
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  },
  "sort": [
    "_score"
  ]
}

query 1 gives back:
"caused_by": {

* "type": "script_exception",
* "reason": "compile error",
* "script_stack": [
  * "_source.price; return 0.2"
,  * "^---- HERE"],
* "script": "_source.price; return 0.2",
* "lang": "painless",
* "caused_by": {
  * "type": "illegal_argument_exception",
  * "reason": "Variable [_source] is not defined."

and query 2 gives back:
"caused_by": {

* "type": "script_exception",
* "reason": "compile error",
* "script_stack": [
  * "params['_source']['price' ..."
,  * "^---- HERE"],
* "script": "params['_source']['price']; return 0.2",
* "lang": "painless",
* "caused_by": {
  * "type": "illegal_argument_exception",
  * "reason": "Not a statement."

...which both look similar. Am I doing something wrong in the mapping definition, or is there a flag I need to set. I'm using the latest Docker image.

I hope you can see what I'm doing wrong, haven't set up, .....

Thanks for your help so far and even looking at this!

Best, Maarten


(Maarten Koopmans) #10

I've figured it out. Here's the function score with script that did the trick for me (maybe in the future, someone else finds it useful - also a nice non-trivial use case for the docs?).

{
  "query": {
    "function_score": {
      "query": {
        "match_all": {}
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "lang": "painless",
              "inline": "if ((doc['price'].value > 8) && (doc['price'].value < 10)) {return doc['flavourScore'].value * 10} else {return doc['flavourScore'].value} "
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  },
  "sort": [
    "_score"
  ]
}

(Ryan Ernst) #11

Both errors are because you have an expression but not a statement. A statement needs to be an assignment, return, or some other element of the language. Eg you can't just put foo on a line by itself (the semicolon make it its own line). You need to too foo = bar or bar = foo, or return foo, or something like that. Also note that in the first query, _source is not a valid variable; you need to access it through params as you are attempting to do in query 2.


(Ryan Ernst) #12

I've figured it out.

Great!

also a nice non-trivial use case for the docs?

If you have a place in the docs in mind, we happily accept PRs. :slight_smile:


(system) #13

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