[[search-validate]]
== Validate API

The validate API allows a user to validate a potentially expensive query
without executing it. We'll use the following test data to explain _validate:

[source,js]
--------------------------------------------------
PUT twitter/tweet/_bulk?refresh
{"index":{"_id":1}}
{"user" : "kimchy", "post_date" : "2009-11-15T14:12:12", "message" : "trying out Elasticsearch"}
{"index":{"_id":2}}
{"user" : "kimchi", "post_date" : "2009-11-15T14:12:13", "message" : "My username is similar to @kimchy!"}
--------------------------------------------------
// CONSOLE
// TESTSETUP

When sent a valid query:

[source,js]
--------------------------------------------------
GET twitter/_validate/query?q=user:foo
--------------------------------------------------
// CONSOLE

The response contains `valid:true`:

[source,js]
--------------------------------------------------
{"valid":true,"_shards":{"total":1,"successful":1,"failed":0}}
--------------------------------------------------
// TESTRESPONSE

[float]
=== Request Parameters

When executing exists using the query parameter `q`, the query passed is
a query string using Lucene query parser. There are additional
parameters that can be passed:

[cols="<,<",options="header",]
|=======================================================================
|Name |Description
|`df` |The default field to use when no field prefix is defined within the
query.

|`analyzer` |The analyzer name to be used when analyzing the query string.

|`default_operator` |The default operator to be used, can be `AND` or
`OR`. Defaults to `OR`.

|`lenient` |If set to true will cause format based failures (like
providing text to a numeric field) to be ignored. Defaults to false.

|`analyze_wildcard` |Should wildcard and prefix queries be analyzed or
not. Defaults to `false`.
|=======================================================================

The query may also be sent in the request body:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query
{
  "query" : {
    "bool" : {
      "must" : {
        "query_string" : {
          "query" : "*:*"
        }
      },
      "filter" : {
        "term" : { "user" : "kimchy" }
      }
    }
  }
}
--------------------------------------------------
// CONSOLE

NOTE: The query being sent in the body must be nested in a `query` key, same as
the <<search-search,search api>> works

If the query is invalid, `valid` will be `false`. Here the query is
invalid because Elasticsearch knows the post_date field should be a date
due to dynamic mapping, and 'foo' does not correctly parse into a date:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query
{
  "query": {
    "query_string": {
      "query": "post_date:foo",
      "lenient": false
    }
  }
}
--------------------------------------------------
// CONSOLE

[source,js]
--------------------------------------------------
{"valid":false,"_shards":{"total":1,"successful":1,"failed":0}}
--------------------------------------------------
// TESTRESPONSE

An `explain` parameter can be specified to get more detailed information
about why a query failed:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query?explain=true
{
  "query": {
    "query_string": {
      "query": "post_date:foo",
      "lenient": false
    }
  }
}
--------------------------------------------------
// CONSOLE

responds with:

[source,js]
--------------------------------------------------
{
  "valid" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "failed" : 0
  },
  "explanations" : [ {
    "index" : "twitter",
    "valid" : false,
    "error" : "twitter/IAEc2nIXSSunQA_suI0MLw] QueryShardException[failed to create query:...failed to parse date field [foo]"
  } ]
}
--------------------------------------------------
// TESTRESPONSE[s/"error" : "[^\"]+"/"error": "$body.explanations.0.error"/]

When the query is valid, the explanation defaults to the string
representation of that query. With `rewrite` set to `true`, the explanation
is more detailed showing the actual Lucene query that will be executed.

For Fuzzy Queries:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query?rewrite=true
{
  "query": {
    "match": {
      "user": {
        "query": "kimchy",
        "fuzziness": "auto"
      }
    }
  }
}
--------------------------------------------------
// CONSOLE
// TEST[skip:https://github.com/elastic/elasticsearch/issues/18254]

Response:

[source,js]
--------------------------------------------------
{
   "valid": true,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "explanations": [
      {
         "index": "twitter",
         "valid": true,
         "explanation": "+user:kimchy +user:kimchi^0.75 #(ConstantScore(_type:tweet))^0.0"
      }
   ]
}
--------------------------------------------------
// TESTRESPONSE

For More Like This:

[source,js]
--------------------------------------------------
GET twitter/tweet/_validate/query?rewrite=true
{
  "query": {
    "more_like_this": {
      "like": {
        "_id": "2"
      },
      "boost_terms": 1
    }
  }
}
--------------------------------------------------
// CONSOLE
// TEST[skip:https://github.com/elastic/elasticsearch/issues/18254]

Response:

[source,js]
--------------------------------------------------
{
   "valid": true,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "explanations": [
      {
         "index": "twitter",
         "valid": true,
         "explanation": "((user:terminator^3.71334 plot:future^2.763601 plot:human^2.8415773 plot:sarah^3.4193945 plot:kyle^3.8244398 plot:cyborg^3.9177752 plot:connor^4.040236 plot:reese^4.7133346 ... )~6) -ConstantScore(_uid:tweet#2)) #(ConstantScore(_type:tweet))^0.0"
      }
   ]
}
--------------------------------------------------
// TESTRESPONSE

CAUTION: The request is executed on a single shard only, which is randomly
selected. The detailed explanation of the query may depend on which shard is
being hit, and therefore may vary from one request to another.
