3

I'm a new bie in ES and I want to use script filter to get all match that the array has at least one element less than max and greater than min (max and min are param in the script).

The document like:

 {
  "number": "5",
  "array": {
    "key": [
      10,
      5,
      9,
      20
    ]
  }
}

I tried the script but it does not work

{
  "script": {
    "lang": "groovy",
    "params": {
      "max": 64,
      "min": 6
    },
    "script": "for(element in doc['array.key'].values){element>= min + doc['number'].value &&  element <=max + doc['number'].value}"
  }
}

There is no error message but the search result is wrong.Is there a way to iterate array field?

Thank you all.

1
  • Did you make sure that you have enabled dynamic scripting in your elasticsearch.yml configuration file? Commented Mar 9, 2016 at 7:19

1 Answer 1

10

Yes it's doable, your script is not doing that, though. Try using Groovy's any() method instead:

doc['array.key'].values.any{ it -> it >= min + doc['number'] && it <= max + doc['number'] }

A few things:

  1. Your script just goes over a collection and checks a condition, doesn't return a boolean value, and that's what you want
  2. you might consider changing the mapping for number into an integer type
  3. not really sure why you have a field array and inside it a nested field key. Couldn't you just have a field array that would be... and array? ;-)
  4. remember that in ES by default each field can be a single value or an array.
  5. As @Val has mentioned you need to enable dynamic scripting in your conf/elasticsearch.yml but I'm guessing you've done it, otherwise you'd be getting exceptions.

A very simple mapping like this should work:

{
    "mappings": {
        "document": {
            "properties": {
                "value": {
                    "type": "integer"
                },
                "key": { 
                    "type": "integer"
                }
            }
        }
    }
}

Example:

POST /documents/document/1
 {
  "number": 5,
    "key": [
      10,
      5,
      9,
      20
    ]
}

POST /documents/document/2
 {
  "number": 5,
    "key": [
      70,
      72
    ]
}

Query:

GET /documents/document/_search
{
  "query": {
    "bool": {
      "filter": {
            "script": {
                "lang": "groovy",
                "params": {
                    "max": 64,
                    "min": 6
                },
                "script": "doc['key'].values.any{ it -> it >= min + doc['number'] && it <= max + doc['number'] }"
        }
      }
    }
  }
}

Result:

{
   "took": 22,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0,
      "hits": [
         {
            "_index": "documents",
            "_type": "document",
            "_id": "1",
            "_score": 0,
            "_source": {
               "number": 5,
               "key": [
                  10,
                  5,
                  9,
                  20
               ]
            }
         }
      ]
   }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer!!

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.