Logical OR between query context and filter context with Elasticsearch 2.x


(Fabio Angelini) #1

Let's say I have an index with the following mapping:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "full_text": {
          "type":  "string" 
        },
        "exact_value": {
          "type":  "string",
          "index": "not_analyzed" 
        }
      }
    }
  }
}

and I index a simple document like the following:

PUT my_index/my_type/1
{
  "full_text":   "This is the city where I live", 
  "exact_value": "MILAN"  
}

What I want, it is to create a query that can be logically expressed as:
full_text:CONTAINS('live') OR exact_value:CONTAINS('MILAN')
But I want to search full_text in the query context while exact_value in the filter context
I tried with the following query but it doesn't work (replacing MILAN with ROME is the prove)

POST _search
{
  "query" : {
    "bool" : {
      "filter" : {
        "bool" : {
          "should" : {
            "term" : {
              "exact_value" : "MILAN"
            }
          }
        }
      },
      "should" : {
        "query_string" : {
          "query" : "live",
          "fields" : [ "full_text" ]
        }
      }
    }
  }
}

(Adrien Grand) #2

Having a clause of a disjunction in a filter context makes little sense. What are you trying to achieve?


(Fabio Angelini) #3

I want to achieve a logical OR between two fields but one using the query context and the other one using the filter context. I want to use the filter context to improve performance as suggested in the documentation.


(Adrien Grand) #4

But this works the other way around: you don't decide to put a query in a filter context to make it faster, you need to define a query that meets your needs and then elastisearch will figure out the filter parts and potentially make it faster by doing less work and caching. So if you don't really care about scoring, you could put your exact value query under a constant_score query. This way scores won't be needed and your query will execute in a filter context. This will however change the scoring.


(Fabio Angelini) #5

I've just applied the following rules:
https://www.elastic.co/guide/en/elasticsearch/guide/current/_queries_and_filters.html


(Fabio Angelini) #6

It looks like it is not possible due to the following restriction:
https://www.elastic.co/guide/en/elasticsearch/reference/2.1/query-dsl-bool-query.html

Bool query in filter context
If this query is used in a filter context and it has should
clauses then at least one should clause is required to match.


(Adrien Grand) #7

I think the more general issue is that filters are aimed at making the set of potential candidates smaller. While here you want to use a filter in a disjunction, meaning that documents are not required to match the filter in order to match.


(Fabio Angelini) #8

I found the solution that can be built using the Java API

    {
      "query" : {
        "bool" : {
          "should" : [ {
            "bool" : {
              "filter" : {
                "term" : {
                  "exact_value" : "MILAN"
                }
              }
            }
          }, {
            "query_string" : {
              "query" : "live",
              "fields" : [ "full_text" ]
            }
          } ]
        }
      }
    }

(system) #9