From: renealr Date: Mon, 19 Mar 2018 14:48:51 +0000 (-0400) Subject: enable suggestions to use search data service X-Git-Tag: v1.2.0~29^2 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=3357aaeb4b8fb08e8ccf5fe65c539ea9bb41caf5;p=aai%2Fsparky-be.git enable suggestions to use search data service Added logic to ensure that suggestions are enabled using the search data service Issue-ID: AAI-895 Change-Id: If0bc6a56a4700a0f96584048676ee1a15db63592 Signed-off-by: renealr --- diff --git a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java index 12443e4..e98ffd5 100644 --- a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java +++ b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateSummaryProcessor.java @@ -48,32 +48,37 @@ import org.restlet.data.Status; public class AggregateSummaryProcessor { - private static final Logger LOG = LoggerFactory.getInstance().getLogger(AggregateSummaryProcessor.class); + private static final Logger LOG = + LoggerFactory.getInstance().getLogger(AggregateSummaryProcessor.class); private static final String KEY_FILTERS = "filters"; private ElasticSearchAdapter elasticSearchAdapter = null; - + private String vnfAggregationIndexName; private FiltersConfig filtersConfig; - - public AggregateSummaryProcessor(ElasticSearchAdapter elasticSearchAdapter, FiltersConfig filtersConfig) { + + public AggregateSummaryProcessor(ElasticSearchAdapter elasticSearchAdapter, + FiltersConfig filtersConfig) { this.elasticSearchAdapter = elasticSearchAdapter; this.filtersConfig = filtersConfig; } - + public void setVnfAggregationIndexName(String vnfAggregationIndexName) { this.vnfAggregationIndexName = vnfAggregationIndexName; } - + public void getFilteredAggregation(Exchange exchange) { - - Response response = exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class); + + Response response = + exchange.getIn().getHeader(RestletConstants.RESTLET_RESPONSE, Response.class); Request request = exchange.getIn().getHeader(RestletConstants.RESTLET_REQUEST, Request.class); - /* Disables automatic Apache Camel Restlet component logging which prints out an undesirable log entry - which includes client (e.g. browser) information */ + /* + * Disables automatic Apache Camel Restlet component logging which prints out an undesirable log + * entry which includes client (e.g. browser) information + */ request.setLoggable(false); try { @@ -95,29 +100,29 @@ public class AggregateSummaryProcessor { if (parameters.has(KEY_FILTERS)) { requestFilters = parameters.getJSONArray(KEY_FILTERS); } else { - + JSONObject zeroResponsePayload = new JSONObject(); zeroResponsePayload.put("count", 0); response.setStatus(Status.SUCCESS_OK); response.setEntity(zeroResponsePayload.toString(), MediaType.APPLICATION_JSON); exchange.getOut().setBody(response); - + LOG.error(AaiUiMsgs.ERROR_FILTERS_NOT_FOUND); return; } - + if (requestFilters != null && requestFilters.length() > 0) { List filtersToQuery = new ArrayList(); - for(int i = 0; i < requestFilters.length(); i++) { + for (int i = 0; i < requestFilters.length(); i++) { JSONObject filterEntry = requestFilters.getJSONObject(i); filtersToQuery.add(filterEntry); } - + String jsonResponsePayload = getVnfFilterAggregations(filtersToQuery); response.setStatus(Status.SUCCESS_OK); response.setEntity(jsonResponsePayload, MediaType.APPLICATION_JSON); exchange.getOut().setBody(response); - + } else { String emptyResponse = getEmptyAggResponse(); response.setStatus(Status.SUCCESS_OK); @@ -127,10 +132,11 @@ public class AggregateSummaryProcessor { } } } catch (Exception exc) { - LOG.error(AaiUiMsgs.ERROR_GENERIC, "FilterProcessor failed to get filter list due to error = " + exc.getMessage()); + LOG.error(AaiUiMsgs.ERROR_GENERIC, + "FilterProcessor failed to get filter list due to error = " + exc.getMessage()); } } - + private String getEmptyAggResponse() { JSONObject aggPayload = new JSONObject(); aggPayload.put("totalChartHits", 0); @@ -139,66 +145,65 @@ public class AggregateSummaryProcessor { payload.append("groupby_aggregation", aggPayload); return payload.toString(); - } - + } + private static final String FILTER_ID_KEY = "filterId"; private static final String FILTER_VALUE_KEY = "filterValue"; private static final int DEFAULT_SHOULD_MATCH_SCORE = 1; private static final String VNF_FILTER_AGGREGATION = "vnfFilterAggregation"; - private String getVnfFilterAggregations(List filtersToQuery) throws IOException { - + List searchFilters = new ArrayList(); - for(JSONObject filterEntry : filtersToQuery) { - + for (JSONObject filterEntry : filtersToQuery) { + String filterId = filterEntry.getString(FILTER_ID_KEY); - if(filterId != null) { + if (filterId != null) { SearchFilter filter = new SearchFilter(); filter.setFilterId(filterId); - - if(filterEntry.has(FILTER_VALUE_KEY)) { + + if (filterEntry.has(FILTER_VALUE_KEY)) { String filterValue = filterEntry.getString(FILTER_VALUE_KEY); filter.addValue(filterValue); } - + searchFilters.add(filter); } } - + // Create query for summary by entity type - JsonObject vnfSearch = FilterQueryBuilder.createCombinedBoolAndAggQuery(filtersConfig, searchFilters, DEFAULT_SHOULD_MATCH_SCORE); + JsonObject vnfSearch = FilterQueryBuilder.createCombinedBoolAndAggQuery(filtersConfig, + searchFilters, DEFAULT_SHOULD_MATCH_SCORE); // Parse response for summary by entity type query OperationResult opResult = elasticSearchAdapter.doPost( elasticSearchAdapter.buildElasticSearchUrlForApi(vnfAggregationIndexName, SparkyConstants.ES_SEARCH_API), vnfSearch.toString(), javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE); - + return buildAggregateVnfResponseJson(opResult.getResult()); - + } - + private String buildAggregateVnfResponseJson(String responseJsonStr) { - + JSONObject finalOutputToFe = new JSONObject(); JSONObject responseJson = new JSONObject(responseJsonStr); - - + JSONObject hits = responseJson.getJSONObject("hits"); int totalHits = hits.getInt("total"); finalOutputToFe.put("total", totalHits); - + JSONObject aggregations = responseJson.getJSONObject("aggregations"); String[] aggKeys = JSONObject.getNames(aggregations); JSONObject aggregationsList = new JSONObject(); - - for(String aggName : aggKeys) { + + for (String aggName : aggKeys) { JSONObject aggregation = aggregations.getJSONObject(aggName); JSONArray buckets = aggregation.getJSONArray("buckets"); aggregationsList.put(aggName, buckets); } - + finalOutputToFe.put("aggregations", aggregationsList); return finalOutputToFe.toString(); diff --git a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java index 6ff779d..3a1f5c4 100644 --- a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java +++ b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProvider.java @@ -22,46 +22,55 @@ */ package org.onap.aai.sparky.aggregatevnf.search; +import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; -import javax.json.JsonObject; -import javax.ws.rs.core.MediaType; - -import org.json.JSONArray; -import org.json.JSONObject; import org.onap.aai.cl.api.Logger; import org.onap.aai.cl.eelf.LoggerFactory; import org.onap.aai.restclient.client.OperationResult; import org.onap.aai.sparky.common.search.CommonSearchSuggestion; -import org.onap.aai.sparky.dal.ElasticSearchAdapter; import org.onap.aai.sparky.logging.AaiUiMsgs; +import org.onap.aai.sparky.search.SearchServiceAdapter; import org.onap.aai.sparky.search.api.SearchProvider; import org.onap.aai.sparky.search.entity.QuerySearchEntity; import org.onap.aai.sparky.search.entity.SearchSuggestion; import org.onap.aai.sparky.search.filters.entity.UiFilterValueEntity; import org.onap.aai.sparky.util.NodeUtils; -import org.onap.aai.sparky.viewandinspect.config.SparkyConstants; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; public class AggregateVnfSearchProvider implements SearchProvider { - - private static final Logger LOG = LoggerFactory.getInstance().getLogger(AggregateVnfSearchProvider.class); + + private static final Logger LOG = + LoggerFactory.getInstance().getLogger(AggregateVnfSearchProvider.class); private ObjectMapper mapper; - private ElasticSearchAdapter elasticSearchAdapter = null; + private SearchServiceAdapter searchServiceAdapter = null; private String autoSuggestIndexName; private String vnfSearchSuggestionRoute; - public AggregateVnfSearchProvider(ElasticSearchAdapter elasticSearchAdapter, + private static final String AUTO_SUGGEST_TEMPLATE = "{ " + "\"results-size\": %d," + + "\"suggest-text\": \"%s\"," + "\"suggest-field\": \"%s\"" + "}"; + + private static final String KEY_SEARCH_RESULT = "searchResult"; + private static final String KEY_HITS = "hits"; + private static final String KEY_DOCUMENT = "document"; + private static final String KEY_CONTENT = "content"; + private static final String KEY_TEXT = "text"; + private static final String KEY_FILTER_LIST = "filterList"; + + public AggregateVnfSearchProvider(SearchServiceAdapter searchServiceAdapter, String autoSuggestIndexName, String vnfSearchSuggestionRoute) { mapper = new ObjectMapper(); - this.elasticSearchAdapter = elasticSearchAdapter; + this.searchServiceAdapter = searchServiceAdapter; this.autoSuggestIndexName = autoSuggestIndexName; this.vnfSearchSuggestionRoute = vnfSearchSuggestionRoute; } - + public void setAutoSuggestIndexName(String autoSuggestIndexName) { this.autoSuggestIndexName = autoSuggestIndexName; } @@ -70,58 +79,96 @@ public class AggregateVnfSearchProvider implements SearchProvider { public List search(QuerySearchEntity queryRequest) { List returnList = new ArrayList(); - try { - /* Create suggestions query */ - JsonObject vnfSearch = VnfSearchQueryBuilder.createSuggestionsQuery(String.valueOf(queryRequest.getMaxResults()), queryRequest.getQueryStr()); + final String fullUrlStr = + searchServiceAdapter.buildSuggestServiceQueryUrl(autoSuggestIndexName); + String postBody = + String.format(AUTO_SUGGEST_TEMPLATE, Integer.parseInt(queryRequest.getMaxResults()), + queryRequest.getQueryStr(), "entity_suggest"); + OperationResult opResult = + searchServiceAdapter.doPost(fullUrlStr, postBody, "application/json"); + if (opResult.getResultCode() == 200) { + returnList = generateSuggestionsForSearchResponse(opResult.getResult()); + } else { + LOG.error(AaiUiMsgs.ERROR_PARSING_JSON_PAYLOAD_VERBOSE, opResult.getResult()); + return returnList; + } + } catch (Exception exc) { + LOG.error(AaiUiMsgs.ERROR_GENERIC, "Search failed due to error = " + exc.getMessage()); + } - /* Parse suggestions response */ - OperationResult opResult = elasticSearchAdapter.doPost( - elasticSearchAdapter.buildElasticSearchUrlForApi(autoSuggestIndexName, - SparkyConstants.ES_SUGGEST_API), - vnfSearch.toString(), MediaType.APPLICATION_JSON_TYPE); + return returnList; + } - String result = opResult.getResult(); + private List generateSuggestionsForSearchResponse(String operationResult) { - if (!opResult.wasSuccessful()) { - LOG.error(AaiUiMsgs.ERROR_PARSING_JSON_PAYLOAD_VERBOSE, result); - return returnList; - } + if (operationResult == null || operationResult.length() == 0) { + return null; + } - JSONObject responseJson = new JSONObject(result); - String suggestionsKey = "vnfs"; - JSONArray suggestionsArray = new JSONArray(); - JSONArray suggestions = responseJson.getJSONArray(suggestionsKey); - if (suggestions.length() > 0) { - suggestionsArray = suggestions.getJSONObject(0).getJSONArray("options"); - for (int i = 0; i < suggestionsArray.length(); i++) { - JSONObject querySuggestion = suggestionsArray.getJSONObject(i); - if (querySuggestion != null) { - CommonSearchSuggestion responseSuggestion = new CommonSearchSuggestion(); - responseSuggestion.setText(querySuggestion.getString("text")); - responseSuggestion.setRoute(vnfSearchSuggestionRoute); - responseSuggestion.setHashId(NodeUtils.generateUniqueShaDigest(querySuggestion.getString("text"))); - - // Extract filter list from JSON and add to response suggestion - JSONObject payload = querySuggestion.getJSONObject("payload"); - if (payload.length() > 0) { - JSONArray filterList = payload.getJSONArray("filterList"); - for (int filter = 0; filter < filterList.length(); filter++) { - String filterValueString = filterList.getJSONObject(filter).toString(); - UiFilterValueEntity filterValue = mapper.readValue(filterValueString, UiFilterValueEntity.class); - responseSuggestion.getFilterValues().add(filterValue); - } + ObjectMapper mapper = new ObjectMapper(); + JsonNode rootNode = null; + List suggestionEntityList = new ArrayList(); + + try { + rootNode = mapper.readTree(operationResult); + JsonNode hitsNode = rootNode.get(KEY_SEARCH_RESULT); + // Check if there are hits that are coming back + if (hitsNode.has(KEY_HITS)) { + ArrayNode hitsArray = (ArrayNode) hitsNode.get(KEY_HITS); + + /* + * next we iterate over the values in the hit array elements + */ + Iterator nodeIterator = hitsArray.elements(); + JsonNode entityNode = null; + CommonSearchSuggestion responseSuggestion = null; + JsonNode sourceNode = null; + + while (nodeIterator.hasNext()) { + entityNode = nodeIterator.next(); + String responseText = getValueFromNode(entityNode, KEY_TEXT); + // do the point transformation as we build the response? + responseSuggestion = new CommonSearchSuggestion(); + responseSuggestion.setRoute(vnfSearchSuggestionRoute); + responseSuggestion.setText(responseText); + responseSuggestion.setHashId(NodeUtils.generateUniqueShaDigest(responseText)); + + sourceNode = entityNode.get(KEY_DOCUMENT).get(KEY_CONTENT); + if (sourceNode.has(KEY_FILTER_LIST)) { + ArrayNode filtersArray = (ArrayNode) sourceNode.get(KEY_FILTER_LIST); + for (int i = 0; i < filtersArray.size(); i++) { + String filterValueString = filtersArray.get(i).toString(); + UiFilterValueEntity filterValue = + mapper.readValue(filterValueString, UiFilterValueEntity.class); + responseSuggestion.getFilterValues().add(filterValue); } - returnList.add(responseSuggestion); } + suggestionEntityList.add(responseSuggestion); } } - } catch (Exception exc) { - LOG.error(AaiUiMsgs.ERROR_GENERIC, "Search failed due to error = " + exc.getMessage()); + } catch (IOException exc) { + LOG.warn(AaiUiMsgs.SEARCH_RESPONSE_BUILDING_EXCEPTION, exc.getLocalizedMessage()); } + return suggestionEntityList; - return returnList; } - + + private String getValueFromNode(JsonNode node, String fieldName) { + + if (node == null || fieldName == null) { + return null; + } + + JsonNode valueNode = node.get(fieldName); + + if (valueNode != null) { + return valueNode.asText(); + } + + return null; + + } + } diff --git a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java index a5b14bd..a71b36b 100644 --- a/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java +++ b/src/main/java/org/onap/aai/sparky/aggregatevnf/search/VnfSearchQueryBuilder.java @@ -30,13 +30,11 @@ import javax.json.JsonArrayBuilder; import javax.json.JsonObject; import javax.json.JsonObjectBuilder; - /** * Build a JSON payload to send to elastic search to get vnf search data. */ public class VnfSearchQueryBuilder { - /** * Creates the suggestions query. @@ -136,8 +134,6 @@ public class VnfSearchQueryBuilder { Json.createObjectBuilder().add("must", mustBlobBuilder))); } - - public static JsonObject createSummaryByEntityTypeQuery(Map attributes, String groupByKey) { JsonObjectBuilder jsonBuilder = Json.createObjectBuilder(); diff --git a/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java b/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java index f1ae6b1..1c64622 100644 --- a/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java +++ b/src/main/java/org/onap/aai/sparky/search/SearchServiceAdapter.java @@ -44,6 +44,7 @@ import org.slf4j.MDC; public class SearchServiceAdapter { private static final String VALUE_QUERY = "query"; + private static final String SUGGEST_QUERY = "suggest"; private RestClient client; private RestEndpointConfig endpointConfig; @@ -126,6 +127,17 @@ public class SearchServiceAdapter { public String buildSearchServiceQueryUrl(String indexName) { return buildSearchServiceUrlForApi(indexName, VALUE_QUERY); } + + /** + * Get Full URL for search + * + * @param api the api + * @param indexName + * @return the full url + */ + public String buildSuggestServiceQueryUrl(String indexName) { + return buildSearchServiceUrlForApi(indexName, SUGGEST_QUERY); + } public String buildSearchServiceUrlForApi(String indexName, String api) { return String.format("https://%s:%s/services/search-data-service/%s/search/indexes/%s/%s", diff --git a/src/test/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProviderTest.java b/src/test/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProviderTest.java new file mode 100644 index 0000000..5a24edf --- /dev/null +++ b/src/test/java/org/onap/aai/sparky/aggregatevnf/search/AggregateVnfSearchProviderTest.java @@ -0,0 +1,62 @@ +package org.onap.aai.sparky.aggregatevnf.search; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; + +import javax.ws.rs.core.MediaType; + +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aai.restclient.client.OperationResult; +import org.onap.aai.restclient.client.RestClient; +import org.onap.aai.restclient.enums.RestAuthenticationMode; +import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig; +import org.onap.aai.sparky.search.SearchServiceAdapter; +import org.onap.aai.sparky.search.entity.QuerySearchEntity; + +public class AggregateVnfSearchProviderTest { + + private AggregateVnfSearchProvider aggregateVnfSearchProvider; + private RestEndpointConfig restEndpointConfig; + private SearchServiceAdapter searchserviceAdapter; + private QuerySearchEntity querySearchEntity; + private String successResponsePayload; + private OperationResult successResult = null; + private String goodDrTargetUrl = "https://0.0.0.0:9502/ui-request/servicegraph"; + + @Before + public void init() throws Exception { + + restEndpointConfig = new RestEndpointConfig(); + successResponsePayload = "good-payload"; + successResult = new OperationResult(200, successResponsePayload); + restEndpointConfig.setRestAuthenticationMode(RestAuthenticationMode.SSL_BASIC); + searchserviceAdapter = Mockito.mock(SearchServiceAdapter.class); + aggregateVnfSearchProvider = + new AggregateVnfSearchProvider(searchserviceAdapter, "auto-suggest", "schema"); + querySearchEntity = new QuerySearchEntity(); + + } + + @Test + public void updateValues() { + + assertNotNull(aggregateVnfSearchProvider.search(querySearchEntity)); + aggregateVnfSearchProvider.setAutoSuggestIndexName("auto-suggest-index-1"); + + } + + @Test + public void testProxyMessage_Success() { + Mockito.when(searchserviceAdapter.doPost(Mockito.eq(goodDrTargetUrl), Mockito.anyString(), + Mockito.eq(MediaType.APPLICATION_JSON_TYPE.toString()))).thenReturn(successResult); + } + +} diff --git a/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java b/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java index 7963528..90acfa4 100644 --- a/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java +++ b/src/test/java/org/onap/aai/sparky/search/SearchServiceAdapterTest.java @@ -40,6 +40,7 @@ public class SearchServiceAdapterTest { assertNotNull(searchServiceAdapter.getTxnHeader()); assertNotNull(searchServiceAdapter.buildSearchServiceQueryUrl("searchentity-localhost")); assertNotNull(searchServiceAdapter.buildSearchServiceUrlForApi("searchentity-localhost","2.0")); + assertNotNull(searchServiceAdapter.buildSuggestServiceQueryUrl("searchentity-localhost")); }