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 java.util.ArrayList;
25 import java.util.List;
26 import java.util.concurrent.atomic.AtomicBoolean;
27 import org.radeox.util.logging.Logger;
30 * This class represents the structure of a search statement.
33 * 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 actual queries. This is optional.
69 private Filter filter;
72 * The list of queries to be applied to the document store.
74 private Query[] queries;
77 * The list of aggregations to be applied to the search
79 private Aggregation[] aggregations;
82 * Defines the sort criteria to apply to the query result set. This is optional.
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 that is understandable by ElasticSearch
150 * and is suitable for inclusion in an ElasticSearch query string.
152 * @return - ElasticSearch syntax string.
154 public String toElasticSearch() {
155 StringBuilder sb = new StringBuilder();
156 List<QueryStatement> notMatchQueries = new ArrayList<>();
157 List<QueryStatement> mustQueries = new ArrayList<>();
158 List<QueryStatement> shouldQueries = new ArrayList<>();
160 createQueryLists(queries, mustQueries, shouldQueries, notMatchQueries);
164 sb.append("\"version\": true,");
166 // If the client has specified an index into the results for the first
167 // document in the result set then include that in the ElasticSearch
169 if (resultsStart != null) {
170 sb.append("\"from\": ").append(resultsStart).append(", ");
173 // If the client has specified a maximum number of documents to be returned
174 // in the result set then include that in the ElasticSearch query.
176 sb.append("\"size\": ").append(size).append(", ");
179 sb.append("\"query\": {");
180 sb.append("\"bool\": {");
182 sb.append("\"must\": [");
183 AtomicBoolean firstQuery = new AtomicBoolean(true);
184 for (QueryStatement query : mustQueries) {
186 if (!firstQuery.compareAndSet(true, false)) {
190 sb.append(query.toElasticSearch());
194 sb.append("\"should\": [");
196 firstQuery = new AtomicBoolean(true);
197 for (QueryStatement query : shouldQueries) {
199 if (!firstQuery.compareAndSet(true, false)) {
203 sb.append(query.toElasticSearch());
206 sb.append("],"); // close should list
208 sb.append("\"must_not\": [");
209 firstQuery.set(true);
210 for (QueryStatement query : notMatchQueries) {
211 sb.append(query.toElasticSearch());
215 // Add the filter stanza, if one is required.
217 sb.append(", \"filter\": ").append(filter.toElasticSearch());
220 sb.append("}"); // close bool clause
221 sb.append("}"); // close query clause
223 // Add the sort directive, if one is required.
225 sb.append(", \"sort\": ").append(sort.toElasticSearch());
229 if (hasAggregations()) {
230 sb.append(", \"aggs\": {");
232 for (int i = 0; i < aggregations.length; i++) {
236 sb.append(aggregations[i].toElasticSearch());
244 Logger.debug("Generated raw ElasticSearch query statement: " + sb.toString());
245 return sb.toString();
248 private void createQueryLists(Query[] queries, List<QueryStatement> mustList, List<QueryStatement> mayList,
249 List<QueryStatement> mustNotList) {
251 for (Query query : queries) {
253 if (query.isMust()) {
255 if (query.getQueryStatement().isNotMatch()) {
256 mustNotList.add(query.getQueryStatement());
258 mustList.add(query.getQueryStatement());
262 if (query.getQueryStatement().isNotMatch()) {
263 mustNotList.add(query.getQueryStatement());
265 mayList.add(query.getQueryStatement());
273 public String toString() {
275 StringBuilder sb = new StringBuilder();
277 sb.append("SEARCH STATEMENT: {");
280 sb.append("from: ").append(resultsStart).append(", size: ").append(size).append(", ");
283 if (filter != null) {
284 sb.append("filter: ").append(filter.toString()).append(", ");
287 sb.append("queries: [");
288 AtomicBoolean firstQuery = new AtomicBoolean(true);
289 if (queries != null) {
290 for (Query query : queries) {
292 if (!firstQuery.compareAndSet(true, false)) {
295 sb.append(query.toString());
300 sb.append("aggregations: [");
301 firstQuery = new AtomicBoolean(true);
303 if (aggregations != null) {
304 for (Aggregation agg : aggregations) {
306 if (!firstQuery.compareAndSet(true, false)) {
309 sb.append(agg.toString());
316 return sb.toString();