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

org.elasticsearch.xpack.core.ml.datafeed.AggProvider Maven / Gradle / Ivy

/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */
package org.elasticsearch.xpack.core.ml.datafeed;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.Version;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.xpack.core.ml.job.messages.Messages;
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
import org.elasticsearch.xpack.core.ml.utils.XContentObjectTransformer;

import java.io.IOException;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

class AggProvider implements Writeable, ToXContentObject {

    private static final Logger logger = LogManager.getLogger(AggProvider.class);

    private Exception parsingException;
    private AggregatorFactories.Builder parsedAggs;
    private Map aggs;

    static AggProvider fromXContent(XContentParser parser, boolean lenient) throws IOException {
        Map aggs = parser.mapOrdered();
        AggregatorFactories.Builder parsedAggs = null;
        Exception exception = null;
        try {
            if (aggs.isEmpty()) {
                throw new Exception("aggs cannot be empty");
            }
            parsedAggs = XContentObjectTransformer.aggregatorTransformer(parser.getXContentRegistry()).fromMap(aggs);
        } catch(Exception ex) {
            if (ex.getCause() instanceof IllegalArgumentException) {
                ex = (Exception)ex.getCause();
            }
            exception = ex;
            if (lenient) {
                logger.warn(Messages.DATAFEED_CONFIG_AGG_BAD_FORMAT, ex);
            } else {
                throw ExceptionsHelper.badRequestException(Messages.DATAFEED_CONFIG_AGG_BAD_FORMAT, ex);
            }
        }
        return new AggProvider(aggs, parsedAggs, exception);
    }

    static AggProvider fromParsedAggs(AggregatorFactories.Builder parsedAggs) throws IOException {
        return parsedAggs == null ?
            null :
            new AggProvider(
                XContentObjectTransformer.aggregatorTransformer(NamedXContentRegistry.EMPTY).toMap(parsedAggs),
                parsedAggs,
                null);
    }

    static AggProvider fromStream(StreamInput in) throws IOException {
        if (in.getVersion().onOrAfter(Version.V_6_7_0)) { // Has our bug fix for query/agg providers
            return new AggProvider(in.readMap(), in.readOptionalWriteable(AggregatorFactories.Builder::new), in.readException());
        } else if (in.getVersion().onOrAfter(Version.V_6_6_0)) { // Has the bug, but supports lazy objects
            return new AggProvider(in.readMap(), null, null);
        } else { // only supports eagerly parsed objects
            // Upstream, we have read the bool already and know for sure that we have parsed aggs in the stream
            return AggProvider.fromParsedAggs(new AggregatorFactories.Builder(in));
        }
    }

    AggProvider(Map aggs, AggregatorFactories.Builder parsedAggs, Exception parsingException) {
        this.aggs = Collections.unmodifiableMap(new LinkedHashMap<>(Objects.requireNonNull(aggs, "[aggs] must not be null")));
        this.parsedAggs = parsedAggs;
        this.parsingException = parsingException;
    }

    AggProvider(AggProvider other) {
        this.aggs = new LinkedHashMap<>(other.aggs);
        this.parsedAggs = other.parsedAggs;
        this.parsingException = other.parsingException;
    }

    @Override
    public void writeTo(StreamOutput out) throws IOException {
        if (out.getVersion().onOrAfter(Version.V_6_7_0)) { // Has our bug fix for query/agg providers
            out.writeMap(aggs);
            out.writeOptionalWriteable(parsedAggs);
            out.writeException(parsingException);
        } else if (out.getVersion().onOrAfter(Version.V_6_6_0)) { // Has the bug, but supports lazy objects
            // We allow the lazy parsing nodes that have the bug throw any parsing errors themselves as
            // they already have the ability to fully parse the passed Maps
            out.writeMap(aggs);
        } else { // only supports eagerly parsed objects
            if (parsingException != null) {
                if (parsingException instanceof IOException) {
                    throw (IOException) parsingException;
                } else {
                    throw new ElasticsearchException(parsingException);
                }
            } else if (parsedAggs == null) {
                // This is an admittedly rare case but we should fail early instead of writing null when there
                // actually are aggregations defined
                throw new ElasticsearchException("Unsupported operation: parsed aggregations are null");
            }
            // Upstream we already verified that this calling object is not null, no need to write a second boolean to the stream
            parsedAggs.writeTo(out);
        }
    }

    public Exception getParsingException() {
        return parsingException;
    }

    AggregatorFactories.Builder getParsedAggs() {
        return parsedAggs;
    }

    public Map getAggs() {
        return aggs;
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }

        if (other == null || getClass() != other.getClass()) {
            return false;
        }

        AggProvider that = (AggProvider) other;

        return Objects.equals(this.aggs, that.aggs)
            && Objects.equals(this.parsedAggs, that.parsedAggs)
            && Objects.equals(this.parsingException, that.parsingException);
    }

    @Override
    public int hashCode() {
        return Objects.hash(aggs, parsedAggs, parsingException);
    }

    @Override
    public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
        builder.map(aggs);
        return builder;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy