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

org.elasticsearch.search.aggregations.support.AggregationContext Maven / Gradle / Ivy

There is a newer version: 8.14.1
Show newest version
/*
 * 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.search.aggregations.support;

import org.apache.lucene.util.BytesRef;
import org.elasticsearch.cache.recycler.PageCacheRecycler;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.geo.GeoUtils;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.fielddata.IndexOrdinalsFieldData;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.core.DateFieldMapper;
import org.elasticsearch.search.SearchParseException;
import org.elasticsearch.search.aggregations.AggregationExecutionException;
import org.elasticsearch.search.internal.SearchContext;

import java.io.IOException;

/**
 *
 */
public class AggregationContext {

    private final SearchContext searchContext;

    public AggregationContext(SearchContext searchContext) {
        this.searchContext = searchContext;
    }

    public SearchContext searchContext() {
        return searchContext;
    }

    public PageCacheRecycler pageCacheRecycler() {
        return searchContext.pageCacheRecycler();
    }

    public BigArrays bigArrays() {
        return searchContext.bigArrays();
    }

    /** Get a value source given its configuration. A return value of null indicates that
     *  no value source could be built. */
    @Nullable
    public  VS valuesSource(ValuesSourceConfig config, SearchContext context) throws IOException {
        assert config.valid() : "value source config is invalid - must have either a field context or a script or marked as unmapped";

        final VS vs;
        if (config.unmapped) {
            if (config.missing == null) {
                // otherwise we will have values because of the missing value
                vs = null;
            } else if (ValuesSource.Numeric.class.isAssignableFrom(config.valueSourceType)) {
                vs = (VS) ValuesSource.Numeric.EMPTY;
            } else if (ValuesSource.GeoPoint.class.isAssignableFrom(config.valueSourceType)) {
                vs = (VS) ValuesSource.GeoPoint.EMPTY;
            } else if (ValuesSource.class.isAssignableFrom(config.valueSourceType)
                    || ValuesSource.Bytes.class.isAssignableFrom(config.valueSourceType)
                    || ValuesSource.Bytes.WithOrdinals.class.isAssignableFrom(config.valueSourceType)) {
                vs = (VS) ValuesSource.Bytes.EMPTY;
            } else {
                throw new SearchParseException(searchContext, "Can't deal with unmapped ValuesSource type " + config.valueSourceType, null);
            }
        } else {
            vs = originalValuesSource(config);
        }

        if (config.missing == null) {
            return vs;
        }

        if (vs instanceof ValuesSource.Bytes) {
            final BytesRef missing = new BytesRef(config.missing.toString());
            if (vs instanceof ValuesSource.Bytes.WithOrdinals) {
                return (VS) MissingValues.replaceMissing((ValuesSource.Bytes.WithOrdinals) vs, missing);
            } else {
                return (VS) MissingValues.replaceMissing((ValuesSource.Bytes) vs, missing);
            }
        } else if (vs instanceof ValuesSource.Numeric) {
            Number missing = null;
            if (config.missing instanceof Number) {
                missing = (Number) config.missing;
            } else {
                if (config.fieldContext != null && config.fieldContext.fieldType() instanceof DateFieldMapper.DateFieldType) {
                    final DateFieldMapper.DateFieldType fieldType = (DateFieldMapper.DateFieldType) config.fieldContext.fieldType();
                    try {
                        missing = fieldType.dateTimeFormatter().parser().parseDateTime(config.missing.toString()).getMillis();
                    } catch (IllegalArgumentException e) {
                        throw new SearchParseException(context, "Expected a date value in [missing] but got [" + config.missing + "]", null, e);
                    }
                } else {
                    try {
                        missing = Double.parseDouble(config.missing.toString());
                    } catch (NumberFormatException e) {
                        throw new SearchParseException(context, "Expected a numeric value in [missing] but got [" + config.missing + "]", null, e);
                    }
                }
            }
            return (VS) MissingValues.replaceMissing((ValuesSource.Numeric) vs, missing);
        } else if (vs instanceof ValuesSource.GeoPoint) {
            // TODO: also support the structured formats of geo points
            final GeoPoint missing = GeoUtils.parseGeoPoint(config.missing.toString(), new GeoPoint());
            return (VS) MissingValues.replaceMissing((ValuesSource.GeoPoint) vs, missing);
        } else {
            // Should not happen
            throw new SearchParseException(searchContext, "Can't apply missing values on a " + vs.getClass(), null);
        }
    }

