Monday 23 November 2015

Elasticsearch: Java: Update API

There are two ways you can update a document using update API.
a.   By creating UpdateRequest.
b.   By using prepareUpdate method.
By creating UpdateRequest.
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.index("organization");
updateRequest.type("employee");
updateRequest.id("1");
updateRequest.doc(jsonBuilder()
        .startObject()
            .field("gender", "male")
        .endObject());
client.update(updateRequest).get();


By using prepareUpdate method.
client.prepareUpdate("organization", "employee", "1")
        .setDoc(jsonBuilder()               
            .startObject()
                .field("gender", "male")
            .endObject())
        .get();


Following application explains step-by-step, how to update a document.

Step 1: Define model class Employee.

package com.self_learn.model;

import java.util.ArrayList;
import java.util.List;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@EqualsAndHashCode()
@ToString
public class Employee {
 @Getter @Setter private String age;
 @Getter @Setter private String firstName;
 @Getter @Setter private String lastName;
 @Getter @Setter private List<String> hobbies = new ArrayList<>();
}

Step 2: Define TransportClientUtil, IPUtil classes.

package com.self_learn.util;

import static com.self_learn.util.IPUtil.isValidHosts;
import static com.self_learn.util.IPUtil.isValidPorts;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.elasticsearch.client.Client;
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 com.google.common.base.Preconditions;

public class TransportClientUtil {
 private static Map<Map<String, Integer>, Client> localMap = new HashMap<>();

 /**
  * Take machine name and port addresses as map and return transport client.
  * Key is host name, value is port number
  * 
  * @throws UnknownHostException
  */
 public static Client getTransportClient(String clusterName,
   Map<String, Integer> map) throws UnknownHostException {

  Preconditions.checkNotNull(clusterName,
    "clusterName shouldn't be empty");
  Preconditions.checkNotNull(map, "Map shouldn't be empty");

  if (localMap.containsKey(map))
   return localMap.get(map);

  Preconditions.checkState(isValidHostPorts(map),
    "Map contains invalid host (or) port");

  Settings settings = ImmutableSettings.settingsBuilder()
    .put("cluster.name", clusterName)
    .put("client.transport.sniff", true).build();

  TransportClient client = new TransportClient(settings);

  InetSocketTransportAddress addresses[] = getInetSocketTransportAddresses(map);
  client.addTransportAddresses(addresses);
  localMap.put(map, client);
  return client;
 }

 /**
  * @param map
  * @return true, if all the entries in map are valid host, ports. Else
  *         false.
  */
 private static boolean isValidHostPorts(Map<String, Integer> map) {
  Set<String> hostNames = map.keySet();
  Set<Integer> ports = new HashSet<>(map.values());

  if (!isValidHosts(hostNames.toArray(new String[hostNames.size()])))
   return false;

  if (!isValidPorts(ports.toArray(new Integer[ports.size()])))
   return false;

  return true;
 }

 private static InetSocketTransportAddress[] getInetSocketTransportAddresses(
   Map<String, Integer> map) throws UnknownHostException {
  InetSocketTransportAddress addresses[] = new InetSocketTransportAddress[map
    .size()];
  int count = 0;

  Set<String> keys = map.keySet();
  for (String key : keys) {
   InetAddress addr = InetAddress.getByName(key);
   InetSocketTransportAddress address = new InetSocketTransportAddress(
     addr, map.get(key));
   addresses[count] = address;
  }

  return addresses;
 }

 /**
  * Get transport client for localhost.
  * 
  * @param clusterName
  * @param port
  * @return
  * @throws UnknownHostException
  */
 public static Client getLocalTransportClient(String clusterName, int port)
   throws UnknownHostException {
  Settings settings = ImmutableSettings.settingsBuilder()
    .put("cluster.name", clusterName)
    .put("client.transport.sniff", true).build();

  TransportClient client = new TransportClient(settings);
  InetAddress addr = InetAddress.getByName("127.0.0.1");
  InetSocketTransportAddress address = new InetSocketTransportAddress(
    addr, port);

  client.addTransportAddress(address);
  return client;
 }

}


package com.self_learn.util;

import org.apache.commons.validator.routines.InetAddressValidator;

import com.google.common.base.Preconditions;

/**
 * Validate IPaddresses, ports
 * 
 * @author harikrishna_gurram
 */
public class IPUtil {
 private static InetAddressValidator inetAddressValidator = InetAddressValidator
   .getInstance();

 /**
  * @param ipAddress
  * @return true if ip address is valid, else false
  */
 public static boolean isValidIPAddress(String ipAddress) {
  Preconditions.checkNotNull(ipAddress, "IP address should not be null");
  return inetAddressValidator.isValid(ipAddress);
 }

