We have seen the operations of elasticsearch queries and filters and the most commonly used queries with examples in the previous posts to this series so far. In this article, we will take a look at one of the most useful type of query methods, which is the “naming” of queries or simply named queries with examples.

Index creation and indexing documents

For the time being, we can use the same documents in the index named testindex we created for the previous article on queries to this series.

Named Queries

There are chances that some of our queries would become more bulky and lengthy over the evolution of our application. Since a query is composed of numerous sub-queries and filters, it would be beneficial to know which of these queries matched against each document. This breakage and analysis would be useful in case where we need to do extensive debugging which in turn would help us in getting better results.

Elasticsearch has provisioned its queries with a naming system, so that each query can be named individually.

A simple named query

First of all let us see how a simple named match query differs from that of a unnamed match query in format and structure. Let us also explore how it works. Let us run the following query in the testindex.

curl -XGET<a href="http://localhost:9200/testindex/employee/_search?pretty=true"> http://localhost:9200/testindex/employee/_search?pretty=true</a> -d '{
  "query": {
    "match": {
      "name": {
        "query": "adams",
        "_name": "query on name field"
      }
    }
  }
}'
'

The above is a simple match query, named as query on name field. Upon comparing with the unnamed match query we have used in the previous post, we can see here the field name "name" is given as a separate level below the query name "match". We have defined the query keyword "adams" against the query field, and lastly the "_name", which is used to define the name "query on name field" of the query. Running this will return us the following response:

{
  "_index": "testindex",
  "_type": "employee",
  "_id": "2",
  "_score": 0.19178301,
  "_source": {
    "name": "July Adams",
    "name_not_analyzed": "July Adams",
    "status": "just feeling sulky",
    "employee-id": "IL F-2213",
    "dessert": "i love marshmallows",
    "favourite_car": "porche"
  },
  "matched_queries": [
    "query on name field"
  ]
}

Here you can see there only one document shown above matched the results. There is field "matched_queries" in the response along the document, which shows the name of the queries the document was matched against. In our case, the query with the name "query on name field" matched against this document and is listed in the "matched_queries" field.

Naming the bool query conditions

Seldom are our queries as simple as the above match query. In most practical cases, the master query would be a bool query with different clauses. In such cases we would be naming each query clause differently so that it would be easy for us to identify which queries matched with which documents.

In "testindex" we are going to apply a bool query with the following requirements:

  1. It must match documents with the word "feeling" in the "status" field.
  2. It must not include the documents with the word "audi" in the "favourite_car" field.
  3. Make the relevancy more if the field "dessert" contains the word "macaroon".

We can apply the bool query for above conditions as we have done for the demonstration of the bool query in the previous post. As told earlier, if we want to examine which all queries matched against the documents, we need to use naming for the queries, which can be done as below:

curl -XGET<a href="http://localhost:9200/testindex/employee/_search?pretty=true"> http://localhost:9200/testindex/employee/_search?pretty=true</a> -d '{
  "query": {
    "bool": {
      "must": {
        "match": {
          "status": {
            "query": "feeling",
            "_name": "query on name field"
          }
        }
      },
      "must_not": {
        "match": {
          "favourite_car": {
            "query": "audi",
            "_name": "query on car field"
          }
        }
      },
      "should": [
        {
          "match": {
            "dessert": {
              "query": "macaroon",
              "_name": "query on dessert"
            }
          }
        }
      ]
    }
  }
}'

In the response, we can see first document matched has a higher score and the second document has a lower score. To examine why is it so, we can simply look to the "matched_queries" section for each document. For the document with the highest score we can see that "matched_queries" field contains "query on dessert" and "query on name field", which indicates it matched two clauses of our query. As for the second document, we can see "query on name field" was the only match and hence the lower score. In this example we were able to understand the scoring better by using the named queries.

Extending naming to filters

The naming process is not limited to queries alone. This can be extended to filters, too. A simple example of naming in filters is below.

curl -XGET<a href="http://localhost:9200/testindex/employee/_search?pretty=true"> http://localhost:9200/testindex/employee/_search?pretty=true</a> -d ‘{
  "query": {
    "filtered": {
      "filter": {
        "term": {
          "name": "turner",
          "_name": "filter on name"
        }
      }
    }
  }
}’

Here we have named the filter as "filter on name" which can be seen in the matching document’s "matched_queries" section.

Conclusion

In this post we explained how to name queries and filters and use it for gaining a better understanding of the complex queries used. Questions, comments? Leave us a note below.