==========
Groovy API
==========

Preface
=======

This section describes the `Groovy <http://groovy.codehaus.org/>`__ API
elasticsearch provides. All elasticsearch APIs are executed using a
`GClient <#client>`__, 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 <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current>`__
exposing it in a groovier manner. The execution options for each API
follow a similar manner and covered in ?.

Maven Repository
----------------

The Groovy API is hosted on `Maven
Central <http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22elasticsearch-client-groovy%22>`__.

For example, you can define the latest version in your ``pom.xml`` file:

.. code:: xml

    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch-lang-groovy</artifactId>
        <version>${es.version}</version>
    </dependency>

API Anatomy
===========

Once a `GClient <#client>`__ has been obtained, all of Elasticsearch
APIs can be executed on it. Each Groovy API is exposed using three
different mechanisms.

Closure Request
---------------

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:

.. code:: js

    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:

.. code:: js

    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:

.. code:: js

    indexR.success = {IndexResponse response ->
        pritnln "Indexed $response.id into $response.index/$response.type"
    }
    indexR.failure = {Throwable t ->
        println "Failed to index: $t.message"
    }

Request
-------

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:

.. code:: js

    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"

Java Like
---------

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``:

.. code:: js

    def indexR = node.client.prepareIndex("test", "type1", "1").setSource({
        test = "value"
        complex {
            value1 = "value1"
            value2 = "value2"
        }
    }).gexecute()

Client
======

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.

Node Client
-----------

A Node based client is the simplest form to get a ``GClient`` to start
executing operations against elasticsearch.

.. code:: js

    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:

.. code:: js

    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()

Index API
=========

The index API is very similar to the `Java index
API <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/index_.html>`__.
The Groovy extension to it is the ability to provide the indexed source
using a closure. For example:

.. code:: js

    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.

Get API
=======

The get API is very similar to the `Java get
API <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/get.html>`__.
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:

.. code:: js

    def getF = node.client.get {
        index "test"
        type "type1"
        id "1"
    }

    println "Result of field2: $getF.response.source.complex.field2"

Delete API
==========

The delete API is very similar to the `Java delete
API <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/delete.html>`__,
here is an example:

.. code:: js

    def deleteF = node.client.delete {
        index "test"
        type "type1"
        id "1"
    }

Search API
==========

The search API is very similar to the `Java search
API <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/search.html>`__.
The Groovy extension allows to provide the search source to execute as a
``Closure`` including the query itself (similar to GORM criteria
builder):

.. code:: js

    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:

.. code:: js

    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 <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-search.html>`__
request.

More examples
-------------

Term query where multiple values are provided (see
`terms <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html>`__):

.. code:: js

    def search = node.client.search {
        indices "test"
        types "type1"
        source {
            query {
                terms(test: ["value1", "value2"])
            }
        }
    }

Query string (see `query
string <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html>`__):

.. code:: js

    def search = node.client.search {
        indices "test"
        types "type1"
        source {
            query {
                query_string(
                    fields: ["test"],
                    query: "value1 value2")
            }
        }
    }

Pagination (see
`from/size <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-from-size.html>`__):

.. code:: js

    def search = node.client.search {
        indices "test"
        types "type1"
        source {
            from = 0
            size = 10
            query {
                term(test: "value")
            }
        }
    }

Sorting (see
`sort <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html>`__):

.. code:: js

    def search = node.client.search {
        indices "test"
        types "type1"
        source {
            query {
                term(test: "value")
            }
            sort = [
                date : [ order: "desc"]
            ]
        }
    }

Count API
=========

The count API is very similar to the `Java count
API <http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/count.html>`__.
The Groovy extension allows to provide the query to execute as a
``Closure`` (similar to GORM criteria builder):

.. code:: js

    def count = client.count {
        indices "test"
        types "type1"
        query {
            term {
                test = "value"
            }
        }
    }

The query follows the same `Query
DSL <http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html>`__.