 /**
  * @param port
  *            : Port number
  * @return true if port number is valid, else false
  */
 public static boolean isValidPort(int port) {
  if (port > 0 && port < 65536)
   return true;
  return false;
 }

 /**
  * @param hostNames
  * @return true if all the elements of array represents valid hosnames, else
  *         false.
  */
 public static boolean isValidHosts(String[] hostNames) {
  Preconditions.checkNotNull(hostNames, "Host names shouldn't be empty");
  for (String hostName : hostNames) {
   if (!isValidIPAddress(hostName)) {
    return false;
   }
  }
  return true;
 }

 /**
  * 
  * @param ports
  * @return true if all the elements of array represents valid ports, else
  *         false.
  */
 public static boolean isValidPorts(Integer[] ports) {
  Preconditions.checkNotNull(ports, "ports shouldn't be empty");
  for (int port : ports) {
   if (!isValidPort(port)) {
    return false;
   }
  }
  return true;
 }

}


Step 3: Define JSONUtil.

package com.self_learn.util;

import org.elasticsearch.common.base.Preconditions;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 * Convert object to json string.
 * 
 * @author harikrishna_gurram
 */
public class JSONUtil {
 private static Gson gson = new Gson();
 private static Gson prettyGson = new GsonBuilder().setPrettyPrinting()
   .create();

 /**
  * @param obj
  * @return json string of this object.
  */
 public static String getJson(Object obj) {
  Preconditions.checkNotNull(obj, "obj shouldn't be null");
  return gson.toJson(obj);
 }

 /**
  * @param obj
  * @return json string of this object (Pretty json).
  */
 public static String getPrettyJson(Object obj) {
  Preconditions.checkNotNull(obj, "obj shouldn't be null");
  return prettyGson.toJson(obj);
 }

 /**
  * Convert given json string to object.
  * 
  * @param json
  * @param obj
  * @return an object by populating properties with json data.
  */
 public static <T> T getObject(String json, Class<T> clazz) {
  Preconditions.checkNotNull(json, "json data shouldn't be null");
  Preconditions.checkNotNull(clazz, "clazz shouldn't be null");
  return gson.fromJson(json, clazz);
 }
}

Step 4: Define IndexUtil, to insert document into an index.

package com.self_learn.util;

import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;

import com.google.common.base.Preconditions;

/**
 * Provides utility methods to store data into Elasticsearch.
 * 
 * @author harikrishna_gurram
 */
public class IndexUtil {

 /**
  * Index given document.
  * 
  * @param client
  *            : Client used to index data
  * @param _index
  *            : Document is stored in this index
  * @param _type
  *            : Document stored in this type
  * @param _id
  *            : Specifies _id of the document
  * @param document
  *            : Represents body of the document
  * @return {@link IndexResponse}
  */
 public static IndexResponse indexData(Client client, String _index,
   String _type, String _id, String document) {
  Preconditions.checkNotNull(client, "client should not be null");
  Preconditions.checkNotNull(_index, "_index should not be null");
  Preconditions.checkNotNull(_type, "_type should not be null");
  Preconditions.checkNotNull(_id, "_id should not be null");
  Preconditions.checkNotNull(document, "data should not be null");

  IndexResponse response = client.prepareIndex(_index, _type, _id)
    .setSource(document).execute().actionGet();
  return response;
 }

 /**
  * Index given object.
  * 
  * @param client
  *            : Client used to index data
  * @param _index
  *            : Document is stored in this index
  * @param _type
  *            : Document stored in this type
  * @param _id
  *            : Specifies _id of the document
  * @param obj
  *            : Object to index
  * @return {@link IndexResponse}
  */
 public static IndexResponse indexData(Client client, String _index,
   String _type, String _id, Object obj) {
  Preconditions.checkNotNull(obj, "data should not be null");
  return indexData(client, _index, _type, _id, JSONUtil.getJson(obj));
 }

}

Step 5: Define SearchUtil, to query Elasticsearch.

package com.self_learn.util;

import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.client.Client;

import com.google.common.base.Preconditions;

/**
 * Provide various utility methods to query Elasticsearch.
 * 
 * @author harikrishna_gurram
 */
public class SearchUtil {

