Home » Php » php – How to combine multi term query in Elasticsearch filter

php – How to combine multi term query in Elasticsearch filter

Posted by: admin February 25, 2020 Leave a comment

Questions:

I’m currently looking for building an Elasticsearch filter (for my query) to filter my query but it’s failing because the filter don’t filter as well.

The ES cluster version is 6.8.3.
Here is my current filter code (PHP version):

'filter' => [
     ['term' => 
            [
                                'displayMode' => 'hidden'
                            ]],
                            [ 'bool' => [
                                'must_not' => [
                                    [ 'bool' => [
                                        'must' => [
                                            'term' => ['displayMode' => 'untreated']
                                        ]
                                    ]],
                                    [ 'bool' => [
                                        'must' => [
                                            'term' => [ 'lifetime' => 'temporary' ]
                                        ]
                                    ]]
                                ]]
                            ],
                            [ 'bool' => [
                                'must' => [
                                    [ 'bool' => [
                                        'must_not' => [
                                            'term' => ['activity' => 'inactive']
                                        ]
                                    ]],
                                    [ 'bool' => [
                                        'must_not' => [
                                            'term' => [ 'lifetime' => 'everlasting' ]
                                        ]
                                    ]],
                                    [ 'bool' => [
                                        'should' => [
                                            [ 'range' => [
                                                'toDate' => [
                                                    'lt' => (new \DateTime())->format('Y-m-d')
                                                ]
                                            ]],
                                            [ 'bool' => [
                                                'must_not' => [
                                                    'exists' => [
                                                        'field' => 'toDate'
                                                    ]
                                                ]
                                            ]]
                                        ]
                                    ]]
                                ]
                            ]]
      ]

So, to display an item, you must respect all these conditions:

item.displayAll != 'hidden'

AND

(item.displayMode != 'untreated' AND item.lifetime != 'temporary')

AND ALSO

(item.activity != 'inactive' AND item.lifetime != 'everlasting' AND item.toDate < NOW())

Unfortunately, my “multi” term conditions are not multi, so each of the sub filters seems to be executed one by one. So if my item are “untreated” but its “lifetime” is other than “temporary”, the item is filtering but it shouldn’t be.

EDIT:
When I try to simplify my filter (just to check if the little one is working) it’s not working also…

// ...
'filter' => [
                                ['bool' => [
                                    'must_not' => [
                                        ['term' => [ 'displayMode' => 'untreated' ]],
                                        ['term' => [ 'lifetime' => 'temporary' ]]
                                    ]
                                ]],
   // ...

OR

'filter' => [
                                ['bool' => [
                                    'must' => [
                                        ['bool' => [
                                            'must_not' => [
                                                ['term' => [ 'displayMode' => 'untreated' ]],
                                            ]
                                        ]],
                                        ['bool' => [
                                            'must_not' => [
                                                ['term' => [ 'lifetime' => 'temporary' ]]
                                            ]
                                        ]]
                                    ]
                                ]],

(the two examples above are not working because it’s filtering all results, even the valid ones)

OR

'filter' => [
                                ['bool' => [
                                    'should' => [
                                        ['bool' => [
                                            'must_not' => [
                                                ['term' => [ 'displayMode' => 'untreated' ]],
                                            ]
                                        ]],
                                        ['bool' => [
                                            'must_not' => [
                                                ['term' => [ 'lifetime' => 'temporary' ]]
                                            ]
                                        ]]
                                    ]
                                ]],

(Exemple above, it’s not filtering anything like I wanted to).

OR

'filter' => [
                                ['bool' => [
                                    'must_not' => [
                                        ['term' => [ 'displayMode' => 'untreated' ]],
                                        ['term' => [ 'lifetime' => 'temporary' ]]
                                    ]
                                ]]

Idem, it’s filtering all the results..

Can anyone can help me please?

How to&Answers:

So according to your boolean logic, you can simply transform that into bool queries:

  • AND => filter
  • OR => should
  • != => must_not

It would yield this:

{
  "query": {
    "bool": {
      "minimum_should_match": 1,
      "should": [
        {
          "bool": {
            "must_not": {
              "term": {
                "displayMode": "hidden"
              }
            }
          }
        },
        {
          "bool": {
            "must_not": [
              {
                "term": {
                  "displayMode": "untreated"
                }
              },
              {
                "term": {
                  "lifetime": "temporary"
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must_not": [
              {
                "term": {
                  "activity": "inactive"
                }
              },
              {
                "term": {
                  "lifetime": "everlasting"
                }
              },
              {
                "bool": {
                  "should": [
                    {
                      "range": {
                        "toDate": {
                          "lt": "now"
                        }
                      }
                    },
                    {
                      "bool": {
                        "must_not": {
                          "exists": {
                            "field": "toDate"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Answer:

So, after a huge waste of time, I finally realized that my index was not containing the “lifetime” field. All the filters conditions was failed for that. My first query was the good one (or one way to do what I wanted to do).
Have a good day.