All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.hadoop.rest.SearchRequestBuilder Maven / Gradle / Ivy

/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.hadoop.rest;

import org.elasticsearch.hadoop.rest.query.BoolQueryBuilder;
import org.elasticsearch.hadoop.rest.query.FilteredQueryBuilder;
import org.elasticsearch.hadoop.rest.query.MatchAllQueryBuilder;
import org.elasticsearch.hadoop.rest.query.QueryBuilder;
import org.elasticsearch.hadoop.serialization.ScrollReader;
import org.elasticsearch.hadoop.serialization.json.JacksonJsonGenerator;
import org.elasticsearch.hadoop.util.Assert;
import org.elasticsearch.hadoop.util.BytesArray;
import org.elasticsearch.hadoop.util.EsMajorVersion;
import org.elasticsearch.hadoop.util.FastByteArrayOutputStream;
import org.elasticsearch.hadoop.util.StringUtils;
import org.elasticsearch.hadoop.util.encoding.HttpEncodingTools;
import org.elasticsearch.hadoop.util.unit.TimeValue;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * A search request builder which allows building {@link ScrollQuery}
 */
public class SearchRequestBuilder {
    private static class Slice {
        final int id;
        final int max;

        Slice(int id, int max) {
            this.id = id;
            this.max = max;
        }
    }

    private final EsMajorVersion version;
    private final boolean includeVersion;
    private TimeValue scroll = TimeValue.timeValueMinutes(10);
    private long size = 50;
    private long limit = -1;
    private String indices;
    private String types;
    private String shard;
    private String fields;
    private QueryBuilder query;
    private final List filters = new ArrayList ();
    private String routing;
    private Slice slice;
    private boolean local = false;
    private String preference = "";
    private boolean excludeSource = false;
    private boolean readMetadata = false;

    public SearchRequestBuilder(EsMajorVersion version, boolean includeVersion) {
        this.version = version;
        this.includeVersion = includeVersion;
    }

    public boolean isReadMetadata() {
        return readMetadata;
    }

    public String routing() {
        return routing;
    }

    public List filters() {
        return filters;
    }

    public SearchRequestBuilder resource(Resource resource) {
        this.indices = resource.index();
        if (resource.isTyped()) {
            this.types = resource.type();
        } else {
            this.types = null;
        }
        return this;
    }

    public SearchRequestBuilder indices(String indices) {
        this.indices = indices;
        return this;
    }

    public SearchRequestBuilder query(QueryBuilder builder) {
        this.query = builder;
        return this;
    }

    public QueryBuilder query() {
        return query;
    }

    public SearchRequestBuilder size(long size) {
        this.size = size;
        return this;
    }

    public SearchRequestBuilder limit(long limit) {
        this.limit = limit;
        return this;
    }

    public SearchRequestBuilder scroll(long keepAliveMillis) {
        Assert.isTrue(keepAliveMillis > 0, "Invalid scroll");
        this.scroll = TimeValue.timeValueMillis(keepAliveMillis);
        return this;
    }

    public SearchRequestBuilder shard(String shard) {
        Assert.hasText(shard, "Invalid shard");
        this.shard = shard;
        return this;
    }

    public SearchRequestBuilder fields(String fieldsCSV) {
        Assert.isFalse(this.excludeSource, "Fields can't be requested because _source section is excluded");
        this.fields = fieldsCSV;
        return this;
    }

    public SearchRequestBuilder filter(QueryBuilder filter) {
        this.filters.add(filter);
        return this;
    }

    public SearchRequestBuilder filters(Collection filters) {
        this.filters.addAll(filters);
        return this;
    }

    public SearchRequestBuilder readMetadata(boolean read) {
        this.readMetadata = read;
        return this;
    }

    public SearchRequestBuilder routing(String routing) {
        this.routing = routing;
        return this;
    }

    public SearchRequestBuilder slice(int id, int max) {
        this.slice = new Slice(id, max);
        return this;
    }

    public SearchRequestBuilder local(boolean value) {
        this.local = value;
        return this;
    }

    public SearchRequestBuilder preference(String preference) {
        this.preference = preference;
        return this;
    }

    public SearchRequestBuilder excludeSource(boolean value) {
        if (value) {
            Assert.hasNoText(this.fields, String.format("_source section can't be excluded if fields [%s] are requested", this.fields));
        }
        this.excludeSource = value;
        return this;
    }

