Friday, March 25, 2016

Connecting to ElasticSearch

      Elasticsearch is a real-time distributed search and analytics engine. Elasticsearch, like most NoSQL databases, is document based storage in json format. An index is a flat collection of independent documents. An index really is a logical namespace pointing to one or more physical shards. Shards as containers for data, documents are stored and indexed in shards.

Elasticsearch supports two types of Java clients: Node Client and Transport Client. Transport client is typically used in java application and is considered to be efficient as it bypasses the process of marshalling & unmarhsalling of request to & from JSON which is typically done in most of the Rest based client.

Using TransportClient in your java application and connecting to elastic is incredibly simple, look at the following code to believe it.

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;

public class ElasticRepository {
 private static final String ELASTIC_URL = "localhost";
 private static final String ELASTIC_PORT = "9300";
 private static final String ELASTIC_CLUSTER = "localhost";
 private static final String ELASTIC_USERNAME = "username";
 private static final String ELASTIC_PASSWORD = "password";
 private final static String ELASTIC_INDEX = "indexName";
 private final static String ELASTIC_TYPE_NAME = "typeName";

 public static void main(String[] args) {

  Settings settings = ImmutableSettings.settingsBuilder()
    .put("cluster.name", ELASTIC_CLUSTER)
    .put("shield.user", ELASTIC_USERNAME + ":" + ELASTIC_PASSWORD)
    .build();

  TransportClient transportClient = new TransportClient(settings);
  // Your random record/index id
  String indexId = "123";
  String sourceData = "This is the data source to be persisted in elastic";
  try {
   TransportAddress transportAddress = new InetSocketTransportAddress(
     ELASTIC_URL, Integer.parseInt(ELASTIC_PORT));
   transportClient.addTransportAddress(transportAddress);

   transportClient
     .prepareIndex(ELASTIC_INDEX, ELASTIC_TYPE_NAME, indexId)
     .setSource(sourceData).execute().actionGet();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   transportClient.close();
  }
 }
}

Elastic Shield is an enterprise security tool to protect data in the elastic server. It provides role based protection to your data at the index level. You need to have an authorization in order to read or write to/from a specific index that is being protected through shield. Once elastic is protected by the shield the above code may not work and fail to connect. It would now require an authentication token in its request header.
Take a look at the code below,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import static org.elasticsearch.shield.authc.support.UsernamePasswordToken.basicAuthHeaderValue;

import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.shield.authc.support.SecuredString;

import org.elasticsearch.shield.authc.support.SecuredString;

public class ElasticRepository {
 private static final String ELASTIC_URL = "localhost";
 private static final String ELASTIC_PORT = "9300";
 private static final String ELASTIC_CLUSTER = "localhost";
 private static final String ELASTIC_USERNAME = "username";
 private static final String ELASTIC_PASSWORD = "password";
 private final static String ELASTIC_INDEX = "indexName";
 private final static String ELASTIC_TYPE_NAME = "typeName";

 public static void main(String[] args) {

  Settings settings = ImmutableSettings.settingsBuilder()
    .put("cluster.name", ELASTIC_CLUSTER)
    .put("shield.user", ELASTIC_USERNAME + ":" + ELASTIC_PASSWORD)
    .build();

  TransportClient transportClient = new TransportClient(settings);
  // Your random record/index id
  String indexId = "123";
  String sourceData = "This is the data source to be persisted in elastic";
  String token;
  try {
   token = basicAuthHeaderValue(ELASTIC_USERNAME,
     new SecuredString(ELASTIC_PASSWORD.toCharArray()));
   TransportAddress transportAddress = new InetSocketTransportAddress(
     ELASTIC_URL, Integer.parseInt(ELASTIC_PORT));
   transportClient.addTransportAddress(transportAddress);
   transportClient
     .prepareIndex(ELASTIC_INDEX, ELASTIC_TYPE_NAME, indexId)
     .putHeader("Authorization", token)
     .setSource(sourceData).execute().actionGet();
  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   transportClient.close();
  }
 }
}

You would require elasticsearch-shield-1.0.2.jar, commons-codec-1.10.jar in your classpath. Line #34 shows how to generate a token using Shield's UsernamePasswordToken class. Once you have the token generated, you will need to set it into TransportClient's header as shown in line #41. This way you could connect to elastic by authenticating shield. 

That's it, happy coding...!

Reference: