0

I have a bunch of objects like this one in Elastic:

{
          "id" : "b397ab9c-2bab-4cce-a419-ba6b23545772",
          "name": "Alice",
          // other fields omitted
          "foo" : [
            {
              "id" : "1",
              "bar" : 20
            },
            {
              "id" : "2",
              "bar" : 20
            }
           ]
},
{
          "id" : "826784cb-7dcd-4d2c-b444-a466032a7b06",
          "name": "Bob",
          // other fields omitted
          "foo" : [
            {
              "id" : "1",
              "bar" : 15
            }
           ]
}

I am trying to make a score based on any elements in foo of which the id is 2. So in the above objects, Alice has a score of 20 and Bob has a score of 0 (as there's no element with id 2 in his foo array. I'm however a bit stuck in how to have my script_score look for the specific element. Here is my query:

  "query": {
    "function_score": {
      "score_mode": "max", 
      "functions": [
        {
          "filter": {
            "term": {
              "foo.id": {
                "value": "2"
              }
            }
          },
          "script_score": {
            "script": {
              "source": "doc['foo'].values /* what goes here? */",
              "params": {
              }
            }
          }
        }
      ]
    }
  }
2
  • Is foo nested ? Commented Nov 30, 2020 at 14:34
  • No, the foo key is in the root of the object. It is an array that contains simple objects. Commented Nov 30, 2020 at 14:55

1 Answer 1

1

When foo is not of type nested, you'll have lost the connection between id and bar due to value flattenning.

After you've reconfigured your mapping to be nested, you can do

{
  "query": {
    "nested": {
      "path": "foo",
      "query": {
        "function_score": {
          "score_mode": "max",
          "functions": [
            {
              "script_score": {
                "script": {
                  "source": "if (doc['foo.id.keyword'].value == '2') { def bar = doc['foo.bar'].value; return bar } return 0",
                  "params": {}
                }
              }
            }
          ]
        }
      }
    }
  }
}

but without the filter because that'd have filtered out doc#2 since it does not meet that condition and you probably want to do some sort of a scripted fallback.

Do note that once you're in the nested context, you don't have access to other object groups in your foo array. In other words, when you're in id: 2, you don't see the id: 1 group. More info here.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks Joe, I'll try reconfiguring my mapping tomorrow.
Got it working, thanks. I'll buy you a coffee tonight!
coming here from the other question posted by @yesman and answered by joe im just here because i actually found a nice interaction in the comments
Cheers @Alvaromon! Which question though?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.