Skip to content

Add a VSConfig resolver for aggregations not using the registry #53038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ protected final ArrayValuesSourceAggregatorFactory doBuild(QueryShardContext que
protected Map<String, ValuesSourceConfig> resolveConfig(QueryShardContext queryShardContext) {
HashMap<String, ValuesSourceConfig> configs = new HashMap<>();
for (String field : fields) {
ValuesSourceConfig config = ValuesSourceConfig.resolve(queryShardContext, userValueTypeHint, field, null, missingMap.get(field),
null, format, CoreValuesSourceType.BYTES, "");
ValuesSourceConfig config = ValuesSourceConfig.resolveUnregistered(queryShardContext, userValueTypeHint, field, null,
missingMap.get(field), null, format, CoreValuesSourceType.BYTES);
configs.put(field, config);
}
return configs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ protected abstract CompositeValuesSourceConfig innerBuild(QueryShardContext quer
ValuesSourceConfig config) throws IOException;

public final CompositeValuesSourceConfig build(QueryShardContext queryShardContext) throws IOException {
ValuesSourceConfig config = ValuesSourceConfig.resolve(queryShardContext,
valueType, field, script, null, timeZone(), format, CoreValuesSourceType.BYTES, name());
ValuesSourceConfig config = ValuesSourceConfig.resolveUnregistered(queryShardContext,
valueType, field, script, null, timeZone(), format, CoreValuesSourceType.BYTES);
return innerBuild(queryShardContext, config);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,8 @@ protected final MultiValuesSourceAggregatorFactory doBuild(QueryShardContext que
Builder subFactoriesBuilder) throws IOException {
Map<String, ValuesSourceConfig> configs = new HashMap<>(fields.size());
fields.forEach((key, value) -> {
ValuesSourceConfig config = ValuesSourceConfig.resolve(queryShardContext, userValueTypeHint,
value.getFieldName(), value.getScript(), value.getMissing(), value.getTimeZone(), format, defaultValueSourceType(),
getType());
ValuesSourceConfig config = ValuesSourceConfig.resolveUnregistered(queryShardContext, userValueTypeHint,
value.getFieldName(), value.getScript(), value.getMissing(), value.getTimeZone(), format, defaultValueSourceType());
configs.put(key, config);
});
DocValueFormat docValueFormat = resolveFormat(format, userValueTypeHint, defaultValueSourceType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@

import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
import org.elasticsearch.index.fielddata.IndexHistogramFieldData;
import org.elasticsearch.index.fielddata.IndexNumericFieldData;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.RangeFieldMapper;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.script.AggregationScript;
import org.elasticsearch.script.Script;
Expand Down Expand Up @@ -61,6 +65,50 @@ public static ValuesSourceConfig resolve(QueryShardContext context,
String format,
ValuesSourceType defaultValueSourceType,
String aggregationName) {

return internalResolve(context, userValueTypeHint, field, script, missing, timeZone, format, defaultValueSourceType,
aggregationName, ValuesSourceConfig::getMappingFromRegistry);
}

/**
* AKA legacy resolve. This method should be called by aggregations not supported by the {@link ValuesSourceRegistry}, to use the
* pre-registry logic to decide on the {@link ValuesSourceType}. New aggregations which extend from
* {@link ValuesSourceAggregationBuilder} should not use this method, preferring {@link ValuesSourceConfig#resolve} instead.
*
* @param context - the query context
* @param userValueTypeHint - User specified value type; used for missing values and scripts
* @param field - The field being aggregated over. At least one of field and script must not be null
* @param script - The script the user specified. At least one of field and script must not be null
* @param missing - A user specified value to apply when the field is missing. Should be of type userValueTypeHint
* @param timeZone - Used to generate a format for dates
* @param format - The format string to apply to this field. Confusingly, this is used for input parsing as well as output formatting
* See https://github.com/elastic/elasticsearch/issues/47469
* @param defaultValueSourceType - per-aggregation {@link ValuesSource} of last resort.
* @return - An initialized {@link ValuesSourceConfig} that will yield the appropriate {@link ValuesSourceType}
*/
public static ValuesSourceConfig resolveUnregistered(QueryShardContext context,
ValueType userValueTypeHint,
String field,
Script script,
Object missing,
ZoneId timeZone,
String format,
ValuesSourceType defaultValueSourceType) {
return internalResolve(context, userValueTypeHint, field, script, missing, timeZone, format, defaultValueSourceType, null,
ValuesSourceConfig::getLegacyMapping);
}

private static ValuesSourceConfig internalResolve(QueryShardContext context,
ValueType userValueTypeHint,
String field,
Script script,
Object missing,
ZoneId timeZone,
String format,
ValuesSourceType defaultValueSourceType,
String aggregationName,
FieldResolver fieldResolver
) {
ValuesSourceConfig config;
MappedFieldType fieldType = null;
ValuesSourceType valuesSourceType;
Expand Down Expand Up @@ -105,10 +153,8 @@ public static ValuesSourceConfig resolve(QueryShardContext context,
scriptValueType = userValueTypeHint;
}
} else {
IndexFieldData<?> indexFieldData = context.getForField(fieldType);
valuesSourceType = context.getValuesSourceRegistry().getValuesSourceType(fieldType, aggregationName, indexFieldData,
userValueTypeHint, script, defaultValueSourceType);

valuesSourceType = fieldResolver.getValuesSourceType(context, fieldType, aggregationName, userValueTypeHint,
defaultValueSourceType);
aggregationScript = createScript(script, context);
}
}
Expand All @@ -119,6 +165,53 @@ public static ValuesSourceConfig resolve(QueryShardContext context,
return config;
}

@FunctionalInterface
private interface FieldResolver {
ValuesSourceType getValuesSourceType(
QueryShardContext context,
MappedFieldType fieldType,
String aggregationName,
ValueType userValueTypeHint,
ValuesSourceType defaultValuesSourceType);

}

private static ValuesSourceType getMappingFromRegistry(
QueryShardContext context,
MappedFieldType fieldType,
String aggregationName,
ValueType userValueTypeHint,
ValuesSourceType defaultValuesSourceType) {
IndexFieldData<?> indexFieldData = context.getForField(fieldType);
return context.getValuesSourceRegistry().getValuesSourceType(fieldType, aggregationName, indexFieldData,
userValueTypeHint, defaultValuesSourceType);
}

private static ValuesSourceType getLegacyMapping(
QueryShardContext context,
MappedFieldType fieldType,
String aggregationName,
ValueType userValueTypeHint,
ValuesSourceType defaultValuesSourceType) {
IndexFieldData<?> indexFieldData = context.getForField(fieldType);
if (indexFieldData instanceof IndexNumericFieldData) {
return CoreValuesSourceType.NUMERIC;
} else if (indexFieldData instanceof IndexGeoPointFieldData) {
return CoreValuesSourceType.GEOPOINT;
} else if (fieldType instanceof RangeFieldMapper.RangeFieldType) {
return CoreValuesSourceType.RANGE;
} else if (indexFieldData instanceof IndexHistogramFieldData) {
return CoreValuesSourceType.HISTOGRAM;
} else {
if (userValueTypeHint == null) {
return defaultValuesSourceType;
} else {
return userValueTypeHint.getValuesSourceType();
}
}

}

private static AggregationScript.LeafFactory createScript(Script script, QueryShardContext context) {
if (script == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.RangeFieldMapper;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.aggregations.AggregationExecutionException;

Expand Down Expand Up @@ -141,7 +140,7 @@ public AggregatorSupplier getAggregator(ValuesSourceType valuesSourceType, Strin
public ValuesSourceType getValuesSourceType(MappedFieldType fieldType, String aggregationName,
// TODO: the following arguments are only needed for the legacy case
IndexFieldData indexFieldData,
ValueType valueType, Script script,
ValueType valueType,
ValuesSourceType defaultValuesSourceType) {
if (aggregationName != null && aggregatorRegistry.containsKey(aggregationName)) {
// This will throw if the field doesn't support values sources, although really we probably threw much earlier in that case
Expand Down