 /**
  * Returns the document by id (Takes _index, _type, _id as input).
  * 
  * @param client
  * @param _index
  * @param _type
  * @param _id
  * @return the document by id
  */
 public static GetResponse getDocumentById(Client client, String _index,
   String _type, String _id) {
  Preconditions.checkNotNull(client, "client should not be null");
  Preconditions.checkNotNull(_index, "_index should not be null");
  Preconditions.checkNotNull(_type, "_type should not be null");
  Preconditions.checkNotNull(_id, "_id should not be null");

  GetResponse response = client.prepareGet(_index, _type, _id).execute()
    .actionGet();
  return response;
 }

}

Step 6: Define DeleteUtil, to delete a document from Elasticsearch.

package com.self_learn.util;

import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.client.Client;

import com.google.common.base.Preconditions;

/**
 * Provide utility methods to delete document from Elasticsearch.
 * 
 * @author harikrishna_gurram
 */
public class DeleteUtil {

 /**
  * Removes the docuemnt and return DeleteResponse.
  * @param client
  * @param _index
  * @param _type
  * @param _id
  * @return DeleteResponse
  */
 public static DeleteResponse deleteDocument(Client client, String _index,
   String _type, String _id) {
  Preconditions.checkNotNull(client, "client should not be null");
  Preconditions.checkNotNull(_index, "_index should not be null");
  Preconditions.checkNotNull(_type, "_type should not be null");
  Preconditions.checkNotNull(_id, "_id should not be null");

  DeleteResponse response = client.prepareDelete(_index, _type, _id)
    .execute().actionGet();
  return response;
 }
}

Step 7: Define UpdateUtil, to update a document.

package com.self_learn.util;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.xcontent.XContentBuilder;

import com.google.common.base.Preconditions;

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

/**
 * Provides various utility methods to update a document.
 * 
 * @author harikrishna_gurram
 */
public class UpdateUtil {

 /**
  * Updates document with given fields (Fields are given as map)
  * 
  * @param client
  * @param _index
  * @param _type
  * @param _id
  * @param map
  * @return {@link UpdateResponse}
  * @throws IOException
  * @throws InterruptedException
  * @throws ExecutionException
  */
 public static UpdateResponse updateDocument(Client client, String _index,
   String _type, String _id, Map<String, Object> map)
   throws IOException, InterruptedException, ExecutionException {
  Preconditions.checkNotNull(client, "client should not be null");
  Preconditions.checkNotNull(_index, "_index should not be null");
  Preconditions.checkNotNull(_type, "_type should not be null");
  Preconditions.checkNotNull(_id, "_id should not be null");
  Preconditions.checkNotNull(map, "map should not be null");

  Set<String> keys = map.keySet();

  XContentBuilder builder = jsonBuilder().startObject();
  for (String key : keys) {
   builder.field(key, map.get(key));
  }
  builder.endObject();

  UpdateRequest updateRequest = new UpdateRequest();
  updateRequest.index(_index);
  updateRequest.type(_type);
  updateRequest.id(_id);
  updateRequest.doc(builder);

  UpdateResponse resposne = client.update(updateRequest).get();
  return resposne;
 }
}

Step 8: Define ResponseUtil, to get response in string format.

package com.self_learn.util;

import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateResponse;

import com.google.common.base.Preconditions;

/**
 * Utility class to return response in string format.
 * 
 * @author harikrishna_gurram
 */
public class ResponseUtil {

 /**
  * @param response
  * @return string representation of {@link IndexResponse}
  */
 public static String getResponseInfo(IndexResponse response) {
  Preconditions.checkNotNull(response, "response shouldn't be null");
  String _index = response.getIndex();
  String _type = response.getType();
  String _id = response.getId();
  long _version = response.getVersion();
  boolean created = response.isCreated();

  StringBuilder builder = new StringBuilder();
  return builder.append("_index: ").append(_index).append("\n")
    .append("_type: ").append(_type).append("\n").append("_id: ")
    .append(_id).append("\n").append("_version: ").append(_version)
    .append("\n").append("created: ").append(created).toString();
 }

 /**
  * @param response
  * @return string representation of {@link GetResponse}
  */
 public static String getResponseInfo(GetResponse response) {
  Preconditions.checkNotNull(response, "response should not be null");

  String _index = response.getIndex();
  String _type = response.getType();
  String _id = response.getId();
  long _version = response.getVersion();
  String source = response.getSourceAsString();

  StringBuilder builder = new StringBuilder();
  return builder.append("_index: ").append(_index).append("\n")
    .append("_type: ").append(_type).append("\n").append("_id: ")
    .append(_id).append("\n").append("_version: ").append(_version)
    .append("\n").append("_source: ").append(source).toString();
 }

 /**
  * Returns source of the result as string
  * 
  * @param response
  * @return
  */
 public static String getSource(GetResponse response) {
  Preconditions.checkNotNull(response, "response shouldn't be null");
  return response.getSourceAsString();
 }

 /**
  * @param response
  * @return string representation of {@link DeleteResponse}
  */
 public static String getResponseInfo(DeleteResponse response) {
  Preconditions.checkNotNull(response, "response shouldn't be null");
  String _index = response.getIndex();
  String _type = response.getType();
  String _id = response.getId();
  long _version = response.getVersion();
  boolean found = response.isFound();

  StringBuilder builder = new StringBuilder();
  return builder.append("_index: ").append(_index).append("\n")
    .append("_type: ").append(_type).append("\n").append("_id: ")
    .append(_id).append("\n").append("_version: ").append(_version)
    .append("\n").append("found: ").append(found).toString();
 }

 /**
  * @param response
  * @return string representation of {@link UpdateResponse}
  */
 public static String getResponseInfo(UpdateResponse response) {
  Preconditions.checkNotNull(response, "response shouldn't be null");
  String _index = response.getIndex();
  String _type = response.getType();
  String _id = response.getId();
  long _version = response.getVersion();
  boolean created = response.isCreated();

  StringBuilder builder = new StringBuilder();
  return builder.append("_index: ").append(_index).append("\n")
    .append("_type: ").append(_type).append("\n").append("_id: ")
    .append(_id).append("\n").append("_version: ").append(_version)
    .append("\n").append("created: ").append(created).toString();
 }
}

Step 9: Define Main.java, to work with complete application.

package com.self_learn.test;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Client;

import com.self_learn.model.Employee;
import com.self_learn.util.IndexUtil;
import com.self_learn.util.ResponseUtil;
import com.self_learn.util.SearchUtil;
import com.self_learn.util.TransportClientUtil;
import com.self_learn.util.UpdateUtil;

public class Main {
 private static String clusterName = "my_cluster_1";
 private static String _index = "organization";
 private static String _type = "employee";

 private static void printStars() {
  System.out.println("*************************************************");
 }

 public static void main(String args[]) throws IOException,
   InterruptedException, ExecutionException {
  /* Get client instance for cluster */
  Client client = TransportClientUtil.getLocalTransportClient(
    clusterName, 9300);

  /* Prepare model object */
  Employee emp = new Employee();
  emp.setAge("27");
  emp.setFirstName("PTR");
  emp.setLastName("Nayan");
  emp.getHobbies().add("Tattoos");
  emp.getHobbies().add("People Watching");
  emp.getHobbies().add("Dagger Collecting");
  emp.getHobbies().add("Confusing People");

  /* Write object into Elasticsearch */
  System.out.println("Writing " + emp + " to Elasticsearch");
  IndexUtil.indexData(client, _index, _type, "1", emp);

  /* Query for the object with id 1 */
  System.out.println("Reading data from Elasticsearch");
  GetResponse response = SearchUtil.getDocumentById(client, _index,
    _type, "1");
  System.out.println(ResponseUtil.getResponseInfo(response));
  printStars();

  Map<String, Object> map = new HashMap<>();
  map.put("firstName", "Krishna");
  map.put("hobbies", Arrays.asList("Playing Cricket", "Watching movies"));

  /* Update document */
  UpdateResponse updateResponse = UpdateUtil.updateDocument(client,
    _index, _type, "1", map);
  System.out.println(ResponseUtil.getResponseInfo(updateResponse));
  printStars();

  /* Query for the object with id 1 */
  System.out.println("Reading data from Elasticsearch");
  response = SearchUtil.getDocumentById(client, _index, _type, "1");
  System.out.println(ResponseUtil.getResponseInfo(response));

  client.close();
 }
}

Run Main.java, you will get following kind of output.

Sep 09, 2015 4:16:51 PM org.elasticsearch.plugins.PluginsService <init>
INFO: [Tower] loaded [], sites []
Writing Employee(age=27, firstName=PTR, lastName=Nayan, hobbies=[Tattoos, People Watching, Dagger Collecting, Confusing People]) to Elasticsearch
Reading data from Elasticsearch
_index: organization
_type: employee
_id: 1
_version: 3
_source: {"age":"27","firstName":"PTR","lastName":"Nayan","hobbies":["Tattoos","People Watching","Dagger Collecting","Confusing People"]}
*************************************************
_index: organization
_type: employee
_id: 1
_version: 4
created: false
*************************************************
Reading data from Elasticsearch
_index: organization
_type: employee
_id: 1
_version: 4
_source: {"age":"27","firstName":"Krishna","lastName":"Nayan","hobbies":["Playing Cricket","Watching movies"]}





Prevoius                                                 Next                                                 Home

No comments:

Post a Comment