This section describes the Groovy API elasticsearch provides. All elasticsearch APIs are executed using a GClient, and are completely asynchronous in nature (they either accept a listener, or return a future).
The Groovy API is a wrapper on top of the Java API exposing it in a groovier manner. The execution options for each API follow a similar manner and covered in ?.
The Groovy API is hosted on Maven Central.
For example, you can define the latest version in your pom.xml file:
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch-lang-groovy</artifactId>
<version>${es.version}</version>
</dependency>
Once a GClient has been obtained, all of Elasticsearch APIs can be executed on it. Each Groovy API is exposed using three different mechanisms.
The first type is to simply provide the request as a Closure, which automatically gets resolved into the respective request instance (for the index API, its the IndexRequest class). The API returns a special future, called GActionFuture. This is a groovier version of elasticsearch Java ActionFuture (in turn a nicer extension to Java own Future) which allows to register listeners (closures) on it for success and failures, as well as blocking for the response. For example:
def indexR = client.index {
index "test"
type "type1"
id "1"
source {
test = "value"
complex {
value1 = "value1"
value2 = "value2"
}
}
}
println "Indexed $indexR.response.id into $indexR.response.index/$indexR.response.type"
In the above example, calling indexR.response will simply block for the response. We can also block for the response for a specific timeout:
IndexResponse response = indexR.response "5s" // block for 5 seconds, same as:
response = indexR.response 5, TimeValue.SECONDS //
We can also register closures that will be called on success and on failure:
indexR.success = {IndexResponse response ->
pritnln "Indexed $response.id into $response.index/$response.type"
}
indexR.failure = {Throwable t ->
println "Failed to index: $t.message"
}
This option allows to pass the actual instance of the request (instead of a closure) as a parameter. The rest is similar to the closure as a parameter option (the GActionFuture handling). For example:
def indexR = client.index (new IndexRequest(
index: "test",
type: "type1",
id: "1",
source: {
test = "value"
complex {
value1 = "value1"
value2 = "value2"
}
}))
println "Indexed $indexR.response.id into $indexR.response.index/$indexR.response.type"
The last option is to provide an actual instance of the API request, and an ActionListener for the callback. This is exactly like the Java API with the added gexecute which returns the GActionFuture:
def indexR = node.client.prepareIndex("test", "type1", "1").setSource({
test = "value"
complex {
value1 = "value1"
value2 = "value2"
}
}).gexecute()
Obtaining an elasticsearch Groovy GClient (a GClient is a simple wrapper on top of the Java Client) is simple. The most common way to get a client is by starting an embedded Node which acts as a node within the cluster.
A Node based client is the simplest form to get a GClient to start executing operations against elasticsearch.
import org.elasticsearch.groovy.client.GClient
import org.elasticsearch.groovy.node.GNode
import static org.elasticsearch.groovy.node.GNodeBuilder.nodeBuilder
// on startup
GNode node = nodeBuilder().node();
GClient client = node.client();
// on shutdown
node.close();
Since elasticsearch allows to configure it using JSON based settings, the configuration itself can be done using a closure that represent the JSON:
import org.elasticsearch.groovy.node.GNode
import org.elasticsearch.groovy.node.GNodeBuilder
import static org.elasticsearch.groovy.node.GNodeBuilder.*
// on startup
GNodeBuilder nodeBuilder = nodeBuilder();
nodeBuilder.settings {
node {
client = true
}
cluster {
name = "test"
}
}
GNode node = nodeBuilder.node()
// on shutdown
node.stop().close()
The index API is very similar to the Java index API. The Groovy extension to it is the ability to provide the indexed source using a closure. For example:
def indexR = client.index {
index "test"
type "type1"
id "1"
source {
test = "value"
complex {
value1 = "value1"
value2 = "value2"
}
}
}
In the above example, the source closure itself gets transformed into an XContent (defaults to JSON). In order to change how the source closure is serialized, a global (static) setting can be set on the GClient by changing the indexContentType field.
Note also that the source can be set using the typical Java based APIs, the Closure option is a Groovy extension.
The get API is very similar to the Java get API. The main benefit of using groovy is handling the source content. It can be automatically converted to a Map which means using Groovy to navigate it is simple:
def getF = node.client.get {
index "test"
type "type1"
id "1"
}
println "Result of field2: $getF.response.source.complex.field2"
The delete API is very similar to the Java delete API, here is an example:
def deleteF = node.client.delete {
index "test"
type "type1"
id "1"
}
The search API is very similar to the Java search API. The Groovy extension allows to provide the search source to execute as a Closure including the query itself (similar to GORM criteria builder):
def search = node.client.search {
indices "test"
types "type1"
source {
query {
term(test: "value")
}
}
}
search.response.hits.each {SearchHit hit ->
println "Got hit $hit.id from $hit.index/$hit.type"
}
It can also be executed using the “Java API” while still using a closure for the query:
def search = node.client.prepareSearch("test").setQuery({
term(test: "value")
}).gexecute();
search.response.hits.each {SearchHit hit ->
println "Got hit $hit.id from $hit.index/$hit.type"
}
The format of the search Closure follows the same JSON syntax as the Search API request.
Term query where multiple values are provided (see terms):
def search = node.client.search {
indices "test"
types "type1"
source {
query {
terms(test: ["value1", "value2"])
}
}
}
Query string (see query string):
def search = node.client.search {
indices "test"
types "type1"
source {
query {
query_string(
fields: ["test"],
query: "value1 value2")
}
}
}
Pagination (see from/size):
def search = node.client.search {
indices "test"
types "type1"
source {
from = 0
size = 10
query {
term(test: "value")
}
}
}
Sorting (see sort):
def search = node.client.search {
indices "test"
types "type1"
source {
query {
term(test: "value")
}
sort = [
date : [ order: "desc"]
]
}
}
The count API is very similar to the Java count API. The Groovy extension allows to provide the query to execute as a Closure (similar to GORM criteria builder):
def count = client.count {
indices "test"
types "type1"
query {
term {
test = "value"
}
}
}
The query follows the same Query DSL.