add endpoint to query suggestion via ES
[aai/search-data-service.git] / src / main / java / org / onap / aai / sa / searchdbabstraction / elasticsearch / dao / ElasticSearchHttpController.java
index ef141ec..00f66e0 100644 (file)
@@ -46,6 +46,8 @@ import org.onap.aai.sa.searchdbabstraction.entity.OperationResult;
 import org.onap.aai.sa.searchdbabstraction.entity.SearchHit;
 import org.onap.aai.sa.searchdbabstraction.entity.SearchHits;
 import org.onap.aai.sa.searchdbabstraction.entity.SearchOperationResult;
+import org.onap.aai.sa.searchdbabstraction.entity.SuggestHit;
+import org.onap.aai.sa.searchdbabstraction.entity.SuggestHits;
 import org.onap.aai.sa.searchdbabstraction.logging.SearchDbMsgs;
 import org.onap.aai.sa.searchdbabstraction.util.AggregationParsingUtil;
 import org.onap.aai.sa.searchdbabstraction.util.DocumentSchemaUtil;
@@ -79,10 +81,9 @@ import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 import javax.ws.rs.core.Response.Status;
 
-
 /**
- * This class has the Elasticsearch implementation of the
- * DB operations defined in DocumentStoreInterface.
+ * This class has the Elasticsearch implementation of the DB operations defined in
+ * DocumentStoreInterface.
  */
 public class ElasticSearchHttpController implements DocumentStoreInterface {
 
@@ -97,10 +98,10 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
   private static final String INTERNAL_SERVER_ERROR_ELASTIC_SEARCH_OPERATION_FAULT =
       "Internal Error: ElasticSearch operation fault occurred";
-  private static final Logger logger = LoggerFactory.getInstance()
-      .getLogger(ElasticSearchHttpController.class.getName());
-  private static final Logger metricsLogger = LoggerFactory.getInstance()
-      .getMetricsLogger(ElasticSearchHttpController.class.getName());
+  private static final Logger logger =
+      LoggerFactory.getInstance().getLogger(ElasticSearchHttpController.class.getName());
+  private static final Logger metricsLogger =
+      LoggerFactory.getInstance().getMetricsLogger(ElasticSearchHttpController.class.getName());
   private final ElasticSearchConfig config;
 
   private static final String DEFAULT_TYPE = "default";
@@ -121,8 +122,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
           properties.load(new FileInputStream(file));
         } catch (Exception e) {
           logger.error(SearchDbMsgs.EXCEPTION_DURING_METHOD_CALL,
-            "ElasticSearchHTTPController.getInstance",
-            e.getLocalizedMessage());
+              "ElasticSearchHTTPController.getInstance", e.getLocalizedMessage());
         }
 
         ElasticSearchConfig config = new ElasticSearchConfig(properties);
@@ -142,12 +142,11 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       checkConnection();
       logger.info(SearchDbMsgs.ELASTIC_SEARCH_CONNECTION_SUCCESS, getFullUrl("", false));
     } catch (Exception e) {
-      logger.error(SearchDbMsgs.ELASTIC_SEARCH_CONNECTION_FAILURE, null, e,
-          getFullUrl("", false), e.getMessage());
+      logger.error(SearchDbMsgs.ELASTIC_SEARCH_CONNECTION_FAILURE, null, e, getFullUrl("", false),
+          e.getMessage());
     }
   }
 
-
   public AnalysisConfiguration getAnalysisConfig() {
     return analysisConfig;
   }
@@ -162,9 +161,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
       // Submit the request to ElasticSearch to create the index using a
       // default document type.
-      result = createTable(index,
-          DEFAULT_TYPE,
-          analysisConfig.getEsIndexSettings(),
+      result = createTable(index, DEFAULT_TYPE, analysisConfig.getEsIndexSettings(),
           DocumentSchemaUtil.generateDocumentMappings(documentSchema));
 
       // ElasticSearch will return us a 200 code on success when we
@@ -172,7 +169,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       result.setResultCode((result.getResultCode() == 200) ? 201 : result.getResultCode());
       if (isSuccess(result)) {
         result.setResult("{\"url\": \"" + ApiUtils.buildIndexUri(index) + "\"}");
-        //result.setResult("{\"index\": \"" + index + ", \"type\": \"" + DEFAULT_TYPE + "\"}");
+        // result.setResult("{\"index\": \"" + index + ", \"type\": \""
+        // + DEFAULT_TYPE + "\"}");
       }
 
     } catch (DocumentStoreOperationException e) {
@@ -187,10 +185,10 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   public OperationResult createDynamicIndex(String index, String dynamicSchema) {
     OperationResult result = new OperationResult();
     result.setResultCode(500);
-    
+
     try {
       result = createTable(index, dynamicSchema);
-      
+
       // ElasticSearch will return us a 200 code on success when we
       // want to report a 201, so translate the result here.
       result.setResultCode((result.getResultCode() == 200) ? 201 : result.getResultCode());
@@ -200,14 +198,14 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     } catch (DocumentStoreOperationException e) {
       result.setFailureCause("Document store operation failure.  Cause: " + e.getMessage());
     }
-    
+
     return result;
   }
 
   @Override
   public OperationResult deleteIndex(String indexName) throws DocumentStoreOperationException {
 
-    //Initialize operation result with a failure codes / fault string
+    // Initialize operation result with a failure codes / fault string
     OperationResult opResult = new OperationResult();
     opResult.setResultCode(500);
     opResult.setResult(INTERNAL_SERVER_ERROR_ELASTIC_SEARCH_OPERATION_FAULT);
@@ -231,18 +229,15 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.DELETE_INDEX_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName);
+        override, indexName);
 
     shutdownConnection(conn);
 
     return opResult;
   }
 
