2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 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 package org.onap.aai.sa.searchdbabstraction.searchapi;
23 import com.fasterxml.jackson.annotation.JsonProperty;
24 import org.radeox.util.logging.Logger;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.concurrent.atomic.AtomicBoolean;
31 * This class represents the structure of a search statement.
33 * <p>The expected JSON structure to represent a search statement is as follows:
37 * "results-start": int, - Optional: index of starting point in result set.
38 * "results-size": int, - Optional: maximum number of documents to include in result set.
41 * { filter structure - see {@link Filter} }
45 * { query structure - see {@link QueryStatement} },
46 * { query structure - see {@link QueryStatement} },
49 * { query structure - see {@link QueryStatement} },
53 * { aggregation structure - see {@link AggregationStatement} },
54 * { aggregation structure - see {@link AggregationStatement} },
57 * { aggregation structure - see {@link AggregationStatement} },
62 public class SearchStatement {
65 * Defines the filters that should be applied before running the
66 * actual queries. This is optional.
68 private Filter filter;
71 * The list of queries to be applied to the document store.
73 private Query[] queries;
76 * The list of aggregations to be applied to the search
78 private Aggregation[] aggregations;
81 * Defines the sort criteria to apply to the query result set.
86 @JsonProperty("results-start")
87 private Integer resultsStart;
89 @JsonProperty("results-size")
92 public Filter getFilter() {
96 public void setFilter(Filter filter) {
100 public Query[] getQueries() {
104 public void setQueries(Query[] queries) {
105 this.queries = queries;
108 public Sort getSort() {
112 public void setSort(Sort sort) {
116 public boolean isFiltered() {
117 return filter != null;
120 public Aggregation[] getAggregations() {
124 public void setAggregations(Aggregation[] aggregations) {
125 this.aggregations = aggregations;
128 public boolean hasAggregations() {
129 return aggregations != null && aggregations.length > 0;
132 public Integer getFrom() {
136 public void setFrom(Integer from) {
137 this.resultsStart = from;
140 public Integer getSize() {
144 public void setSize(Integer size) {
149 * This method returns a string which represents this statement in syntax
150 * that is understandable by ElasticSearch and is suitable for inclusion
151 * in an ElasticSearch query string.
153 * @return - ElasticSearch syntax string.
155 public String toElasticSearch() {
157 StringBuilder sb = new StringBuilder();
158 List<QueryStatement> notMatchQueries = new ArrayList<QueryStatement>();
159 List<QueryStatement> mustQueries = new ArrayList<QueryStatement>();
160 List<QueryStatement> shouldQueries = new ArrayList<QueryStatement>();
162 createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
166 sb.append("\"version\": true,");
168 // If the client has specified an index into the results for the first
169 // document in the result set then include that in the ElasticSearch
171 if (resultsStart != null) {
172 sb.append("\"from\": ").append(resultsStart).append(", ");
175 // If the client has specified a maximum number of documents to be returned
176 // in the result set then include that in the ElasticSearch query.
178 sb.append("\"size\": ").append(size).append(", ");
181 sb.append("\"query\": {");
182 sb.append("\"bool\": {");
184 sb.append("\"must\": [");
185 AtomicBoolean firstQuery = new AtomicBoolean(true);
186 for (QueryStatement query : mustQueries) {
188 if (!firstQuery.compareAndSet(true, false)) {
192 sb.append(query.toElasticSearch());
196 sb.append("\"should\": [");
198 firstQuery = new AtomicBoolean(true);
199 for (QueryStatement query : shouldQueries) {
201 if (!firstQuery.compareAndSet(true, false)) {
205 sb.append(query.toElasticSearch());
208 sb.append("],"); // close should list
210 sb.append("\"must_not\": [");
211 firstQuery.set(true);
212 for (QueryStatement query : notMatchQueries) {
213 sb.append(query.toElasticSearch());
217 // Add the filter stanza, if one is required.
219 sb.append(", \"filter\": ").append(filter.toElasticSearch());
222 sb.append("}"); // close bool clause
223 sb.append("}"); // close query clause
225 // Add the sort directive, if one is required.
227 sb.append(", \"sort\": ").append(sort.toElasticSearch());
231 if (hasAggregations()) {
232 sb.append(", \"aggs\": {");
234 for (int i = 0; i < aggregations.length; i++) {
238 sb.append(aggregations[i].toElasticSearch());
246 Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
247 return sb.toString();
250 private void createQueryLists(Query[] queries, List<QueryStatement> mustList,
251 List<QueryStatement> mayList, List<QueryStatement> mustNotList) {
253 for (Query query : queries) {
255 if (query.isMust()) {
257 if (query.getQueryStatement().isNotMatch()) {
258 mustNotList.add(query.getQueryStatement());
260 mustList.add(query.getQueryStatement());
264 if (query.getQueryStatement().isNotMatch()) {
265 mustNotList.add(query.getQueryStatement());
267 mayList.add(query.getQueryStatement());
275 public String toString() {
277 StringBuilder sb = new StringBuilder();
279 sb.append("SEARCH STATEMENT: {");
282 sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
285 if (filter != null) {
286 sb.append("filter: ").append(filter.toString()).append(", ");
289 sb.append("queries: [");
290 AtomicBoolean firstQuery = new AtomicBoolean(true);
291 if (queries != null) {
292 for (Query query : queries) {
294 if (!firstQuery.compareAndSet(true, false)) {
297 sb.append(query.toString());
302 sb.append("aggregations: [");
303 firstQuery = new AtomicBoolean(true);
305 if (aggregations != null) {
306 for (Aggregation agg : aggregations) {
308 if (!firstQuery.compareAndSet(true, false)) {
311 sb.append(agg.toString());
318 return sb.toString();