X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Forg%2Fonap%2Faai%2Fsa%2Fsearchdbabstraction%2Fsearchapi%2FTermQuery.java;h=b8afa7e3d0ba80ea1a2b391ae24160a757553880;hb=15af66b115f3e8046b2d0f2634fb77b3d835f730;hp=08bd501a4c28db4d3431ea51a0ff49e2e09062b5;hpb=71393bb2bf9fb10962723e61cf0e70d9aa202645;p=aai%2Fsearch-data-service.git diff --git a/src/main/java/org/onap/aai/sa/searchdbabstraction/searchapi/TermQuery.java b/src/main/java/org/onap/aai/sa/searchdbabstraction/searchapi/TermQuery.java index 08bd501..b8afa7e 100644 --- a/src/main/java/org/onap/aai/sa/searchdbabstraction/searchapi/TermQuery.java +++ b/src/main/java/org/onap/aai/sa/searchdbabstraction/searchapi/TermQuery.java @@ -28,18 +28,20 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * This class represents a simple term query. * - *

A term query takes an operator, a field to apply the query to and a value to match - * against the query contents. + *

+ * A term query takes an operator, a field to apply the query to and a value to match against the query contents. * - *

Valid operators include: + *

+ * Valid operators include: *

- * The following examples illustrate the structure of a few variants of the - * term query: + * The following examples illustrate the structure of a few variants of the term query: * - *

+ * 

+ * + *

  *     // Single Field Match Query:
  *     {
  *         "match": {"field": "searchTags", "value": "abcd"}
@@ -51,7 +53,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
  *     }
  * 
* - *

+ * 

