[[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. [[elasticsearch.query-methods.finders.declared]] === 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.criterions]] == Query creation Generally the query creation mechanism for Elasticsearch works as described in <>. Here's a short example of what a Elasticsearch query method translates into: .Query creation from method names ==== [source,java] ---- interface BookRepository extends Repository { List 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` (when annotated as FieldType.Keyword) | `findByNameIn(Collectionnames)` | `{ "query" : { "bool" : { "must" : [ {"bool" : {"must" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}` | `In` | `findByNameIn(Collectionnames)` | `{ "query": {"bool": {"must": [{"query_string":{"query": "\"?\" \"?\"", "fields": ["name"]}}]}}}` | `NotIn` (when annotated as FieldType.Keyword) | `findByNameNotIn(Collectionnames)` | `{ "query" : { "bool" : { "must" : [ {"bool" : {"must_not" : [ {"terms" : {"name" : ["?","?"]}} ] } } ] } }}` | `NotIn` | `findByNameNotIn(Collectionnames)` | `{"query": {"bool": {"must": [{"query_string": {"query": "NOT(\"?\" \"?\")", "fields": ["name"]}}]}}}` | `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"}}] }` | `Exists` | `findByNameExists` | `{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}` | `IsNull` | `findByNameIsNull` | `{"query":{"bool":{"must_not":[{"exists":{"field":"name"}}]}}}` | `IsNotNull` | `findByNameIsNotNull` | `{"query":{"bool":{"must":[{"exists":{"field":"name"}}]}}}` | `IsEmpty` | `findByNameIsEmpty` | `{"query":{"bool":{"must":[{"bool":{"must":[{"exists":{"field":"name"}}],"must_not":[{"wildcard":{"name":{"wildcard":"*"}}}]}}]}}}` | `IsNotEmpty` | `findByNameIsNotEmpty` | `{"query":{"bool":{"must":[{"wildcard":{"name":{"wildcard":"*"}}}]}}}` |=== NOTE: Methods names to build Geo-shape queries taking `GeoJson` parameters are not supported. Use `ElasticsearchOperations` with `CriteriaQuery` in a custom repository implementation if you need to have such a function in a repository. [[elasticsearch.query-methods.return-types]] == Method return types Repository methods can be defined to have the following return types for returning multiple Elements: * `List` * `Stream` * `SearchHits` * `List>` * `Stream>` * `SearchPage` [[elasticsearch.query-methods.at-query]] == Using @Query Annotation .Declare query on the method using the `@Query` annotation. ==== The arguments passed to the method can be inserted into placeholders in the query string. the placeholders are of the form `?0`, `?1`, `?2` etc. for the first, second, third parameter and so on. [source,java] ---- interface BookRepository extends ElasticsearchRepository { @Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}") Page findByName(String name,Pageable pageable); } ---- The String that is set as the annotation argument must be a valid Elasticsearch JSON query. It will be sent to Easticsearch as value of the query element; if for example the function is called with the parameter _John_, it would produce the following query body: [source,json] ---- { "query": { "match": { "name": { "query": "John" } } } } ---- ==== .`@Query` annotation on a method taking a Collection argument ==== A repository method such as [source,java] ---- @Query("{\"ids\": {\"values\": ?0 }}") List getByIds(Collection ids); ---- would make an https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html[IDs query] to return all the matching documents. So calling the method with a `List` of `["id1", "id2", "id3"]` would produce the query body [source,json] ---- { "query": { "ids": { "values": ["id1", "id2", "id3"] } } } ---- ====