[[elasticsearch.query-methods]]
= Query methods

[[elasticsearch.query-methods.finders]]
== Query lookup strategies

The Elasticsearch module supports all basic query building feature as string queries, native search queries, criteria based queries or have it being derived from the method name.

=== Declared queries

Deriving the query from the method name is not always sufficient and/or may result in unreadable method names. In this case one might make use of the `@Query` annotation (see <<elasticsearch.query-methods.at-query>> ).

[[elasticsearch.query-methods.criterions]]
== Query creation

Generally the query creation mechanism for Elasticsearch works as described in <<repositories.query-methods>>. Here's a short example of what a Elasticsearch query method translates into:

.Query creation from method names
====
[source,java]
----
interface BookRepository extends Repository<Book, String> {
  List<Book> findByNameAndPrice(String name, Integer price);
}
----
====

The method name above will be translated into the following Elasticsearch json query

[source]
----
{
    "query": {
        "bool" : {
            "must" : [
                { "query_string" : { "query" : "?", "fields" : [ "name" ] } },
                { "query_string" : { "query" : "?", "fields" : [ "price" ] } }
            ]
        }
    }
}
----

A list of supported keywords for Elasticsearch is shown below.

[cols="1,2,3", options="header"]
.Supported keywords inside method names
|===
| Keyword
| Sample
| Elasticsearch Query String| `And`
| `findByNameAndPrice`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "?", "fields" : [ "name" ] } },
      { "query_string" : { "query" : "?", "fields" : [ "price" ] } }
    ]
  }
}}`

| `Or`
| `findByNameOrPrice`
| `{ "query" : {
"bool" : {
"should" : [
      { "query_string" : { "query" : "?", "fields" : [ "name" ] } },
      { "query_string" : { "query" : "?", "fields" : [ "price" ] } }
    ]
  }
}}`

| `Is`
| `findByName`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "?", "fields" : [ "name" ] } }
    ]
  }
}}`

| `Not`
| `findByNameNot`
| `{ "query" : {
"bool" : {
"must_not" : [
      { "query_string" : { "query" : "?", "fields" : [ "name" ] } }
    ]
  }
}}`

| `Between`
| `findByPriceBetween`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } }
    ]
  }
}}`

| `LessThan`
| `findByPriceLessThan`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } }
    ]
  }
}}`

| `LessThanEqual`
| `findByPriceLessThanEqual`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
    ]
  }
}}`

| `GreaterThan`
| `findByPriceGreaterThan`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } }
    ]
  }
}}`


| `GreaterThanEqual`
| `findByPriceGreaterThan`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
    ]
  }
}}`

| `Before`
| `findByPriceBefore`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
    ]
  }
}}`

| `After`
| `findByPriceAfter`
| `{ "query" : {
"bool" : {
"must" : [
    {"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
    ]
  }
}}`

| `Like`
| `findByNameLike`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
    ]
  }
}}`

| `StartingWith`
| `findByNameStartingWith`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
    ]
  }
}}`

| `EndingWith`
| `findByNameEndingWith`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true }
    ]
  }
}}`

| `Contains/Containing`
| `findByNameContaining`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "\*?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
    ]
  }
}}`

| `In`
| `findByNameIn(Collection<String>names)`
| `{ "query" : {
"bool" : {
"must" : [
      {"bool" : {"must" : [
            {"terms" : {"name" : ["?","?"]}}
          ]
        }
      }
    ]
  }
}}`

| `NotIn`
| `findByNameNotIn(Collection<String>names)`
| `{ "query" : {
"bool" : {
"must" : [
      {"bool" : {"must_not" : [
            {"terms" : {"name" : ["?","?"]}}
          ]
        }
      }
    ]
  }
}}`

| `Near`
| `findByStoreNear`
| `Not Supported Yet !`

| `True`
| `findByAvailableTrue`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "true", "fields" : [ "available" ] } }
    ]
  }
}}`

| `False`
| `findByAvailableFalse`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "false", "fields" : [ "available" ] } }
    ]
  }
}}`

| `OrderBy`
| `findByAvailableTrueOrderByNameDesc`
| `{ "query" : {
"bool" : {
"must" : [
      { "query_string" : { "query" : "true", "fields" : [ "available" ] } }
    ]
  }
}, "sort":[{"name":{"order":"desc"}}]
}`

|===

== Method return types

Repository methods can be defined to have the following return types for returning multiple Elements:

* `List<T>`
* `Stream<T>`
* `SearchHits<T>`
* `List<SearchHits<T>>`
* `Stream<>>SearchHit<T>>`

[[elasticsearch.query-methods.at-query]]
== Using @Query Annotation

.Declare query at the method using the `@Query` annotation.
====
[source,java]
----
interface BookRepository extends ElasticsearchRepository<Book, String> {
    @Query("{\"bool\" : {\"must\" : {\"field\" : {\"name\" : \"?0\"}}}}")
    Page<Book> findByName(String name,Pageable pageable);
}
----
====
