Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
polyfractal committed Oct 14, 2019
1 parent d7ae6de commit 0299689
Show file tree
Hide file tree
Showing 6 changed files with 518 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.xpack.analytics.metricselector.InternalMetricSelector;
import org.elasticsearch.xpack.analytics.metricselector.MetricSelectorAggregationBuilder;
import org.elasticsearch.xpack.core.XPackPlugin;
import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
import org.elasticsearch.xpack.core.action.XPackUsageFeatureAction;
Expand Down Expand Up @@ -52,4 +54,14 @@ public List<PipelineAggregationSpec> getPipelineAggregations() {
new ActionHandler<>(XPackInfoFeatureAction.ANALYTICS, AnalyticsInfoTransportAction.class),
new ActionHandler<>(AnalyticsStatsAction.INSTANCE, TransportAnalyticsStatsAction.class));
}

@Override
public List<AggregationSpec> getAggregations() {
return singletonList(
new AggregationSpec(
MetricSelectorAggregationBuilder.NAME,
MetricSelectorAggregationBuilder::new,
MetricSelectorAggregationBuilder::parse).addResultReader(InternalMetricSelector::new)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.analytics.metricselector;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.metrics.WeightedAvg;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class InternalMetricSelector extends InternalNumericMetricsAggregation.SingleValue implements WeightedAvg {
private final double value;
private final double sort;
private final SelectionCriteria selectionCriteria;

public static final ParseField SORT_FIELD = new ParseField("sort");
public static final ParseField SORT_FIELD_AS_STRING = new ParseField("sort_as_string");

InternalMetricSelector(String name, double value, double sort, SelectionCriteria selectionCriteria,
DocValueFormat format, List<PipelineAggregator> pipelineAggregators,
Map<String, Object> metaData) {
super(name, pipelineAggregators, metaData);
this.value = value;
this.sort = sort;
this.format = format;
this.selectionCriteria = selectionCriteria;
}

/**
* Read from a stream.
*/
public InternalMetricSelector(StreamInput in) throws IOException {
super(in);
format = in.readNamedWriteable(DocValueFormat.class);
value = in.readDouble();
sort = in.readDouble();
selectionCriteria = SelectionCriteria.fromStream(in);
}

@Override
protected void doWriteTo(StreamOutput out) throws IOException {
out.writeNamedWriteable(format);
out.writeDouble(value);
out.writeDouble(sort);
if (selectionCriteria != null) {
selectionCriteria.writeTo(out);
}
}

@Override
public double value() {
return getValue();
}

@Override
public double getValue() {
return value;
}

double getSort() {
return sort;
}
DocValueFormat getFormatter() {
return format;
}

@Override
public String getWriteableName() {
return MetricSelectorAggregationBuilder.NAME;
}

@Override
public InternalMetricSelector doReduce(List<InternalAggregation> aggregations, ReduceContext reduceContext) {
Double bestValue = null;
Double bestSort = null;

for (InternalAggregation aggregation : aggregations) {
InternalMetricSelector metric = (InternalMetricSelector) aggregation;
if (bestValue == null) {
bestValue = metric.getValue();
bestSort = metric.getSort();
} else {
if (metric.getSort() == selectionCriteria.select(bestSort, metric.getSort())) {
bestSort = metric.getSort();
bestValue = metric.getValue();
}
}
}
return new InternalMetricSelector(getName(), bestValue == null ? Double.NaN : bestValue,
bestSort == null ? Double.NaN : bestSort, selectionCriteria, format, pipelineAggregators(), getMetaData());
}
@Override
public XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException {
builder.field(CommonFields.VALUE.getPreferredName(), Double.isNaN(value) ? null : getValue());
builder.field(SORT_FIELD.getPreferredName(), Double.isNaN(sort) ? null : getSort());

String keyAsString = format.format(getSort()).toString();
if (format != DocValueFormat.RAW) {
builder.field(SORT_FIELD_AS_STRING.getPreferredName(), keyAsString);
}
return builder;
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode(), value, sort, format.getWriteableName());
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
if (super.equals(obj) == false) return false;
InternalMetricSelector other = (InternalMetricSelector) obj;
return Objects.equals(value, other.value) &&
Objects.equals(sort, other.sort) &&
Objects.equals(format.getWriteableName(), other.format.getWriteableName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.analytics.metricselector;

import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.MultiValueMode;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorFactories;
import org.elasticsearch.search.aggregations.AggregatorFactory;
import org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregationBuilder;
import org.elasticsearch.search.aggregations.support.MultiValuesSourceAggregatorFactory;
import org.elasticsearch.search.aggregations.support.MultiValuesSourceFieldConfig;
import org.elasticsearch.search.aggregations.support.MultiValuesSourceParseHelper;
import org.elasticsearch.search.aggregations.support.ValueType;
import org.elasticsearch.search.aggregations.support.ValuesSource;
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;

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

public class MetricSelectorAggregationBuilder extends MultiValuesSourceAggregationBuilder.LeafOnly<ValuesSource.Numeric, MetricSelectorAggregationBuilder> {
public static final String NAME = "metric_selector";
public static final ParseField METRIC_FIELD = new ParseField("metric_field");
public static final ParseField SELECTOR_FIELD = new ParseField("selector_field");
public static final ParseField MULTIVALUE_MODE_FIELD = new ParseField("multi_value_mode");

private SelectionCriteria selectionCriteria = SelectionCriteria.MAX;
private MultiValueMode multiValueMode = MultiValueMode.AVG;

private static final ObjectParser<MetricSelectorAggregationBuilder, Void> PARSER;
static {
PARSER = new ObjectParser<>(MetricSelectorAggregationBuilder.NAME);
MultiValuesSourceParseHelper.declareCommon(PARSER, true, ValueType.NUMERIC);
MultiValuesSourceParseHelper.declareField(METRIC_FIELD.getPreferredName(), PARSER, true, false);
MultiValuesSourceParseHelper.declareField(SELECTOR_FIELD.getPreferredName(), PARSER, true, false);
PARSER.declareString(MetricSelectorAggregationBuilder::selectionCriteria, SelectionCriteria.SELECTION_CRITERIA);
PARSER.declareString(MetricSelectorAggregationBuilder::multiValueMode, MULTIVALUE_MODE_FIELD);
}

public static AggregationBuilder parse(String aggregationName, XContentParser parser) throws IOException {
return PARSER.parse(parser, new MetricSelectorAggregationBuilder(aggregationName), null);
}

public MetricSelectorAggregationBuilder(String name) {
super(name, ValueType.NUMERIC);
}

public MetricSelectorAggregationBuilder(MetricSelectorAggregationBuilder clone, AggregatorFactories.Builder factoriesBuilder, Map<String, Object> metaData) {
super(clone, factoriesBuilder, metaData);
}

public MetricSelectorAggregationBuilder metricField(MultiValuesSourceFieldConfig metricConfig) {
metricConfig = Objects.requireNonNull(metricConfig, "Configuration for field [" + METRIC_FIELD + "] cannot be null");
field(METRIC_FIELD.getPreferredName(), metricConfig);
return this;
}

public MetricSelectorAggregationBuilder selectorField(MultiValuesSourceFieldConfig selectorConfig) {
selectorConfig = Objects.requireNonNull(selectorConfig, "Configuration for field [" + SELECTOR_FIELD + "] cannot be null");
field(SELECTOR_FIELD.getPreferredName(), selectorConfig);
return this;
}

public MetricSelectorAggregationBuilder selectionCriteria(String criteria) {
this.selectionCriteria = SelectionCriteria.fromString(criteria);
return this;
}

public MetricSelectorAggregationBuilder multiValueMode(String mode) {
this.multiValueMode = MultiValueMode.fromString(mode);
return this;
}

/**
* Read from a stream.
*/
public MetricSelectorAggregationBuilder(StreamInput in) throws IOException {
super(in, ValueType.NUMERIC);
}

@Override
protected AggregationBuilder shallowCopy(AggregatorFactories.Builder factoriesBuilder, Map<String, Object> metaData) {
return new MetricSelectorAggregationBuilder(this, factoriesBuilder, metaData);
}

@Override
protected void innerWriteTo(StreamOutput out) throws IOException {
multiValueMode.writeTo(out);
selectionCriteria.writeTo(out);
}

@Override
protected MultiValuesSourceAggregatorFactory<ValuesSource.Numeric> innerBuild(QueryShardContext queryShardContext,
Map<String, ValuesSourceConfig<ValuesSource.Numeric>> configs,
DocValueFormat format,
AggregatorFactory parent,
AggregatorFactories.Builder subFactoriesBuilder) throws IOException {
return new MetricSelectorAggregatorFactory(name, configs, format, selectionCriteria, multiValueMode,
queryShardContext, parent, subFactoriesBuilder, metaData);
}

@Override
public XContentBuilder doXContentBody(XContentBuilder builder, ToXContent.Params params) throws IOException {
builder.field(MULTIVALUE_MODE_FIELD.getPreferredName(), multiValueMode);
builder.field(SelectionCriteria.SELECTION_CRITERIA.getPreferredName(), selectionCriteria);
return builder;
}

@Override
public String getType() {
return NAME;
}
}
Loading

0 comments on commit 0299689

Please sign in to comment.