-
   private OperationResult checkConnection() throws Exception {
 
     String fullUrl = getFullUrl("/_cluster/health", false);
@@ -288,7 +283,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     try {
       inputstream = connection.getInputStream();
     } catch (IOException e) {
-      logger.debug(SearchDbMsgs.EXCEPTION_DURING_METHOD_CALL, "shutdownConnection", e.getLocalizedMessage());
+      logger.debug(SearchDbMsgs.EXCEPTION_DURING_METHOD_CALL, "shutdownConnection",
+          e.getLocalizedMessage());
     } finally {
       if (inputstream != null) {
         try {
@@ -303,7 +299,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     try {
       outputstream = connection.getOutputStream();
     } catch (IOException e) {
-      logger.debug(SearchDbMsgs.EXCEPTION_DURING_METHOD_CALL, "shutdownConnection", e.getLocalizedMessage());
+      logger.debug(SearchDbMsgs.EXCEPTION_DURING_METHOD_CALL, "shutdownConnection",
+          e.getLocalizedMessage());
     } finally {
       if (outputstream != null) {
         try {
@@ -318,10 +315,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     connection.disconnect();
   }
 
-  //@Override
-  protected OperationResult createTable(String indexName, String typeName,
-                                        String indexSettings, String indexMappings)
-      throws DocumentStoreOperationException {
+  // @Override
+  protected OperationResult createTable(String indexName, String typeName, String indexSettings,
+      String indexMappings) throws DocumentStoreOperationException {
 
     if (indexSettings == null) {
       logger.debug("No settings provided.");
@@ -371,32 +367,31 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.CREATE_INDEX_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResultCode()),
-        override,
-        indexName);
+        override, indexName);
 
     return opResult;
   }
 
-    /**
-   * Will send the passed in JSON payload to Elasticsearch using the 
-   * provided index name in an attempt to create the index.
+  /**
+   * Will send the passed in JSON payload to Elasticsearch using the provided index name in an
+   * attempt to create the index.
    * 
    * @param indexName - The name of the index to be created
    * @param settingsAndMappings - The actual JSON object that will define the index
    * @return - The operation result of writing into Elasticsearch
    * @throws DocumentStoreOperationException
    */
-  protected OperationResult createTable(String indexName, String settingsAndMappings) throws DocumentStoreOperationException {
+  protected OperationResult createTable(String indexName, String settingsAndMappings)
+      throws DocumentStoreOperationException {
     OperationResult result = new OperationResult();
     result.setResultCode(500);
     result.setResult(INTERNAL_SERVER_ERROR_ELASTIC_SEARCH_OPERATION_FAULT);
-    
+
     // Grab the current time so we can use it to generate a metrics log.
     MdcOverride override = getStartTime(new MdcOverride());
-    
+
     String fullUrl = getFullUrl("/" + indexName + "/", false);
     HttpURLConnection conn = initializeConnection(fullUrl);
 
@@ -406,36 +401,38 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       shutdownConnection(conn);
       throw new DocumentStoreOperationException("Failed to set HTTP request method to PUT.", e);
     }
-    
+
     attachContent(conn, settingsAndMappings);
     handleResponse(conn, result);
-    
+
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.CREATE_INDEX_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, result.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, result.getResultCode()),
-        override,
-        indexName);
-    
+        override, indexName);
+
+    shutdownConnection(conn);
+
     return result;
   }
 
   @Override
-  public DocumentOperationResult createDocument(String                  indexName, 
-                                                DocumentStoreDataEntity document,
-                                                boolean                 allowImplicitIndexCreation)
-      throws DocumentStoreOperationException {
-    
-    if(!allowImplicitIndexCreation) {
-      
-      // Before we do anything, make sure that the specified index actually exists in the
-      // document store - we don't want to rely on ElasticSearch to fail the document
-      // create because it could be configured to implicitly create a non-existent index,
-      // which can lead to hard-to-debug behaviour with queries down the road.
+  public DocumentOperationResult createDocument(String indexName, DocumentStoreDataEntity document,
+      boolean allowImplicitIndexCreation) throws DocumentStoreOperationException {
+
+    if (!allowImplicitIndexCreation) {
+
+      // Before we do anything, make sure that the specified index
+      // actually exists in the
+      // document store - we don't want to rely on ElasticSearch to fail
+      // the document
+      // create because it could be configured to implicitly create a
+      // non-existent index,
+      // which can lead to hard-to-debug behaviour with queries down the
+      // road.
       OperationResult indexExistsResult = checkIndexExistence(indexName);
       if ((indexExistsResult.getResultCode() < 200) || (indexExistsResult.getResultCode() >= 300)) {
-  
+
         DocumentOperationResult opResult = new DocumentOperationResult();
         opResult.setResultCode(Status.NOT_FOUND.getStatusCode());
         opResult.setResult("Document Index '" + indexName + "' does not exist.");
@@ -443,7 +440,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         return opResult;
       }
     }
-    
+
     if (document.getId() == null || document.getId().isEmpty()) {
       return createDocumentWithoutId(indexName, document);
     } else {
@@ -452,17 +449,16 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   private DocumentOperationResult createDocumentWithId(String indexName,
-                                                       DocumentStoreDataEntity document)
-      throws DocumentStoreOperationException {
+      DocumentStoreDataEntity document) throws DocumentStoreOperationException {
     // check if the document already exists
     DocumentOperationResult opResult = checkDocumentExistence(indexName, document.getId());
 
-
     if (opResult.getResultCode() != Status.NOT_FOUND.getStatusCode()) {
       if (opResult.getResultCode() == Status.OK.getStatusCode()) {
         opResult.setFailureCause("A document with the same id already exists.");
       } else {
-        opResult.setFailureCause("Failed to verify a document with the specified id does not already exist.");
+        opResult.setFailureCause(
+            "Failed to verify a document with the specified id does not already exist.");
       }
       opResult.setResultCode(Status.CONFLICT.getStatusCode());
       return opResult;
@@ -476,8 +472,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     // Grab the current time so we can use it to generate a metrics log.
     MdcOverride override = getStartTime(new MdcOverride());
 
-    String fullUrl = getFullUrl("/" + indexName + "/" + DEFAULT_TYPE
-        + "/" + document.getId(), false);
+    String fullUrl =
+        getFullUrl("/" + indexName + "/" + DEFAULT_TYPE + "/" + document.getId(), false);
     HttpURLConnection conn = initializeConnection(fullUrl);
 
     try {
@@ -496,11 +492,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.CREATE_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName);
+        override, indexName);
 
     shutdownConnection(conn);
 
@@ -509,8 +503,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   private DocumentOperationResult createDocumentWithoutId(String indexName,
-                                                          DocumentStoreDataEntity document)
-      throws DocumentStoreOperationException {
+      DocumentStoreDataEntity document) throws DocumentStoreOperationException {
 
     DocumentOperationResult response = new DocumentOperationResult();
     // Initialize operation result with a failure codes / fault string
@@ -539,11 +532,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.CREATE_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, response.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, response.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, response.getResult()),
-        override,
-        indexName);
+        override, indexName);
 
     shutdownConnection(conn);
 
@@ -558,8 +549,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     attachContent(conn, doc.getContentInJson());
   }
 
-  private DocumentOperationResult checkDocumentExistence(String indexName,
-                                                         String docId)
+  private DocumentOperationResult checkDocumentExistence(String indexName, String docId)
       throws DocumentStoreOperationException {
     DocumentOperationResult opResult = new DocumentOperationResult();
 
@@ -586,7 +576,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       resultCode = conn.getResponseCode();
     } catch (IOException e) {
       shutdownConnection(conn);
-      throw new DocumentStoreOperationException("Failed to get the response code from the connection.", e);
+      throw new DocumentStoreOperationException(
+          "Failed to get the response code from the connection.", e);
     }
 
     logger.debug("Response Code : " + resultCode);
@@ -595,12 +586,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.GET_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName,
-        docId);
+        override, indexName, docId);
 
     shutdownConnection(conn);
 
@@ -608,20 +596,22 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   @Override
-  public DocumentOperationResult updateDocument(String                  indexName, 
-                                                DocumentStoreDataEntity document,
-                                                boolean                 allowImplicitIndexCreation)
-      throws DocumentStoreOperationException {
-    
-    if(!allowImplicitIndexCreation) {
-      
-      // Before we do anything, make sure that the specified index actually exists in the
-      // document store - we don't want to rely on ElasticSearch to fail the document
-      // create because it could be configured to implicitly create a non-existent index,
-      // which can lead to hard-to-debug behaviour with queries down the road.
+  public DocumentOperationResult updateDocument(String indexName, DocumentStoreDataEntity document,
+      boolean allowImplicitIndexCreation) throws DocumentStoreOperationException {
+
+    if (!allowImplicitIndexCreation) {
+
+      // Before we do anything, make sure that the specified index
+      // actually exists in the
+      // document store - we don't want to rely on ElasticSearch to fail
+      // the document
+      // create because it could be configured to implicitly create a
+      // non-existent index,
+      // which can lead to hard-to-debug behaviour with queries down the
+      // road.
       OperationResult indexExistsResult = checkIndexExistence(indexName);
       if ((indexExistsResult.getResultCode() < 200) || (indexExistsResult.getResultCode() >= 300)) {
-  
+
         DocumentOperationResult opResult = new DocumentOperationResult();
         opResult.setResultCode(Status.NOT_FOUND.getStatusCode());
         opResult.setResult("Document Index '" + indexName + "' does not exist.");
@@ -629,7 +619,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         return opResult;
       }
     }
-    
+
     DocumentOperationResult opResult = new DocumentOperationResult();
 
     // Initialize operation result with a failure codes / fault string
@@ -659,12 +649,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.UPDATE_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName,
-        document.getId());
+        override, indexName, document.getId());
 
     shutdownConnection(conn);
 
@@ -698,7 +685,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     handleResponse(conn, opResult);
     buildDocumentResult(opResult, indexName);
-    //supress the etag and url in response for delete as they are not required
+    // supress the etag and url in response for delete as they are not
+    // required
     if (opResult.getDocument() != null) {
       opResult.getDocument().setEtag(null);
       opResult.getDocument().setUrl(null);
@@ -706,12 +694,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.DELETE_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResult())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResult())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResultCode()),
-        override,
-        indexName,
-        document.getId());
+        override, indexName, document.getId());
 
     shutdownConnection(conn);
 