    private String assemble() {
        if (limit > 0) {
            if (size > limit) {
                size = limit;
            }
        }
        Map uriParams = new LinkedHashMap();
        StringBuilder sb = new StringBuilder();
        sb.append(indices);
        if (StringUtils.hasLength(types)) {
            sb.append("/");
            sb.append(types);
        }
        sb.append("/_search?");

        // override infrastructure params
        if (version.onOrAfter(EsMajorVersion.V_5_X)) {
            // scan type was removed
            // default to sorting by indexing/doc order
            uriParams.put("sort", "_doc");
        }
        else {
            uriParams.put("search_type", "scan");
        }
        uriParams.put("scroll", String.valueOf(scroll.toString()));
        uriParams.put("size", String.valueOf(size));
        if (includeVersion) {
            uriParams.put("version", "true");
        }

        // set shard preference
        StringBuilder pref = new StringBuilder();
        if (StringUtils.hasText(shard)) {
            pref.append("_shards:");
            pref.append(shard);
        }
        if (local || StringUtils.hasText(preference)) {
            if (pref.length() > 0) {
                if (version.onOrAfter(EsMajorVersion.V_5_X)) {
                    pref.append("|");
                } else {
                    pref.append(";");
                }
            }
            if (StringUtils.hasText(preference)) {
                pref.append(preference);
            } else {
                pref.append("_local");
            }
        }

        if (pref.length() > 0) {
            uriParams.put("preference", HttpEncodingTools.encode(pref.toString()));
        }

        // Request routing
        if (routing != null) {
            uriParams.put("routing", HttpEncodingTools.encode(routing));
        }

        // Always track total hits on versions that support it. 7.0+ will return lower bounded
        // hit counts if this is not set, and we want them to be accurate for scroll bookkeeping.
        if (version.onOrAfter(EsMajorVersion.V_6_X)) {
            uriParams.put("track_total_hits", "true");
        }

        if (readMetadata) {
            uriParams.put("track_scores", "true");
        }

        // append params
        for (Iterator> it = uriParams.entrySet().iterator(); it.hasNext();) {
            Entry entry = it.next();
            sb.append(entry.getKey());
            if (StringUtils.hasText(entry.getValue())) {
                sb.append("=");
                sb.append(entry.getValue());
            }
            if (it.hasNext()) {
                sb.append("&");
            }
        }

        return sb.toString();
    }

    private BytesArray assembleBody() {
        QueryBuilder root = query;
        if (root == null) {
            root = MatchAllQueryBuilder.MATCH_ALL;
        }
        if (filters.isEmpty() == false) {
            if (version.onOrAfter(EsMajorVersion.V_2_X)) {
                root = new BoolQueryBuilder().must(root).filters(filters);
            } else {
                root = new FilteredQueryBuilder().query(root).filters(filters);
            }
        }
        FastByteArrayOutputStream out = new FastByteArrayOutputStream(256);
        JacksonJsonGenerator generator = new JacksonJsonGenerator(out);
        try {
            generator.writeBeginObject();
            if (slice != null && slice.max > 1) {
                generator.writeFieldName("slice");
                generator.writeBeginObject();
                generator.writeFieldName("id");
                generator.writeNumber(slice.id);
                generator.writeFieldName("max");
                generator.writeNumber(slice.max);
                generator.writeEndObject();
            }
            generator.writeFieldName("query");
            generator.writeBeginObject();
            root.toJson(generator);
            generator.writeEndObject();
            // override fields
            if (StringUtils.hasText(fields)) {
                generator.writeFieldName("_source");
                generator.writeBeginArray();
                final List fieldsArray = StringUtils.tokenize(fields, StringUtils.DEFAULT_DELIMITER);
                for (String field : fieldsArray) {
                    generator.writeString(field);
                }
                generator.writeEndArray();
            } else if (excludeSource) {
                generator.writeFieldName("_source");
                generator.writeBoolean(false);
            }
            generator.writeEndObject();
        } finally {
            generator.close();
        }
        return out.bytes();
    }

    public ScrollQuery build(RestRepository client, ScrollReader reader) {
        String scrollUri = assemble();
        BytesArray requestBody = assembleBody();
        return client.scanLimit(scrollUri, requestBody, limit, reader);
    }

    @Override
    public String toString() {
        return "QueryBuilder [" + assemble() + "][" + assembleBody() + "]";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy