2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
8 * ================================================================================
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License ati
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 * ============LICENSE_END=========================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.openecomp.sa.searchdbabstraction.searchapi;
27 import com.fasterxml.jackson.annotation.JsonProperty;
28 import org.radeox.util.logging.Logger;
30 import java.util.ArrayList;
31 import java.util.List;
32 import java.util.concurrent.atomic.AtomicBoolean;
35 * This class represents the structure of a search statement.
37 * <p>The expected JSON structure to represent a search statement is as follows:
41 * "results-start": int, - Optional: index of starting point in result set.
42 * "results-size": int, - Optional: maximum number of documents to include in result set.
45 * { filter structure - see {@link Filter} }
49 * { query structure - see {@link QueryStatement} },
50 * { query structure - see {@link QueryStatement} },
53 * { query structure - see {@link QueryStatement} },
57 * { aggregation structure - see {@link AggregationStatement} },
58 * { aggregation structure - see {@link AggregationStatement} },
61 * { aggregation structure - see {@link AggregationStatement} },
66 public class SearchStatement {
69 * Defines the filters that should be applied before running the
70 * actual queries. This is optional.
72 private Filter filter;
75 * The list of queries to be applied to the document store.
77 private Query[] queries;
80 * The list of aggregations to be applied to the search
82 private Aggregation[] aggregations;
85 * Defines the sort criteria to apply to the query result set.
90 @JsonProperty("results-start")
91 private Integer resultsStart;
93 @JsonProperty("results-size")
96 public Filter getFilter() {
100 public void setFilter(Filter filter) {
101 this.filter = filter;
104 public Query[] getQueries() {
108 public void setQueries(Query[] queries) {
109 this.queries = queries;
112 public Sort getSort() {
116 public void setSort(Sort sort) {
120 public boolean isFiltered() {
121 return filter != null;
124 public Aggregation[] getAggregations() {
128 public void setAggregations(Aggregation[] aggregations) {
129 this.aggregations = aggregations;
132 public boolean hasAggregations() {
133 return aggregations != null && aggregations.length > 0;
136 public Integer getFrom() {
140 public void setFrom(Integer from) {
141 this.resultsStart = from;
144 public Integer getSize() {
148 public void setSize(Integer size) {
153 * This method returns a string which represents this statement in syntax
154 * that is understandable by ElasticSearch and is suitable for inclusion
155 * in an ElasticSearch query string.
157 * @return - ElasticSearch syntax string.
159 public String toElasticSearch() {
161 StringBuilder sb = new StringBuilder();
162 List<QueryStatement> notMatchQueries = new ArrayList<QueryStatement>();
163 List<QueryStatement> mustQueries = new ArrayList<QueryStatement>();
164 List<QueryStatement> shouldQueries = new ArrayList<QueryStatement>();
166 createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
170 sb.append("\"version\": true,");
172 // If the client has specified an index into the results for the first
173 // document in the result set then include that in the ElasticSearch
175 if (resultsStart != null) {
176 sb.append("\"from\": ").append(resultsStart).append(", ");
179 // If the client has specified a maximum number of documents to be returned
180 // in the result set then include that in the ElasticSearch query.
182 sb.append("\"size\": ").append(size).append(", ");
185 sb.append("\"query\": {");
186 sb.append("\"bool\": {");
188 sb.append("\"must\": [");
189 AtomicBoolean firstQuery = new AtomicBoolean(true);
190 for (QueryStatement query : mustQueries) {
192 if (!firstQuery.compareAndSet(true, false)) {
196 sb.append(query.toElasticSearch());
200 sb.append("\"should\": [");
202 firstQuery = new AtomicBoolean(true);
203 for (QueryStatement query : shouldQueries) {
205 if (!firstQuery.compareAndSet(true, false)) {
209 sb.append(query.toElasticSearch());
212 sb.append("],"); // close should list
214 sb.append("\"must_not\": [");
215 firstQuery.set(true);
216 for (QueryStatement query : notMatchQueries) {
217 sb.append(query.toElasticSearch());
221 // Add the filter stanza, if one is required.
223 sb.append(", \"filter\": ").append(filter.toElasticSearch());
226 sb.append("}"); // close bool clause
227 sb.append("}"); // close query clause
229 // Add the sort directive, if one is required.
231 sb.append(", \"sort\": ").append(sort.toElasticSearch());
235 if (hasAggregations()) {
236 sb.append(", \"aggs\": {");
238 for (int i = 0; i < aggregations.length; i++) {
242 sb.append(aggregations[i].toElasticSearch());
250 Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
251 return sb.toString();
254 private void createQueryLists(Query[] queries, List<QueryStatement> mustList,
255 List<QueryStatement> mayList, List<QueryStatement> mustNotList) {
257 for (Query query : queries) {
259 if (query.isMust()) {
261 if (query.getQueryStatement().isNotMatch()) {
262 mustNotList.add(query.getQueryStatement());
264 mustList.add(query.getQueryStatement());
268 if (query.getQueryStatement().isNotMatch()) {
269 mustNotList.add(query.getQueryStatement());
271 mayList.add(query.getQueryStatement());
279 public String toString() {
281 StringBuilder sb = new StringBuilder();
283 sb.append("SEARCH STATEMENT: {");
286 sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
289 if (filter != null) {
290 sb.append("filter: ").append(filter.toString()).append(", ");
293 sb.append("queries: [");
294 AtomicBoolean firstQuery = new AtomicBoolean(true);
295 if (queries != null) {
296 for (Query query : queries) {
298 if (!firstQuery.compareAndSet(true, false)) {
301 sb.append(query.toString());
306 sb.append("aggregations: [");
307 firstQuery = new AtomicBoolean(true);
309 if (aggregations != null) {
310 for (Aggregation agg : aggregations) {
312 if (!firstQuery.compareAndSet(true, false)) {
315 sb.append(agg.toString());
322 return sb.toString();