@@ -746,12 +731,9 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.GET_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName,
-        document.getId());
+        override, indexName, document.getId());
 
     shutdownConnection(conn);
 
@@ -785,14 +767,10 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     handleResponse(conn, opResult);
     buildSearchResult(opResult, indexName);
 
-
     metricsLogger.info(SearchDbMsgs.QUERY_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName,
-        queryString);
+        override, indexName, queryString);
 
     return opResult;
   }
@@ -832,12 +810,54 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     buildSearchResult(opResult, indexName);
 
     metricsLogger.info(SearchDbMsgs.QUERY_DOCUMENT_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+            .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
+        override, indexName, query);
+
+    shutdownConnection(conn);
+
+    return opResult;
+  }
+
+  public SearchOperationResult suggestionQueryWithPayload(String indexName, String query)
+      throws DocumentStoreOperationException {
+
+    SearchOperationResult opResult = new SearchOperationResult();
+
+    if (logger.isDebugEnabled()) {
+      logger.debug("Querying Suggestion index: " + indexName + " with query string: " + query);
+    }
+
+    // Initialize operation result with a failure codes / fault string
+    opResult.setResultCode(500);
+    opResult.setResult(INTERNAL_SERVER_ERROR_ELASTIC_SEARCH_OPERATION_FAULT);
+
+    String fullUrl = getFullUrl("/" + indexName + "/_suggest", false);
+
+    // Grab the current time so we can use it to generate a metrics log.
+    MdcOverride override = getStartTime(new MdcOverride());
+
+    HttpURLConnection conn = initializeConnection(fullUrl);
+
+    try {
+      conn.setRequestMethod("POST");
+    } catch (ProtocolException e) {
+      shutdownConnection(conn);
+      throw new DocumentStoreOperationException("Failed to set HTTP request method to POST.", e);
+    }
+
+    attachContent(conn, query);
+
+    logger.debug("\nsearch(), Sending 'POST' request to URL : " + conn.getURL());
+    logger.debug("Request body =  Elasticsearch query = " + query);
+
+    handleResponse(conn, opResult);
+    buildSuggestResult(opResult, indexName);
+
+    metricsLogger.info(SearchDbMsgs.QUERY_DOCUMENT_TIME,
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResult()),
-        override,
-        indexName,
-        query);
+        override, indexName, query);
 
     shutdownConnection(conn);
 
