Elasticsearch Scoring function is based on maximum value in array / nested

I have a field inside my document that stores an array of integers.

Java class:

public class Clazz {
    public List<Foo> foo;

    public static Foo {
         public Integer bar;
         public Integer baz;
    }
}

      

Mapping:

"properties" : {
    "foo" : {
        "properties" : {
          "bar" : {
            "type" : "integer"
          },
          "baz" : {
            "type" : "integer"
          }
        }
    }
}

      

Examples of documents:

{
    id: 1
    foo: [
        { bar: 10 }, 
        { bar: 20 }
    ]
},

{
    id: 2
    foo: [
        { bar: 15 }
    ]
}

      

Now I would like to make my account. Counting function gives the value of input

: 10

.

And the scoring function basically has: "The closer foo.bar

to input

, the higher the score. And if foo.bar

lower than input

, the score will only be half good

Request:

"function_score" : {
    "functions" : [ {
        "script_score" : {
            "script" : "if(doc['foo.bar'].value >= input) { (input - doc['foo.bar'].value) * 1 } else { (doc['foo.bar'].value - input) * 2 }",
            "lang" : "groovy",
            "params" : {
                "input" : 10
            }
      }
} ],
"score_mode" : "max",
"boost_mode" : "replace"

      

}

Expected Result:

id 1

must be first because there is foo.bar

one that matches input=10

.

What's happening:

Scoring works great if documents have only one value foo.bar

. If an array (like in doc c id 1

) Elasticsearch seems to take the last value in the array.

What the request should do:

Take your best score. This is why I used score_mode: max

. But it seems that this only respects the array functions

in function_score

and not (as I expected) the possible evaluations inside the function.


I read somewhere about usage doc['foo.bar'].values

( s value instead of value), but I don't know how to use it in this case.

Do you have an idea how to do this?

+3


source to share


1 answer


One way to achieve this with groovy is as follows: you can use the maximum list method by values.

Example:



{
   "query": {
      "function_score": {
         "functions": [
            {
               "script_score": {
                  "script": "max_score=doc[\"foo.bar\"].values.max();if(max_score >= input) {return (max_score - input);} else { return (max_score - input) *2;}",
                  "lang": "groovy",
                  "params": {
                     "input": 10
                  }
               }
            }
         ],
         "score_mode": "max",
         "boost_mode": "replace"
      }
   }
}

      

+3


source







All Articles