Wonay
Wonay

Reputation: 1250

Filter by length of nested array

Here is my mapping:

{"field_name": {
    "dynamic": "strict",
    "properties": {...},
    "type": "nested"
}}

And I am trying to filter only documents which have at least one field_name.

I tried:

{"query": {
    "bool": {
        "filter": [ { "script" : {
              "script" : {
                   "inline": "doc['field_name'].length >= 1",
                   "lang": "painless"
        } } ]
    }
} }

But elasticsearch is screaming at me about No field found for [field_name] in mapping with types [type_name].

I also tried to wrap the previous query into a nested but didn't work either:

{ "nested": {
     "path": "field_name",
     "query": {
          "bool": {
              "filter": [ {
                   "script": {
                        "script": {
                            "inline": "doc['field_name'].length >= 1",
                            "lang": "painless"
                        }
                   }
              } ]
         }
    }
} }

This gave the same error as above.

Any ideas?

Upvotes: 6

Views: 6732

Answers (3)

Lambda
Lambda

Reputation: 138

if all object has same field , you can use exist to check if object exist, then use sum to calc count,then use script score to choose the condition you want. like below code

{
  "query": {
    "function_score": {
      "query": {
        "nested": {
          "path": "field_name",
          "query": {
            "exists": {
              "field": "field_name.same_field"
            }
          },
          "score_mode": "sum"
        }
      },
      "functions": [
        {
          "script_score": {
            "script": {
              "source": "_score >= 1 ? 1 : 0"
            }
          }
        }
      ],
      "boost_mode": "replace"
    }
  },
  "min_score": 1
}

Upvotes: 6

Wonay
Wonay

Reputation: 1250

What I ended up doing is adding a field my_array_length during construction time. Like that I can just filter by the value of this field.

Upvotes: 3

Eli
Eli

Reputation: 4926

Simple approach would be using exists term for each of the fields:

{
  "query": {
    "filtered": {
      "filter": {
        "bool": {
          "should": [
            {
              "exists": {
                "field": "field_name.dynamic"
              }
            },
            {
              "exists": {
                "field": "field_name.properties"
              }
            },
            {
              "exists": {
                "field": "field_name.type"
              }
            }
          ],
          "minimum_should_match": 1
        }
      }
    }
  }
}

You define should clause with minimum_should_match and get only relevant documents.

See exists, bool-query

Upvotes: 0

Related Questions