/** * Copyright 2015-2017 The OpenZipkin Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package zipkin.storage.elasticsearch.http.internal.client; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public final class SearchRequest { /** * The maximum results returned in a query. This only affects non-aggregation requests. * * <p>Not configurable as it implies adjustments to the index template (index.max_result_window) * * <p> See https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-from-size.html */ static final int MAX_RESULT_WINDOW = 10000; // the default elasticsearch allowed limit transient final List<String> indices; transient final String type; Integer size = MAX_RESULT_WINDOW; Boolean _source; Object query; Map<String, Aggregation> aggs; SearchRequest(List<String> indices, String type) { this.indices = indices; this.type = type; } public static class Filters extends LinkedList<Object> { public Filters addRange(String field, long from, Long to) { add(new Range(field, from, to)); return this; } public Filters addTerm(String field, String value) { add(new Term(field, value)); return this; } public Filters addNestedTerms(Collection<String> nestedFields, String value) { add(_nestedTermsEqual(nestedFields, value)); return this; } public Filters addNestedTerms(Map<String, String>... nestedTerms) { if (nestedTerms.length == 1) { add(mustMatchAllNestedTerms(nestedTerms[0])); return this; } List<NestedBoolQuery> nestedBoolQueries = new ArrayList<>(nestedTerms.length); for (Map<String, String> next : nestedTerms) { nestedBoolQueries.add(mustMatchAllNestedTerms(next)); } add(new SearchRequest.BoolQuery("should", nestedBoolQueries)); return this; } } static NestedBoolQuery mustMatchAllNestedTerms(Map<String, String> next) { List<Term> terms = new ArrayList<>(); String field = null; for (Map.Entry<String, String> nestedTerm : next.entrySet()) { terms.add(new Term(field = nestedTerm.getKey(), nestedTerm.getValue())); } return new NestedBoolQuery(field.substring(0, field.indexOf('.')), "must", terms); } public SearchRequest filters(Filters filters) { return query(new BoolQuery("must", filters)); } static SearchRequest.BoolQuery _nestedTermsEqual(Collection<String> nestedFields, String value) { List<SearchRequest.NestedBoolQuery> conditions = new ArrayList<>(); for (String nestedField : nestedFields) { conditions.add(new NestedBoolQuery(nestedField.substring(0, nestedField.indexOf('.')), "must", new SearchRequest.Term(nestedField, value))); } return new SearchRequest.BoolQuery("should", conditions); } public static SearchRequest forIndicesAndType(List<String> indices, String type) { return new SearchRequest(indices, type); } public SearchRequest term(String field, String value) { return query(new Term(field, value)); } public SearchRequest terms(String field, List<String> values) { return query(new Terms(field, values)); } public SearchRequest addAggregation(Aggregation agg) { size = null; // we return aggs, not source data _source = false; if (aggs == null) aggs = new LinkedHashMap<>(); aggs.put(agg.field, agg); return this; } String tag() { return aggs != null ? "aggregation" : "search"; } SearchRequest query(Object filter) { query = Collections.singletonMap("bool", Collections.singletonMap("filter", filter)); return this; } static class Term { final Map<String, String> term; Term(String field, String value) { term = Collections.singletonMap(field, value); } } static class Terms { final Map<String, List<String>> terms; Terms(String field, List<String> values) { this.terms = Collections.singletonMap(field, values); } } static class Range { final Map<String, Bounds> range; Range(String field, long from, Long to) { range = Collections.singletonMap(field, new Bounds(from, to)); } static class Bounds { final long from; final Long to; final boolean include_lower = true; final boolean include_upper = true; Bounds(long from, Long to) { this.from = from; this.to = to; } } } static class NestedBoolQuery { final Map<String, Object> nested; NestedBoolQuery(String path, String condition, List<Term> terms) { nested = new LinkedHashMap<>(2); nested.put("path", path); nested.put("query", new BoolQuery(condition, terms)); } NestedBoolQuery(String path, String condition, Term term) { nested = new LinkedHashMap<>(2); nested.put("path", path); nested.put("query", new BoolQuery(condition, term)); } } static class BoolQuery { final Map<String, Object> bool; BoolQuery(String op, Object clause) { bool = Collections.singletonMap(op, clause); } } }