Tech Topics

Making Elasticsearch Groovy-er

The Groovy community has been asking for us to ensure it’s an officially supported language once again, and we’ve been listening. With the recent release of Elasticsearch 1.4.1, we are also excited to announce the release of the official Elasticsearch Groovy client (1.4.1), which is fully compatible with Elasticsearch 1.4.1.

Starting today, the Groovy client becomes an officially supported client hosted on our elasticsearch-groovy GitHub repository. The old, long-defunct Groovy client has been completely rewritten for this release in order to guarantee 100% Java client compatiblity. Unlike before, any feature that exists in the Java client is now guaranteed to exist in the Groovy client.

New Features

  • 100% Compatibility with the Java client
  • Simplified Closure to Map conversion

The More You Know

The new and improved Groovy client does away with the old, Groovy-friendly variants of Java client objects in favor of using Groovy extension modules. Groovy extension modules provide the excellent ability to add new methods to existing classes and the Groovy client takes full advantage of them.

Thanks to the use of the extension modules, all Java client examples are 100% compatible with the Groovy client, which means that any Groovy project can transition to using the Groovy client where and when it is convenient without having to make hard decisions about features. Naturally, any new Groovy code can be written to take full advantage of the new client immediately.

What does 100% compatibility mean?

Having 100% compatibility means that you can and will use the same code as the Java client, often with added Groovy-isms as opposed to custom-written Groovy equivalents (ye olde GClient will be missed … but hopefully forgotten). From development of the Groovy client’s perspective, this means that there is less code to write and test, and superior usability. And, from your perspective, it hopefully means less new code to learn and no worrying about missing any functionality as future versions are released.

// No Groovy imports!
import org.elasticsearch.action.search.SearchResponse
import org.elasticsearch.client.Client
import static org.elasticsearch.node.NodeBuilder.nodeBuilder

// Create a client node using a mix of the Java NodeBuilder and Groovy extensions
Client client = nodeBuilder().client(true).settings {
  cluster {
    name = "my-cluster-name"
  }
  arbitrary {
    setting = "arbitraryValue"
  }
}.node().client

// Perform a search on your cluster using a Closure!
SearchResponse response = client.search {
  indices "index1", "index2"
  types "type1", "type2"
  source {
    query {
      match_all { }
    }
  }
}.actionGet()

Making Life Groovy-er

As with earlier incarnations of the Groovy client, support for treating a Groovy Closure as data — instead of just as a block of code — is a core concept.

This allows you to do things that are sometimes verbose when using the Java client by using a Groovy Closure.

In your Java code, you might see something akin to:

import static org.elasticsearch.common.xcontent.XContentFactory.*;

XContentBuilder builder = jsonBuilder()
    .startObject()
      .field("user", "kimchy")
      .field("postDate", new Date())
      .field("message", "trying out Elasticsearch")
    .endObject()
    
String json = builder.string()

However, if you start to use the Groovy client, then you could replace this with an equivalent Closure:

String json = {
  user = "kimchy"
  postDate = new Date()
  message = "trying out Elasticsearch"
}.asJsonString()

No code import. Just Groovy magic! And thanks to this feature, the Groovy client makes full use of passing a Closure into your Elasticsearch Client requests as well:

import org.elasticsearch.action.ListenableActionFuture

def username = "kimchy"

ListenableActionFuture<IndexResponse> responseFuture = client.index {
  index "my-index"
  type "my-type"
  id "my-id"
  source {
    user = username
    postDate = new Date()
    message = "Trying out Elasticsearch Groovy"
    nested {
      nested_object {
        some_int = 123
        some_double = 4.56
        some_object_list = [{
            key = "Closures"
          }, {
            key = "Beats"
          }, {
            key = "Bears"
        }]
      }
      favorites = Integer.MAX_VALUE
    }
  }
}

This enables very powerful flows for submitting requests to your Elasticsearch cluster(s) by allowing you to use a Closure instead of a Map or String to pass around request bodies because the full flexibility of each Closure is expanded to be handled as data. It creates some of the easiest to read and reuse conversion code around (and no one’s ever going to keep it down).

Finding Closure

Most of the flexibility added by the Groovy client comes from extension methods applied to the Closure class itself and the internal usages of it. Other than the convenient-for-debugging closure.asJsonString(), you can easily convert your Closure into a Map<String, Object> using closure.asMap() (this kind of thing is done for you in the Groovy client’s methods that accept a Closure):

Map<String, Object> map = {
  user = "kimchy"
  postDate = new Date()
  nested {
    value = 1.23
  }
}.asMap()

Feedback

The release of the Groovy client was because of user comments and requests. If you have a future feature request or find a bug, please let us know by opening an issue on GitHub or if you just want to leave us some good ol’ fashion, 140-character feedback, find us on Twitter (@elasticsearch)!