@@ -897,14 +917,16 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       resultCode = conn.getResponseCode();
     } catch (IOException e) {
       shutdownConnection(conn);
-      throw new DocumentStoreOperationException("Failed to get the response code from the connection.", e);
+      throw new DocumentStoreOperationException(
+          "Failed to get the response code from the connection.", e);
     }
 
     logger.debug("Response Code : " + resultCode);
 
     InputStream inputStream = null;
 
-    if (!(resultCode >= 200 && resultCode <= 299)) { // 2xx response indicates success
+    if (!(resultCode >= 200 && resultCode <= 299)) { // 2xx response
+                                                     // indicates success
       inputStream = conn.getErrorStream();
     } else {
       try {
@@ -963,9 +985,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   /**
-   * This convenience method gets the current system time and stores
-   * it in an attribute in the supplied {@link MdcOverride} object so
-   * that it can be used later by the metrics logger.
+   * This convenience method gets the current system time and stores it in an attribute in the
+   * supplied {@link MdcOverride} object so that it can be used later by the metrics logger.
    *
    * @param override - The {@link MdcOverride} object to update.
    * @return - The supplied {@link MdcOverride} object.
@@ -983,7 +1004,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     // Return the MdcOverride object that we were passed.
     // This looks odd, but it allows us to do stuff like:
     //
-    //    MdcOverride ov = getStartTime(new MdcOverride())
+    // MdcOverride ov = getStartTime(new MdcOverride())
     //
     // which is quite handy, but also allows us to pass in an existing
     // MdcOverride object which already has some attributes set.
@@ -995,12 +1016,10 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     return isSuccessCode(result.getResultCode());
   }
 
-
   private boolean isSuccessCode(int statusCode) {
     return ((statusCode >= 200) && (statusCode < 300));
   }
 
-
   @Override
   public OperationResult performBulkOperations(BulkRequest[] requests)
       throws DocumentStoreOperationException {
@@ -1055,32 +1074,34 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
           logger.debug(Throwables.getStackTraceAsString(e));
         }
 
-        throw new DocumentStoreOperationException("Failed to open connection to document store.  Cause: "
-            + e.getMessage(), e);
+        throw new DocumentStoreOperationException(
+            "Failed to open connection to document store.  Cause: " + e.getMessage(), e);
       }
 
       StringBuilder bulkResult = new StringBuilder(128);
       try {
         // Create an output stream to write our request to.
-        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
-        ;
+        OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());;
 
         if (logger.isDebugEnabled()) {
           logger.debug("ESController: Sending 'BULK' request to " + conn.getURL());
-          logger.debug("ESController: operations: " + esOperationSet.toString().replaceAll("\n",
-              "\\n"));
+          logger.debug(
+              "ESController: operations: " + esOperationSet.toString().replaceAll("\n", "\\n"));
         }
 
-        // Write the resulting request string to our output stream. (this sends the request to ES?)
+        // Write the resulting request string to our output stream.
+        // (this sends the request to ES?)
         out.write(esOperationSet.toString());
         out.close();
 
-        // Open an input stream on our connection in order to read back the results.
+        // Open an input stream on our connection in order to read back
+        // the results.
         InputStream is = conn.getInputStream();
         InputStreamReader inputstreamreader = new InputStreamReader(is);
         BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
 
-        // Read the contents of the input stream into our result string...
+        // Read the contents of the input stream into our result
+        // string...
         String esResponseString = null;
 
         while ((esResponseString = bufferedreader.readLine()) != null) {
@@ -1096,13 +1117,13 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
           logger.debug(sw.toString());
         }
 
-        throw new DocumentStoreOperationException("Failure interacting with document store.  Cause: "
-            + e.getMessage(), e);
+        throw new DocumentStoreOperationException(
+            "Failure interacting with document store.  Cause: " + e.getMessage(), e);
       }
 
       if (logger.isDebugEnabled()) {
-        logger.debug("ESController: Received result string from ElasticSearch: = "
-            + bulkResult.toString());
+        logger.debug(
+            "ESController: Received result string from ElasticSearch: = " + bulkResult.toString());
       }
 
       // ...and marshal the resulting string into a Java object.
@@ -1116,8 +1137,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
           logger.debug(Throwables.getStackTraceAsString(e));
         }
 
-        throw new DocumentStoreOperationException("Failed to marshal response body.  Cause: "
-            + e.getMessage(), e);
+        throw new DocumentStoreOperationException(
+            "Failed to marshal response body.  Cause: " + e.getMessage(), e);
       }
     }
 
@@ -1130,31 +1151,29 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     // dumped into the metrics log, so concatenate it.
     String resultStringForMetricsLog = result.getResult();
     if ((result.getResultCode() >= 200) && (result.getResultCode() < 300)) {
-      resultStringForMetricsLog = resultStringForMetricsLog.substring(0,
-          Math.max(resultStringForMetricsLog.length(), 85)) + "...";
+      resultStringForMetricsLog =
+          resultStringForMetricsLog.substring(0, Math.max(resultStringForMetricsLog.length(), 85))
+              + "...";
     }
 
     metricsLogger.info(SearchDbMsgs.BULK_OPERATIONS_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, result.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, result.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, resultStringForMetricsLog),
         override);
 
     return result;
   }
 
-
   /**
-   * This method converts a {@link BulkRequest} object into a json structure
-   * which can be understood by ElasticSearch.
+   * This method converts a {@link BulkRequest} object into a json structure which can be understood
+   * by ElasticSearch.
    *
    * @param request - The request to be performed.
-   * @param sb      - The string builder to append the json data to
+   * @param sb - The string builder to append the json data to
    * @throws DocumentStoreOperationException
    */
   private boolean buildEsOperation(BulkRequest request, StringBuilder sb,
-                                   List<ElasticSearchResultItem> fails)
-      throws DocumentStoreOperationException {
+      List<ElasticSearchResultItem> fails) throws DocumentStoreOperationException {
 
     boolean retVal = true;
     OperationResult indexExistsResult = null;
@@ -1168,11 +1187,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // Make sure that we were supplied a document payload.
         if (request.getOperation().getDocument() == null) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Missing document payload",
-              request.getIndex(),
-              request.getId(),
-              400,
+          fails.add(generateRejectionEntry(request.getOperationType(), "Missing document payload",
+              request.getIndex(), request.getId(), 400,
               request.getOperation().getMetaData().getUrl()));
           return false;
         }
@@ -1182,24 +1198,21 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         if (!ApiUtils.validateDocumentUri(request.getOperation().getMetaData().getUrl(), false)) {
           fails.add(generateRejectionEntry(request.getOperationType(),
               "Invalid document URL: " + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              "",
-              400,
-              request.getOperation().getMetaData().getUrl()));
+              request.getIndex(), "", 400, request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
         // Validate that the specified index actually exists before we
         // try to perform the create.
-        if (!indexExists(ApiUtils.extractIndexFromUri(request.getOperation().getMetaData().getUrl()))) {
-
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Specified resource does not exist: "
-                  + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              request.getId(),
-              404,
-              request.getOperation().getMetaData().getUrl()));
+        if (!indexExists(
+            ApiUtils.extractIndexFromUri(request.getOperation().getMetaData().getUrl()))) {
+
+          fails
+              .add(generateRejectionEntry(request.getOperationType(),
+                  "Specified resource does not exist: "
+                      + request.getOperation().getMetaData().getUrl(),
+                  request.getIndex(), request.getId(), 404,
+                  request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
@@ -1207,16 +1220,13 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // include it in the bulk operation to Elastic Search
         if (request.getId() == null) {
 
-          sb.append(String.format(BULK_CREATE_WITHOUT_INDEX_TEMPLATE,
-              request.getIndex(),
-              DEFAULT_TYPE));
+          sb.append(
+              String.format(BULK_CREATE_WITHOUT_INDEX_TEMPLATE, request.getIndex(), DEFAULT_TYPE));
 
           // Otherwise, we just leave that parameter off and ElasticSearch
           // will generate one for us.
         } else {
-          sb.append(String.format(BULK_CREATE_WITH_INDEX_TEMPLATE,
-              request.getIndex(),
-              DEFAULT_TYPE,
+          sb.append(String.format(BULK_CREATE_WITH_INDEX_TEMPLATE, request.getIndex(), DEFAULT_TYPE,
               request.getId()));
         }
 
@@ -1235,11 +1245,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // Make sure that we were supplied a document payload.
         if (request.getOperation().getDocument() == null) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Missing document payload",
-              request.getIndex(),
-              request.getId(),
-              400,
+          fails.add(generateRejectionEntry(request.getOperationType(), "Missing document payload",
+              request.getIndex(), request.getId(), 400,
               request.getOperation().getMetaData().getUrl()));
           return false;
         }
@@ -1249,10 +1256,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         if (!ApiUtils.validateDocumentUri(request.getOperation().getMetaData().getUrl(), true)) {
           fails.add(generateRejectionEntry(request.getOperationType(),
               "Invalid document URL: " + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              "",
-              400,
-              request.getOperation().getMetaData().getUrl()));
+              request.getIndex(), "", 400, request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
@@ -1260,13 +1264,12 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // try to perform the update.
         if (!indexExists(request.getIndex())) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Specified resource does not exist: "
-                  + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              request.getId(),
-              404,
-              request.getOperation().getMetaData().getUrl()));
+          fails
+              .add(generateRejectionEntry(request.getOperationType(),
+                  "Specified resource does not exist: "
+                      + request.getOperation().getMetaData().getUrl(),
+                  request.getIndex(), request.getId(), 404,
+                  request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
@@ -1274,35 +1277,29 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // exists before we try to perform the update.
         if (!documentExists(request.getIndex(), request.getId())) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Specified resource does not exist: "
-                  + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              request.getId(),
-              404,
-              request.getOperation().getMetaData().getUrl()));
+          fails
+              .add(generateRejectionEntry(request.getOperationType(),
+                  "Specified resource does not exist: "
+                      + request.getOperation().getMetaData().getUrl(),
+                  request.getIndex(), request.getId(), 404,
+                  request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
-        // It is mandatory that a version be supplied for an update operation,
+        // It is mandatory that a version be supplied for an update
+        // operation,
         // so validate that now.
         if (request.getOperation().getMetaData().getEtag() == null) {
 
           fails.add(generateRejectionEntry(request.getOperationType(),
-              "Missing mandatory ETag field",
-              request.getIndex(),
-              request.getId(),
-              400,
+              "Missing mandatory ETag field", request.getIndex(), request.getId(), 400,
               request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
         // Generate the update request...
-        sb.append(String.format(BULK_IMPORT_INDEX_TEMPLATE,
-            request.getIndex(),
-            DEFAULT_TYPE,
-            request.getId(),
-            request.getOperation().getMetaData().getEtag()));
+        sb.append(String.format(BULK_IMPORT_INDEX_TEMPLATE, request.getIndex(), DEFAULT_TYPE,
+            request.getId(), request.getOperation().getMetaData().getEtag()));
 
         // ...and append the document that we want to update.
         try {
@@ -1320,10 +1317,7 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         if (!ApiUtils.validateDocumentUri(request.getOperation().getMetaData().getUrl(), true)) {
           fails.add(generateRejectionEntry(request.getOperationType(),
               "Invalid document URL: " + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              "",
-              400,
-              request.getOperation().getMetaData().getUrl()));
+              request.getIndex(), "", 400, request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
@@ -1331,13 +1325,12 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // try to perform the delete.
         if (!indexExists(request.getIndex())) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Specified resource does not exist: "
-                  + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              request.getId(),
-              404,
-              request.getOperation().getMetaData().getUrl()));
+          fails
+              .add(generateRejectionEntry(request.getOperationType(),
+                  "Specified resource does not exist: "
+                      + request.getOperation().getMetaData().getUrl(),
+                  request.getIndex(), request.getId(), 404,
+                  request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
@@ -1345,35 +1338,29 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // exists before we try to perform the delete.
         if (!documentExists(request.getIndex(), request.getId())) {
 
-          fails.add(generateRejectionEntry(request.getOperationType(),
-              "Specified resource does not exist: "
-                  + request.getOperation().getMetaData().getUrl(),
-              request.getIndex(),
-              request.getId(),
-              404,
-              request.getOperation().getMetaData().getUrl()));
+          fails
+              .add(generateRejectionEntry(request.getOperationType(),
+                  "Specified resource does not exist: "
+                      + request.getOperation().getMetaData().getUrl(),
+                  request.getIndex(), request.getId(), 404,
+                  request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
-        // It is mandatory that a version be supplied for a delete operation,
+        // It is mandatory that a version be supplied for a delete
+        // operation,
         // so validate that now.
         if (request.getOperation().getMetaData().getEtag() == null) {
 
           fails.add(generateRejectionEntry(request.getOperationType(),
-              "Missing mandatory ETag field",
-              request.getIndex(),
-              request.getId(),
-              400,
+              "Missing mandatory ETag field", request.getIndex(), request.getId(), 400,
               request.getOperation().getMetaData().getUrl()));
           return false;
         }
 
         // Generate the delete request.
-        sb.append(String.format(BULK_DELETE_TEMPLATE,
-            request.getIndex(),
-            DEFAULT_TYPE,
-            request.getId(),
-            request.getOperation().getMetaData().getEtag()));
+        sb.append(String.format(BULK_DELETE_TEMPLATE, request.getIndex(), DEFAULT_TYPE,
+            request.getId(), request.getOperation().getMetaData().getEtag()));
         break;
       default:
     }
@@ -1397,21 +1384,16 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
   }
 
   /**
-   * This method constructs a status entry for a bulk operation which has
-   * been rejected before even sending it to the document store.
+   * This method constructs a status entry for a bulk operation which has been rejected before even
+   * sending it to the document store.
    *
    * @param rejectReason - A message describing why the operation was rejected.
-   * @param anId         - The identifier associated with the document being
-   *                     acted on.
-   * @param statusCode  - An HTTP status code.
+   * @param anId - The identifier associated with the document being acted on.
+   * @param statusCode - An HTTP status code.
    * @return - A result set item.
    */
-  private ElasticSearchResultItem generateRejectionEntry(OperationType opType,
-                                                         String rejectReason,
-                                                         String index,
-                                                         String anId,
-                                                         int statusCode,
-                                                         String originalUrl) {
+  private ElasticSearchResultItem generateRejectionEntry(OperationType opType, String rejectReason,
+      String index, String anId, int statusCode, String originalUrl) {
 
     ElasticSearchError err = new ElasticSearchError();
     err.setReason(rejectReason);
@@ -1441,14 +1423,11 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     return rejectionResult;
   }
 
-
   /**
-   * This method takes the json structure returned from ElasticSearch in
-   * response to a bulk operations request and marshals it into a Java
-   * object.
+   * This method takes the json structure returned from ElasticSearch in response to a bulk
+   * operations request and marshals it into a Java object.
    *
-   * @param jsonResult - The bulk operations response returned from
-   *                   ElasticSearch.
+   * @param jsonResult - The bulk operations response returned from ElasticSearch.
    * @return - The marshalled response.
    * @throws JsonParseException
    * @throws JsonMappingException
@@ -1472,16 +1451,15 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     return null;
   }
 
-
   /**
-   * This method takes the marshalled ElasticSearch bulk response and
-   * converts it into a generic response payload.
+   * This method takes the marshalled ElasticSearch bulk response and converts it into a generic
+   * response payload.
    *
    * @param esResult - ElasticSearch bulk operations response.
    * @return - A generic result set.
    */
   private String buildGenericBulkResultSet(ElasticSearchBulkOperationResult esResult,
-                                           List<ElasticSearchResultItem> rejectedOps) {
+      List<ElasticSearchResultItem> rejectedOps) {
 
     int totalOps = 0;
     int totalSuccess = 0;
@@ -1490,8 +1468,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     if (logger.isDebugEnabled()) {
 
       logger.debug("ESController: Build generic result set.  ES Results: "
-          + ((esResult != null) ? esResult.toString() : "[]")
-          + " Rejected Ops: " + rejectedOps.toString());
+          + ((esResult != null) ? esResult.toString() : "[]") + " Rejected Ops: "
+          + rejectedOps.toString());
     }
 
     // Build a combined list of result items from the results returned
@@ -1527,24 +1505,19 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
     }
 
     // Now, build the result string and return it.
-    String responseBody = "{ \"total_operations\": " + totalOps + ", "
-        + "\"total_success\": " + totalSuccess + ", "
-        + "\"total_fails\": " + totalFails + ", "
-        + "\"results\": ["
-        + resultsBuilder.toString()
-        + "]}";
+    String responseBody = "{ \"total_operations\": " + totalOps + ", " + "\"total_success\": "
+        + totalSuccess + ", " + "\"total_fails\": " + totalFails + ", " + "\"results\": ["
+        + resultsBuilder.toString() + "]}";
 
     return responseBody;
   }
 
-
   /**
-   * This method queryies ElasticSearch to determine if the supplied
-   * index is present in the document store.
+   * This method queryies ElasticSearch to determine if the supplied index is present in the
+   * document store.
    *
    * @param indexName - The index to look for.
-   * @return - An operation result indicating the success or failure of
-   * the check.
+   * @return - An operation result indicating the success or failure of the check.
    * @throws DocumentStoreOperationException
    */
   public OperationResult checkIndexExistence(String indexName)
@@ -1575,7 +1548,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       resultCode = conn.getResponseCode();
     } catch (IOException e) {
       shutdownConnection(conn);
-      throw new DocumentStoreOperationException("Failed to get the response code from the connection.", e);
+      throw new DocumentStoreOperationException(
+          "Failed to get the response code from the connection.", e);
     }
     logger.debug("Response Code : " + resultCode);
 
@@ -1583,18 +1557,15 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
 
     // Generate a metrics log so we can track how long the operation took.
     metricsLogger.info(SearchDbMsgs.CHECK_INDEX_TIME,
-        new LogFields()
-            .setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
+        new LogFields().setField(LogLine.DefinedFields.RESPONSE_CODE, opResult.getResultCode())
             .setField(LogLine.DefinedFields.RESPONSE_DESCRIPTION, opResult.getResultCode()),
-        override,
-        indexName);
+        override, indexName);
 
     shutdownConnection(conn);
 
     return opResult;
   }
 
-
   private void buildDocumentResult(DocumentOperationResult result, String index)
       throws DocumentStoreOperationException {
 
@@ -1616,17 +1587,16 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
         // Error response object
         JSONObject error = (JSONObject) root.get("error");
         if (error != null) {
-          result.setError(new ErrorResult(error.get("type").toString(),
-              error.get("reason").toString()));
+          result.setError(
+              new ErrorResult(error.get("type").toString(), error.get("reason").toString()));
         }
 
       }
     } catch (Exception e) {
-      throw new DocumentStoreOperationException("Failed to parse Elastic Search response."
-          + result.getResult());
+      throw new DocumentStoreOperationException(
+          "Failed to parse Elastic Search response." + result.getResult());
     }
 
-
   }
 
   private String buildDocumentResponseUrl(String index, String id) {
@@ -1657,8 +1627,8 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
             doc.setEtag((hit.get("_version") != null) ? hit.get("_version").toString() : "");
           }
 
-          doc.setUrl(buildDocumentResponseUrl(index, (hit.get("_id") != null)
-              ? hit.get("_id").toString() : ""));
+          doc.setUrl(buildDocumentResponseUrl(index,
+              (hit.get("_id") != null) ? hit.get("_id").toString() : ""));
           doc.setContent((JSONObject) hit.get("_source"));
           searchHit.setDocument(doc);
           searchHitArray.add(searchHit);
@@ -1679,13 +1649,73 @@ public class ElasticSearchHttpController implements DocumentStoreInterface {
       } else {
         JSONObject error = (JSONObject) root.get("error");
         if (error != null) {
-          result.setError(new ErrorResult(error.get("type").toString(),
-              error.get("reason").toString()));
+          result.setError(
+              new ErrorResult(error.get("type").toString(), error.get("reason").toString()));
+        }
+      }
+    } catch (Exception e) {
+      throw new DocumentStoreOperationException(
+          "Failed to parse Elastic Search response." + result.getResult());
+    }
+
+  }
+
+  private void buildSuggestResult(SearchOperationResult result, String index)
+      throws DocumentStoreOperationException {
+
+    JSONParser parser = new JSONParser();
+    JSONObject root;
+    try {
+      root = (JSONObject) parser.parse(result.getResult());
+      if (result.getResultCode() >= 200 && result.getResultCode() <= 299) {
+        JSONArray hitArray = (JSONArray) root.get("suggest-vnf");
+        JSONObject hitdata = (JSONObject) hitArray.get(0);
+        JSONArray optionsArray = (JSONArray) hitdata.get("options");
+        SuggestHits suggestHits = new SuggestHits();
+        suggestHits.setTotalHits(String.valueOf(optionsArray.size()));
+
+        ArrayList<SuggestHit> suggestHitArray = new ArrayList<SuggestHit>();
+
+        for (int i = 0; i < optionsArray.size(); i++) {
+          JSONObject hit = (JSONObject) optionsArray.get(i);
+
+          SuggestHit suggestHit = new SuggestHit();
+          suggestHit.setScore((hit.get("score") != null) ? hit.get("score").toString() : "");
+          suggestHit.setText((hit.get("text") != null) ? hit.get("text").toString() : "");
+          Document doc = new Document();
+          if (hit.get("_version") != null) {
+            doc.setEtag((hit.get("_version") != null) ? hit.get("_version").toString() : "");
+          }
+          doc.setUrl(buildDocumentResponseUrl(index,
+              (hit.get("_id") != null) ? hit.get("_id").toString() : ""));
+
+          doc.setContent((JSONObject) hit.get("payload"));
+          suggestHit.setDocument(doc);
+          suggestHitArray.add(suggestHit);
+        }
+        suggestHits.setHits(suggestHitArray.toArray(new SuggestHit[suggestHitArray.size()]));
+        result.setSuggestResult(suggestHits);
+
+        JSONObject aggregations = (JSONObject) root.get("aggregations");
+        if (aggregations != null) {
+          AggregationResult[] aggResults =
+              AggregationParsingUtil.parseAggregationResults(aggregations);
+          AggregationResults aggs = new AggregationResults();
+          aggs.setAggregations(aggResults);
+          result.setAggregationResult(aggs);
+        }
+
+        // success
+      } else {
+        JSONObject error = (JSONObject) root.get("error");
+        if (error != null) {
+          result.setError(
+              new ErrorResult(error.get("type").toString(), error.get("reason").toString()));
         }
       }
     } catch (Exception e) {
-      throw new DocumentStoreOperationException("Failed to parse Elastic Search response."
-          + result.getResult());
+      throw new DocumentStoreOperationException(
+          "Failed to parse Elastic Search response." + result.getResult());
     }
 
   }