    /**
     * Return the original values source, before we apply `missing`.
     */
    private  VS originalValuesSource(ValuesSourceConfig config) throws IOException {
        if (config.fieldContext == null) {
            if (ValuesSource.Numeric.class.isAssignableFrom(config.valueSourceType)) {
                return (VS) numericScript(config);
            }
            if (ValuesSource.Bytes.class.isAssignableFrom(config.valueSourceType)) {
                return (VS) bytesScript(config);
            }
            throw new AggregationExecutionException("value source of type [" + config.valueSourceType.getSimpleName() + "] is not supported by scripts");
        }

        if (ValuesSource.Numeric.class.isAssignableFrom(config.valueSourceType)) {
            return (VS) numericField(config);
        }
        if (ValuesSource.GeoPoint.class.isAssignableFrom(config.valueSourceType)) {
            return (VS) geoPointField(config);
        }
        // falling back to bytes values
        return (VS) bytesField(config);
    }

    private ValuesSource.Numeric numericScript(ValuesSourceConfig config) throws IOException {
        return new ValuesSource.Numeric.Script(config.script, config.scriptValueType);
    }

    private ValuesSource.Numeric numericField(ValuesSourceConfig config) throws IOException {

        if (!(config.fieldContext.indexFieldData() instanceof IndexNumericFieldData)) {
            throw new IllegalArgumentException("Expected numeric type on field [" + config.fieldContext.field() +
                    "], but got [" + config.fieldContext.fieldType().typeName() + "]");
        }

        ValuesSource.Numeric dataSource = new ValuesSource.Numeric.FieldData((IndexNumericFieldData) config.fieldContext.indexFieldData());
        if (config.script != null) {
            dataSource = new ValuesSource.Numeric.WithScript(dataSource, config.script);
        }
        return dataSource;
    }

    private ValuesSource bytesField(ValuesSourceConfig config) throws IOException {
        final IndexFieldData indexFieldData = config.fieldContext.indexFieldData();
        ValuesSource dataSource;
        if (indexFieldData instanceof ParentChildIndexFieldData) {
            dataSource = new ValuesSource.Bytes.WithOrdinals.ParentChild((ParentChildIndexFieldData) indexFieldData);
        } else if (indexFieldData instanceof IndexOrdinalsFieldData) {
            dataSource = new ValuesSource.Bytes.WithOrdinals.FieldData((IndexOrdinalsFieldData) indexFieldData);
        } else {
            dataSource = new ValuesSource.Bytes.FieldData(indexFieldData);
        }
        if (config.script != null) {
            dataSource = new ValuesSource.WithScript(dataSource, config.script);
        }
        return dataSource;
    }

    private ValuesSource.Bytes bytesScript(ValuesSourceConfig config) throws IOException {
        return new ValuesSource.Bytes.Script(config.script);
    }

    private ValuesSource.GeoPoint geoPointField(ValuesSourceConfig config) throws IOException {

        if (!(config.fieldContext.indexFieldData() instanceof IndexGeoPointFieldData)) {
            throw new IllegalArgumentException("Expected geo_point type on field [" + config.fieldContext.field() +
                    "], but got [" + config.fieldContext.fieldType().typeName() + "]");
        }

        return new ValuesSource.GeoPoint.Fielddata((IndexGeoPointFieldData) config.fieldContext.indexFieldData());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy