2019-06-28 21:40:59 +02:00
[[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
2020-10-21 23:05:18 +02:00
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>> ).
2019-06-28 21:40:59 +02:00
[[elasticsearch.query-methods.criterions]]
== Query creation
2020-10-21 23:05:18 +02:00
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:
2019-06-28 21:40:59 +02:00
.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]
----
2020-01-02 13:27:32 +01:00
{
"query": {
"bool" : {
"must" : [
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
]
}
2019-06-28 21:40:59 +02:00
}
}
----
A list of supported keywords for Elasticsearch is shown below.
2020-10-21 23:05:18 +02:00
[cols="1,2,3",options="header"]
2019-06-28 21:40:59 +02:00
.Supported keywords inside method names
|===
| Keyword
| Sample
2020-08-24 07:02:43 +02:00
| Elasticsearch Query String
| `And`
2019-06-28 21:40:59 +02:00
| `findByNameAndPrice`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Or`
| `findByNameOrPrice`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"should" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } },
{ "query_string" : { "query" : "?", "fields" : [ "price" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Is`
| `findByName`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Not`
| `findByNameNot`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must_not" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?", "fields" : [ "name" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Between`
| `findByPriceBetween`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : ?, "to" : ?, "include_lower" : true, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
2020-01-02 13:27:32 +01:00
| `LessThan`
2019-06-28 21:40:59 +02:00
| `findByPriceLessThan`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : false } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
| `LessThanEqual`
| `findByPriceLessThanEqual`
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
| `GreaterThan`
| `findByPriceGreaterThan`
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : false, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `GreaterThanEqual`
| `findByPriceGreaterThan`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Before`
| `findByPriceBefore`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : null, "to" : ?, "include_lower" : true, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `After`
| `findByPriceAfter`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"range" : {"price" : {"from" : ?, "to" : null, "include_lower" : true, "include_upper" : true } } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Like`
| `findByNameLike`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `StartingWith`
| `findByNameStartingWith`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `EndingWith`
| `findByNameEndingWith`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "*?", "fields" : [ "name" ] }, "analyze_wildcard": true }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `Contains/Containing`
| `findByNameContaining`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "\*?*", "fields" : [ "name" ] }, "analyze_wildcard": true }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
2020-08-24 07:02:43 +02:00
| `In` (when annotated as FieldType.Keyword)
2019-06-28 21:40:59 +02:00
| `findByNameIn(Collection<String>names)`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"bool" : {"must" : [
{"terms" : {"name" : ["?","?"]}}
]
}
}
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
2020-08-24 07:02:43 +02:00
| `In`
| `findByNameIn(Collection<String>names)`
| `{ "query": {"bool": {"must": [{"query_string":{"query": "\"?\" \"?\"", "fields": ["name"]}}]}}}`
| `NotIn` (when annotated as FieldType.Keyword)
2019-06-28 21:40:59 +02:00
| `findByNameNotIn(Collection<String>names)`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{"bool" : {"must_not" : [
{"terms" : {"name" : ["?","?"]}}
]
}
}
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
2020-08-24 07:02:43 +02:00
| `NotIn`
| `findByNameNotIn(Collection<String>names)`
| `{"query": {"bool": {"must": [{"query_string": {"query": "NOT(\"?\" \"?\")", "fields": ["name"]}}]}}}`
2019-06-28 21:40:59 +02:00
| `True`
| `findByAvailableTrue`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "true", "fields" : [ "available" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `False`
| `findByAvailableFalse`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "false", "fields" : [ "available" ] } }
]
}
2020-01-02 13:27:32 +01:00
}}`
2019-06-28 21:40:59 +02:00
| `OrderBy`
| `findByAvailableTrueOrderByNameDesc`
2020-01-02 13:27:32 +01:00
| `{ "query" : {
"bool" : {
"must" : [
2020-10-21 23:05:18 +02:00
{ "query_string" : { "query" : "true", "fields" : [ "available" ] } }
]
}
2020-01-02 13:27:32 +01:00
}, "sort":[{"name":{"order":"desc"}}]
}`
2021-09-25 14:51:40 +02:00
| `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":"*"}}}]}}}`
2019-06-28 21:40:59 +02:00
|===
2020-10-21 23:05:18 +02:00
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.
2020-01-03 23:20:17 +01:00
== Method return types
Repository methods can be defined to have the following return types for returning multiple Elements:
* `List<T>`
* `Stream<T>`
* `SearchHits<T>`
2020-05-06 08:19:48 +02:00
* `List<SearchHit<T>>`
2020-03-06 19:08:49 +01:00
* `Stream<SearchHit<T>>`
* `SearchPage<T>`
2020-01-03 23:20:17 +01:00
2019-06-28 21:40:59 +02:00
[[elasticsearch.query-methods.at-query]]
== Using @Query Annotation
2022-01-20 18:35:40 +00:00
.Declare query on the method using the `@Query` annotation.
2019-06-28 21:40:59 +02:00
====
2022-01-20 18:35:40 +00:00
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.
2019-06-28 21:40:59 +02:00
[source,java]
----
interface BookRepository extends ElasticsearchRepository<Book, String> {
2020-03-06 19:08:49 +01:00
@Query("{\"match\": {\"name\": {\"query\": \"?0\"}}}")
2019-06-28 21:40:59 +02:00
Page<Book> findByName(String name,Pageable pageable);
}
----
2020-10-21 23:05:18 +02:00
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:
2020-03-06 19:08:49 +01:00
[source,json]
----
{
"query": {
"match": {
"name": {
"query": "John"
}
}
}
}
----
2019-06-28 21:40:59 +02:00
====
2022-01-20 18:35:40 +00:00
.`@Query` annotation on a method taking a Collection argument
====
A repository method such as
[source,java]
----
@Query("{\"ids\": {\"values\": ?0 }}")
List<SampleEntity> getByIds(Collection<String> 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"]
}
}
}
----
====