+ * + *

  *     // Multi Field Match Query With A Single Value:
  *     {
  *         "match": {"field": "entityType searchTags", "value": "pserver"}
@@ -65,280 +69,274 @@ import java.util.concurrent.atomic.AtomicBoolean;
  */
 public class TermQuery {
 
-  /**
-   * The name of the field to apply the term query to.
-   */
-  private String field;
+    /**
+     * The name of the field to apply the term query to.
+     */
+    private String field;
+
+    /**
+     * The value which the field must contain in order to have a match.
+     */
+    private Object value;
+
+    /**
+     * For multi field queries only. Determines the rules for whether or not a document matches the query, as follows:
+     *
+     * 

+ * "and" - At least one occurrence of every supplied value must be present in any of the supplied fields. + * + *

+ * "or" - At least one occurrence of any of the supplied values must be present in any of the supplied fields. + */ + private String operator; + + @JsonProperty("analyzer") + private String searchAnalyzer; + + + public String getField() { + return field; + } + + public void setField(String field) { + this.field = field; + } - /** - * The value which the field must contain in order to have a match. - */ - private Object value; - - /** - * For multi field queries only. Determines the rules for whether or not a document matches - * the query, as follows: - * - *

"and" - At least one occurrence of every supplied value must be present in any of the - * supplied fields. - * - *

"or" - At least one occurrence of any of the supplied values must be present in any of - * the supplied fields. - */ - private String operator; - - @JsonProperty("analyzer") - private String searchAnalyzer; - - - public String getField() { - return field; - } - - public void setField(String field) { - this.field = field; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - private boolean isNumericValue() { - return ((value instanceof Integer) || (value instanceof Double)); - } - - public String getOperator() { - return operator; - } - - public void setOperator(String operator) { - this.operator = operator; - } - - public String getSearchAnalyzer() { - return searchAnalyzer; - } - - public void setSearchAnalyzer(String searchAnalyzer) { - this.searchAnalyzer = searchAnalyzer; - } - - /** - * This method returns a string which represents this query in syntax - * that is understandable by ElasticSearch and is suitable for inclusion - * in an ElasticSearch query string. - * - * @return - ElasticSearch syntax string. - */ - public String toElasticSearch() { - - StringBuilder sb = new StringBuilder(); - - sb.append("{"); - - // Are we generating a multi field query? - if (isMultiFieldQuery()) { - - // For multi field queries, we have to be careful about how we handle - // nested fields, so check to see if any of the specified fields are - // nested. - if (field.contains(".")) { - - // Build the equivalent of a multi match query across one or more nested fields. - toElasticSearchNestedMultiMatchQuery(sb); - - } else { - - // Build a real multi match query, since we don't need to worry about nested fields. - toElasticSearchMultiFieldQuery(sb); - } - } else { - - // Single field query. - - // Add the necessary wrapping if this is a query against a nested field. - if (fieldIsNested(field)) { - sb.append("{\"nested\": { \"path\": \"").append(pathForNestedField(field)) - .append("\", \"query\": "); - } - - // Build the query. - toElasticSearchSingleFieldQuery(sb); - - if (fieldIsNested(field)) { - sb.append("}}"); - } + public Object getValue() { + return value; } - sb.append("}"); + public void setValue(Object value) { + this.value = value; + } + + private boolean isNumericValue() { + return ((value instanceof Integer) || (value instanceof Double)); + } - return sb.toString(); - } + public String getOperator() { + return operator; + } + public void setOperator(String operator) { + this.operator = operator; + } - /** - * Determines whether or not the client has specified a term query with - * multiple fields. - * - * @return - true if the query is referencing multiple fields, false, otherwise. - */ - private boolean isMultiFieldQuery() { + public String getSearchAnalyzer() { + return searchAnalyzer; + } - return (field.split(" ").length > 1); - } + public void setSearchAnalyzer(String searchAnalyzer) { + this.searchAnalyzer = searchAnalyzer; + } + /** + * This method returns a string which represents this query in syntax that is understandable by ElasticSearch and is + * suitable for inclusion in an ElasticSearch query string. + * + * @return - ElasticSearch syntax string. + */ + public String toElasticSearch() { - /** - * Constructs a single field term query in ElasticSearch syntax. - * - * @param sb - The string builder to assemble the query string with. - * @return - The single term query. - */ - private void toElasticSearchSingleFieldQuery(StringBuilder sb) { + StringBuilder sb = new StringBuilder(); - sb.append("\"term\": {\"").append(field).append("\" : "); + sb.append("{"); - // For numeric values, don't enclose the value in quotes. - if (!isNumericValue()) { - sb.append("\"").append(value).append("\""); - } else { - sb.append(value); - } + // Are we generating a multi field query? + if (isMultiFieldQuery()) { - sb.append("}"); - } + // For multi field queries, we have to be careful about how we handle + // nested fields, so check to see if any of the specified fields are + // nested. + if (field.contains(".")) { + // Build the equivalent of a multi match query across one or more nested fields. + toElasticSearchNestedMultiMatchQuery(sb); - /** - * Constructs a multi field query in ElasticSearch syntax. - * - * @param sb - The string builder to assemble the query string with. - * @return - The multi field query. - */ - private void toElasticSearchMultiFieldQuery(StringBuilder sb) { + } else { - sb.append("\"multi_match\": {"); + // Build a real multi match query, since we don't need to worry about nested fields. + toElasticSearchMultiFieldQuery(sb); + } + } else { - sb.append("\"query\": \"").append(value).append("\", "); - sb.append("\"type\": \"cross_fields\","); - sb.append("\"fields\": ["); + // Single field query. - List fields = Arrays.asList(field.split(" ")); - AtomicBoolean firstField = new AtomicBoolean(true); - for (String f : fields) { - if (!firstField.compareAndSet(true, false)) { - sb.append(", "); - } - sb.append("\"").append(f.trim()).append("\""); - } - sb.append("],"); + // Add the necessary wrapping if this is a query against a nested field. + if (fieldIsNested(field)) { + sb.append("{\"nested\": { \"path\": \"").append(pathForNestedField(field)).append("\", \"query\": "); + } - sb.append("\"operator\": \"").append((operator != null) - ? operator.toLowerCase() : "and").append("\""); + // Build the query. + toElasticSearchSingleFieldQuery(sb); - if (searchAnalyzer != null) { - sb.append(", \"analyzer\": \"").append(searchAnalyzer).append("\""); + if (fieldIsNested(field)) { + sb.append("}}"); + } + } + + sb.append("}"); + + return sb.toString(); } - sb.append("}"); - } + /** + * Determines whether or not the client has specified a term query with multiple fields. + * + * @return - true if the query is referencing multiple fields, false, otherwise. + */ + private boolean isMultiFieldQuery() { - /** - * Constructs the equivalent of an ElasticSearch multi match query across - * multiple nested fields. - * - *

Since ElasticSearch doesn't really let you do that, we have to be clever - * and construct an equivalent query using boolean operators to produce - * the same result. - * - * @param sb - The string builder to use to build the query. - */ - public void toElasticSearchNestedMultiMatchQuery(StringBuilder sb) { + return (field.split(" ").length > 1); + } - // Break out our whitespace delimited list of fields and values into a actual lists. - List fields = Arrays.asList(field.split(" ")); - List values = Arrays.asList(((String) value).split(" ")); // GDF: revisit this cast. - sb.append("\"bool\": {"); + /** + * Constructs a single field term query in ElasticSearch syntax. + * + * @param sb - The string builder to assemble the query string with. + * @return - The single term query. + */ + private void toElasticSearchSingleFieldQuery(StringBuilder sb) { - if (operator != null) { + sb.append("\"term\": {\"").append(field).append("\" : "); - if (operator.toLowerCase().equals("and")) { - sb.append("\"must\": ["); - } else if (operator.toLowerCase().equals("or")) { - sb.append("\"should\": ["); - } + // For numeric values, don't enclose the value in quotes. + if (!isNumericValue()) { + sb.append("\"").append(value).append("\""); + } else { + sb.append(value); + } - } else { - sb.append("\"must\": ["); + sb.append("}"); } - AtomicBoolean firstField = new AtomicBoolean(true); - for (String f : fields) { - if (!firstField.compareAndSet(true, false)) { - sb.append(", "); - } + /** + * Constructs a multi field query in ElasticSearch syntax. + * + * @param sb - The string builder to assemble the query string with. + * @return - The multi field query. + */ + private void toElasticSearchMultiFieldQuery(StringBuilder sb) { - sb.append("{ "); + sb.append("\"multi_match\": {"); - // Is this a nested field? - if (fieldIsNested(f)) { + sb.append("\"query\": \"").append(value).append("\", "); + sb.append("\"type\": \"cross_fields\","); + sb.append("\"fields\": ["); - sb.append("\"nested\": {"); - sb.append("\"path\": \"").append(pathForNestedField(f)).append("\", "); - sb.append("\"query\": "); - } + List fields = Arrays.asList(field.split(" ")); + AtomicBoolean firstField = new AtomicBoolean(true); + for (String f : fields) { + if (!firstField.compareAndSet(true, false)) { + sb.append(", "); + } + sb.append("\"").append(f.trim()).append("\""); + } + sb.append("],"); - sb.append("{\"bool\": {"); - sb.append("\"should\": ["); + sb.append("\"operator\": \"").append((operator != null) ? operator.toLowerCase() : "and").append("\""); - AtomicBoolean firstValue = new AtomicBoolean(true); - for (String v : values) { - if (!firstValue.compareAndSet(true, false)) { - sb.append(", "); + if (searchAnalyzer != null) { + sb.append(", \"analyzer\": \"").append(searchAnalyzer).append("\""); } - sb.append("{\"match\": { \""); - sb.append(f).append("\": {\"query\": \"").append(v).append("\""); - if (searchAnalyzer != null) { - sb.append(", \"analyzer\": \"").append(searchAnalyzer).append("\""); + sb.append("}"); + } + + + /** + * Constructs the equivalent of an ElasticSearch multi match query across multiple nested fields. + * + *

+ * Since ElasticSearch doesn't really let you do that, we have to be clever and construct an equivalent query using + * boolean operators to produce the same result. + * + * @param sb - The string builder to use to build the query. + */ + public void toElasticSearchNestedMultiMatchQuery(StringBuilder sb) { + + // Break out our whitespace delimited list of fields and values into a actual lists. + List fields = Arrays.asList(field.split(" ")); + List values = Arrays.asList(((String) value).split(" ")); // GDF: revisit this cast. + + sb.append("\"bool\": {"); + + if (operator != null) { + + if (operator.toLowerCase().equals("and")) { + sb.append("\"must\": ["); + } else if (operator.toLowerCase().equals("or")) { + sb.append("\"should\": ["); + } + + } else { + sb.append("\"must\": ["); } - sb.append("}}}"); - } - sb.append("]"); - sb.append("}"); + AtomicBoolean firstField = new AtomicBoolean(true); + for (String f : fields) { - if (fieldIsNested(f)) { - sb.append("}"); - sb.append("}"); - } + if (!firstField.compareAndSet(true, false)) { + sb.append(", "); + } - sb.append("}"); - } + sb.append("{ "); + + // Is this a nested field? + if (fieldIsNested(f)) { + + sb.append("\"nested\": {"); + sb.append("\"path\": \"").append(pathForNestedField(f)).append("\", "); + sb.append("\"query\": "); + } - sb.append("]"); - sb.append("}"); - } + sb.append("{\"bool\": {"); + sb.append("\"should\": ["); + AtomicBoolean firstValue = new AtomicBoolean(true); + for (String v : values) { + if (!firstValue.compareAndSet(true, false)) { + sb.append(", "); + } + sb.append("{\"match\": { \""); + sb.append(f).append("\": {\"query\": \"").append(v).append("\""); - @Override - public String toString() { - return "field: " + field + ", value: " + value + " (" + value.getClass().getName() + ")"; - } + if (searchAnalyzer != null) { + sb.append(", \"analyzer\": \"").append(searchAnalyzer).append("\""); + } + sb.append("}}}"); + } - public boolean fieldIsNested(String field) { - return field.contains("."); - } + sb.append("]"); + sb.append("}"); - public String pathForNestedField(String field) { - int index = field.lastIndexOf('.'); - return field.substring(0, index); - } + if (fieldIsNested(f)) { + sb.append("}"); + sb.append("}"); + } + + sb.append("}"); + } + + sb.append("]"); + sb.append("}"); + } + + + @Override + public String toString() { + return "field: " + field + ", value: " + value + " (" + value.getClass().getName() + ")"; + } + + public boolean fieldIsNested(String field) { + return field.contains("."); + } + + public String pathForNestedField(String field) { + int index = field.lastIndexOf('.'); + return field.substring(0, index); + } }