# Jest
Jest is a Java HTTP Rest client for [ElasticSearch](http://www.elasticsearch.org).
ElasticSearch is an Open Source (Apache 2), Distributed, RESTful, Search Engine built on top of Apache Lucene.
ElasticSearch already has a Java API which is also used by ElasticSearch internally, [but Jest fills a gap, it is the missing client for ElasticSearch Http Rest interface](#comparison-to-native-api).
>Read great [introduction](http://www.ibm.com/developerworks/java/library/j-javadev2-24/index.html?ca=drs-) to ElasticSearch and Jest from IBM Developer works.
Installation
------------
### Stable
Jest maven repository is hosted on [Sonatype](http://www.sonatype.org) which is then synced to [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.searchbox%22) with a slight delay.
To get the latest *stable* version without waiting for Maven Central sync add Sonatype repository definition to your root pom.xml
``` xml
<repositories>
.
.
<repository>
<id>sonatype</id>
<name>Sonatype Groups</name>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
.
.
</repositories>
```
Add Jest as a dependency to your project.
``` xml
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>5.3.3</version>
</dependency>
```
### Snapshot
Jest also publishes a snapshot version on [Sonatype Snapshot Repository](https://oss.sonatype.org/content/repositories/snapshots) after every push resulting in a successfull build.
To get the latest *snapshot* version add Sonatype Snapshot Repository definition to your root pom.xml
``` xml
<repositories>
.
.
<repository>
<id>snapshots-repo</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases><enabled>false</enabled></releases>
<snapshots><enabled>true</enabled></snapshots>
</repository>
.
.
</repositories>
```
Add Jest snapshot as a dependency to your project.
``` xml
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
<version>2.0.1-SNAPSHOT</version>
</dependency>
```
>Ensure to check [the Changelog](https://github.com/searchbox-io/Jest/wiki/Changelog).
Usage
------------
Start using Jest by simply creating a `JestClient` instance:
``` java
// Construct a new Jest client according to configuration via factory
JestClientFactory factory = new JestClientFactory();
factory.setHttpClientConfig(new HttpClientConfig
.Builder("http://localhost:9200")
.multiThreaded(true)
//Per default this implementation will create no more than 2 concurrent connections per given route
.defaultMaxTotalConnectionPerRoute(<YOUR_DESIRED_LEVEL_OF_CONCURRENCY_PER_ROUTE>)
// and no more 20 connections in total
.maxTotalConnection(<YOUR_DESIRED_LEVEL_OF_CONCURRENCY_TOTAL>)
.build());
JestClient client = factory.getObject();
```
> `JestClient` is designed to be singleton, don't construct it for each request!
### Creating an Index
To create an index just pass the associated `CreateIndex` action to the client:
``` java
client.execute(new CreateIndex.Builder("articles").build());
```
Index settings can also be passed during the creation by
* using a JSON formatted string:
``` java
String settings = "\"settings\" : {\n" +
" \"number_of_shards\" : 5,\n" +
" \"number_of_replicas\" : 1\n" +
" }\n";
client.execute(new CreateIndex.Builder("articles").settings(Settings.builder().loadFromSource(settings).build().getAsMap()).build());
```
* using the `SettingsBuilder` helper class from Elasticsearch:
``` java
import org.elasticsearch.common.settings.Settings;
.
.
Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put("number_of_shards",5);
settingsBuilder.put("number_of_replicas",1);
client.execute(new CreateIndex.Builder("articles").settings(settingsBuilder.build().getAsMap()).build());
```
>Add ElasticSearch dependency to use Settings api
### Creating an Index Mapping
An index mapping can be created via Jest with ease, just pass the mapping source as a JSON formatted string.
``` java
PutMapping putMapping = new PutMapping.Builder(
"my_index",
"my_type",
"{ \"my_type\" : { \"properties\" : { \"message\" : {\"type\" : \"string\", \"store\" : \"yes\"} } } }"
).build();
client.execute(putMapping);
```
The helper class `DocumentMapper.Builder` from Elasticsearch can also be used to create the mapping source.
``` java
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.index.mapper.object.RootObjectMapper;
.
.
RootObjectMapper.Builder rootObjectMapperBuilder = new RootObjectMapper.Builder("my_mapping_name").add(
new StringFieldMapper.Builder("message").store(true)
);
DocumentMapper documentMapper = new DocumentMapper.Builder("my_index", null, rootObjectMapperBuilder).build(null);
String expectedMappingSource = documentMapper.mappingSource().toString();
PutMapping putMapping = new PutMapping.Builder(
"my_index",
"my_type",
expectedMappingSource
).build();
client.execute(putMapping);
```
>Add ElasticSearch dependency to use DocumentMapper.Builder api
### Indexing Documents
ElasticSearch requires index data as JSON. There are several ways to create documents to index via Jest.
From now on, we will refer documents as source. Source objects can be String, Map or POJOs.
as JSON String;
``` java
String source = "{\"user\":\"kimchy\"}";
```
or creating JSON via ElasticSearch JSONBuilder;
``` java
String source = jsonBuilder()
.startObject()
.field("user", "kimchy")
.field("postDate", "date")
.field("message", "trying out Elastic Search")
.endObject().string();
```
as Map;
``` java
Map<String, String> source = new LinkedHashMap<String,String>();
source.put("user", "kimchy");
```
as POJO;
``` java
Article source = new Article();
source.setAuthor("John Ronald Reuel Tolkien");
source.setContent("The Lord of the Rings is an epic high fantasy novel");
```
An example of indexing given source to twitter index with type tweet;
``` java
Index index = new Index.Builder(source).index("twitter").type("tweet").build();
client.execute(index);
```
Index id can be typed explicitly;
``` java
Index index = new Index.Builder(source).index("twitter").type("tweet").id("1").build();
client.execute(index);
```
@JestId annotation can be used to mark a property of a bean as id;
```java
class Article {
@JestId
private String documentId;
}
```
Now whenever an instance of Article is indexed, index id will be value of documentId.
If @JestId value is null, it will be set the value of ElasticSearch generated "_id".
Jest also supports using JestId annotation on fields with type other than String but the
catch is then you will need to manually manage the document IDs.
```java
class NumericArticle {
@JestId
private Long documentId;
}
```
It should be noted that when a non-String type is used for the documentId, conversion
errors may occur unless you manually manage the documentId. For example if a NumericArticle
instance without a documentId is indexed then Elasticsearch will assign an automatically
generated id to that document but Jest will not be able to convert that id to Long since
all id fields are of type String in Elasticsearch and the auto generated id contains non
numeric characters.
So the non-String type support for JestId annotation is purely for ease of use and should
not be used if you plan to use the automatic id generation functionality of Elasticsearch.
#### Version field support (aka Optimistic Concurrency Control)
`_version` field for documents are supported via the @JestVersion annotation. Marking a
property of your bean with @JestVersion will cause that field to be serialized and deserialized
as `_version` in the document JSON communicated to Elasticsearch. This in turn lets