Documentation / Features / Elastic / Query
orderBy -> sort
The orderBy
clause translates to the ElasticSearch
sort.
firstRows/maxRows -> from/size
The firstRows
and maxRows
translate to the ElasticSearch
from and size
respectively.
select/fetch -> fields/include
The select
and fetch
clauses of an ORM query translate to the ElasticSearch
fields
and _source include.
For background reading there is managing elasticsearch fields when searching.
Ebean will translate a fetch() clause into a _source include if the fetch is a *
"fetch all properties for the path" or if the path is a OneToMany or ManyToMany.
The expectation is that there will be some specific queries we want to optimise (to support Autocomplete UI etc) and for those we can store the fields we want to fetch (so that ElasticSearch does not need to read them out of the _source) and then use fields to specifically only fetch those fields. An expected use case would be to support autocomplete for 'customer name' or 'product name' etc where we really only need the id and name fields.
If no select() or fetch() is specified then no fields or _source section is included in the query and ElasticSearch will return the _source.
where -> filter context
Expressions added to where
becomes expression in the ElasticSearch
filter context.
Expression in the filter context are not scored and do not take part in relevance ordering. The benefit of expressions in the filter context is that they can be cached by ElasticSearch for performance.
By default where() expressions are joined by MUST
When multiple expressions are added to where()
they are by default added using MUST
and
this is consistent with the 'object relational' default of AND
.
Example: filter context
PagedList<Order> orders =
Order.find
.where()
// default to MUST for where()
.customer.name.istartsWith("Rob")
.status.eq(Order.Status.COMPLETE)
.setMaxRows(50)
.setUseDocStore(true)
.findPagedList();
{
"size": 50,
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{ "prefix": { "customer.name": "rob" } },
{ "term": { "status": "COMPLETE" } }
]
}
}
}
}
}
text -> query context
Expressions added to text
become expressions in the ElasticSearch
query context.
These expressions are scored and are used to determine the relevance ordering of documents.
If expressions are added text()
then the query is automatically deemed to be a document
store query.
By default text() expressions are joined by SHOULD
When multiple expressions are added to text()
they are by default added using SHOULD
and
this is consistent with the 'object relational' default of OR
.
Example: query context
PagedList<Order> orders =
Order.find
.text()
// implicitly sets setUseDocStore(true)
// goes to ElasticSearch 'query context'
// defaults to SHOULD for text()
.customer.name.match("Rob")
.status.eq(Order.Status.COMPLETE)
.setMaxRows(50)
.findPagedList();
{
"size": 50,
"query": {
"bool": {
"should": [
{ "match": { "customer.name": "Rob" } },
{ "term": { "status": "COMPLETE" } }
]
}
}
}
Example: query context and filter context
A "Full text" query can have both the query context
and filter context
like
the example query below.
List<Order> orders = Order.find
.text() // 'query context'
.must()
.customer.name.match("Rob")
.customer.name.match("Bygr")
.endJunction()
.mustNot()
.customer.status.eq(Customer.Status.ACTIVE)
.where() // 'filter context'
.should()
.status.eq(Order.Status.COMPLETE)
.status.isNotNull()
.findList();
{
"query": {
"bool": {
"must": [
{ "match": { "customer.name": "Rob" } },
{ "match": { "customer.name": "Bygr" } }
],
"must_not": [
{ "term": { "customer.status": "ACTIVE" } }
]
}
},
"filter": {
"bool": {
"should": [
{ "term": { "status": "COMPLETE" } },
{ "exists": { "field": "status" } }
]
}
}
}
Explicit useDocStore(true)
If useDocStore(true)
is set then the query will execute against ElasticSearch.
Implied useDocStore(true)
A query is implicitly set as a doc store query when:
text()
is used- Text junctions are used -
must()
,mustNot()
,should()
- A "Full text" expression is used -
match()
,multiMatch()
,textSimple()
,textQueryString()
,textCommonTerms()
Must, must not, should
MUST
, MUST NOT
and SHOULD
are junction expressions that are
using in text searches and map to AND
, NOT
and OR
respectively.
We can not use must(), mustNot() or should() in normal ORM queries and as soon as we use one of these 'text search junction expressions' the query is automatically considered a document store query and will hit ElasticSearch.
Product
.where()
// we used must() so automatically
// becomes a doc store query
.must()
.sku.equalTo("C002")
.findList();
We use must()
, mustNot()
and should()
to join
expressions.
List<Customer> customers =
server.find(Customer.class)
.text()
.must()
.match("name", "Rob")
.match("smallNote", "interesting")
.findList();
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Rob" } },
{ "match": { "smallNote": "interesting" } }
]
}
}
}
We use endJunction()
to end the 'current junction' so that we can start
another one.
List<Order> orders = Order.find
.text() // 'query context'
.must()
.customer.name.match("Rob")
.customer.name.match("Bygr")
.endJunction()
.mustNot()
.customer.status.eq(Customer.Status.ACTIVE)
.where() // 'filter context'
.should()
.status.eq(Order.Status.COMPLETE)
.status.isNotNull()
.findList();
{
"query": {
"bool": {
"must": [
{ "match": { "customer.name": "Rob" } },
{ "match": { "customer.name": "Bygr" } }
],
"must_not": [
{ "term": { "customer.status": "ACTIVE" } }
]
}
},
"filter": {
"bool": {
"should": [
{ "term": { "status": "COMPLETE" } },
{ "exists": { "field": "status" } }
]
}
}
}
Match
Match is an ElasticSearch only expression and when used the query is automatically treated as a document store query.
For query beans the match()
expression is available on properties of type string.
List<Order> orders =
new QOrder()
.customer.name.match("Rob")
.findList();
{
"query": {
"match": {
"customer.name": "Rob"
}
}
}
Multi match, Text simple etc
multiMatch()
, textSimple()
,
textCommonTerms()
and textQueryString()
are all ElasticSearch only
expression and using them automatically make the query a document store query.
These expression are "query level" expressions that apply to multiple fields or the entire document (_all field).
MultiMatch multiMatch =
MultiMatch.fields("customer.name", "customer.notes")
.opAnd()
.type(MultiMatch.Type.PHRASE_PREFIX);
new QOrder()
.multiMatch("Rob", multiMatch)
.findList();
{"query": {
"multi_match": {
"query": "Rob",
"fields": [
"customer.name",
"customer.notes"
],
"type": "phrase_prefix",
"operator": "and"
}
}}
Text expressions
match
match
maps to ElasticSearch match query.
multi match
multi match
maps to ElasticSearch multi match query.
text simple
text simple
maps to ElasticSearch simple query string query.
text query string
text query string
maps to ElasticSearch query string query.
text common terms
text common terms
maps to ElasticSearch common terms query.