2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.sa.searchdbabstraction.searchapi;
25 import com.fasterxml.jackson.annotation.JsonProperty;
26 import org.radeox.util.logging.Logger;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.atomic.AtomicBoolean;
33 * This class represents the structure of a search statement.
35 * <p>The expected JSON structure to represent a search statement is as follows:
39 * "results-start": int, - Optional: index of starting point in result set.
40 * "results-size": int, - Optional: maximum number of documents to include in result set.
43 * { filter structure - see {@link Filter} }
47 * { query structure - see {@link QueryStatement} },
48 * { query structure - see {@link QueryStatement} },
51 * { query structure - see {@link QueryStatement} },
55 * { aggregation structure - see {@link AggregationStatement} },
56 * { aggregation structure - see {@link AggregationStatement} },
59 * { aggregation structure - see {@link AggregationStatement} },
64 public class SearchStatement {
67 * Defines the filters that should be applied before running the
68 * actual queries. This is optional.
70 private Filter filter;
73 * The list of queries to be applied to the document store.
75 private Query[] queries;
78 * The list of aggregations to be applied to the search
80 private Aggregation[] aggregations;
83 * Defines the sort criteria to apply to the query result set.
88 @JsonProperty("results-start")
89 private Integer resultsStart;
91 @JsonProperty("results-size")
94 public Filter getFilter() {
98 public void setFilter(Filter filter) {
102 public Query[] getQueries() {
106 public void setQueries(Query[] queries) {
107 this.queries = queries;
110 public Sort getSort() {
114 public void setSort(Sort sort) {
118 public boolean isFiltered() {
119 return filter != null;
122 public Aggregation[] getAggregations() {
126 public void setAggregations(Aggregation[] aggregations) {
127 this.aggregations = aggregations;
130 public boolean hasAggregations() {
131 return aggregations != null && aggregations.length > 0;
134 public Integer getFrom() {
138 public void setFrom(Integer from) {
139 this.resultsStart = from;
142 public Integer getSize() {
146 public void setSize(Integer size) {
151 * This method returns a string which represents this statement in syntax
152 * that is understandable by ElasticSearch and is suitable for inclusion
153 * in an ElasticSearch query string.
155 * @return - ElasticSearch syntax string.
157 public String toElasticSearch() {
159 StringBuilder sb = new StringBuilder();
160 List<QueryStatement> notMatchQueries = new ArrayList<QueryStatement>();
161 List<QueryStatement> mustQueries = new ArrayList<QueryStatement>();
162 List<QueryStatement> shouldQueries = new ArrayList<QueryStatement>();
164 createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
168 sb.append("\"version\": true,");
170 // If the client has specified an index into the results for the first
171 // document in the result set then include that in the ElasticSearch
173 if (resultsStart != null) {
174 sb.append("\"from\": ").append(resultsStart).append(", ");
177 // If the client has specified a maximum number of documents to be returned
178 // in the result set then include that in the ElasticSearch query.
180 sb.append("\"size\": ").append(size).append(", ");
183 sb.append("\"query\": {");
184 sb.append("\"bool\": {");
186 sb.append("\"must\": [");
187 AtomicBoolean firstQuery = new AtomicBoolean(true);
188 for (QueryStatement query : mustQueries) {
190 if (!firstQuery.compareAndSet(true, false)) {
194 sb.append(query.toElasticSearch());
198 sb.append("\"should\": [");
200 firstQuery = new AtomicBoolean(true);
201 for (QueryStatement query : shouldQueries) {
203 if (!firstQuery.compareAndSet(true, false)) {
207 sb.append(query.toElasticSearch());
210 sb.append("],"); // close should list
212 sb.append("\"must_not\": [");
213 firstQuery.set(true);
214 for (QueryStatement query : notMatchQueries) {
215 sb.append(query.toElasticSearch());
219 // Add the filter stanza, if one is required.
221 sb.append(", \"filter\": ").append(filter.toElasticSearch());
224 sb.append("}"); // close bool clause
225 sb.append("}"); // close query clause
227 // Add the sort directive, if one is required.
229 sb.append(", \"sort\": ").append(sort.toElasticSearch());
233 if (hasAggregations()) {
234 sb.append(", \"aggs\": {");
236 for (int i = 0; i < aggregations.length; i++) {
240 sb.append(aggregations[i].toElasticSearch());
248 Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
249 return sb.toString();
252 private void createQueryLists(Query[] queries, List<QueryStatement> mustList,
253 List<QueryStatement> mayList, List<QueryStatement> mustNotList) {
255 for (Query query : queries) {
257 if (query.isMust()) {
259 if (query.getQueryStatement().isNotMatch()) {
260 mustNotList.add(query.getQueryStatement());
262 mustList.add(query.getQueryStatement());
266 if (query.getQueryStatement().isNotMatch()) {
267 mustNotList.add(query.getQueryStatement());
269 mayList.add(query.getQueryStatement());
277 public String toString() {
279 StringBuilder sb = new StringBuilder();
281 sb.append("SEARCH STATEMENT: {");
284 sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
287 if (filter != null) {
288 sb.append("filter: ").append(filter.toString()).append(", ");
291 sb.append("queries: [");
292 AtomicBoolean firstQuery = new AtomicBoolean(true);
293 if (queries != null) {
294 for (Query query : queries) {
296 if (!firstQuery.compareAndSet(true, false)) {
299 sb.append(query.toString());
304 sb.append("aggregations: [");
305 firstQuery = new AtomicBoolean(true);
307 if (aggregations != null) {
308 for (Aggregation agg : aggregations) {
310 if (!firstQuery.compareAndSet(true, false)) {
313 sb.append(agg.toString());
320 return sb.toString();