Skip to content
Closed
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 @@ -23,6 +23,7 @@
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.xcontent.AbstractObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.action.search.RestSearchAction;
Expand Down Expand Up @@ -193,6 +194,11 @@ public final XContentBuilder toXContent(XContentBuilder builder, Params params)
return builder;
}

protected static void declareCommonField(AbstractObjectParser<Map<String, Object>, Void> parser) {
parser.declareObject((map, metaMap) -> map.put(CommonFields.META.getPreferredName(), metaMap),
(p, c) -> p.map(), CommonFields.META);
}

public abstract XContentBuilder doXContentBody(XContentBuilder builder, Params params) throws IOException;

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,37 @@
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.util.BigArrays;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.DocValueFormat;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class InternalCardinality extends InternalNumericMetricsAggregation.SingleValue implements Cardinality {
public class InternalCardinality extends InternalNumericMetricsAggregation.SingleValue implements Cardinality {
private final HyperLogLogPlusPlus counts;
transient private Long cardinalityValue;

InternalCardinality(String name, HyperLogLogPlusPlus counts, List<PipelineAggregator> pipelineAggregators,
Map<String, Object> metaData) {
super(name, pipelineAggregators, metaData);
this.counts = counts;
}

private InternalCardinality(String name, long cardinalityValue, List<PipelineAggregator> pipelineAggregators,
Map<String, Object> metaData) {
super(name, pipelineAggregators, metaData);
this.counts = null;
this.cardinalityValue = cardinalityValue;
}

/**
* Read from a stream.
*/
Expand Down Expand Up @@ -77,9 +89,14 @@ public double value() {

@Override
public long getValue() {
return counts == null ? 0 : counts.cardinality(0);
if (cardinalityValue == null) {
cardinalityValue = counts == null ? 0 : counts.cardinality(0);
}
return cardinalityValue;
}



@Override
public InternalAggregation doReduce(List<InternalAggregation> aggregations, ReduceContext reduceContext) {
InternalCardinality reduced = null;
Expand Down Expand Up @@ -127,4 +144,22 @@ protected boolean doEquals(Object obj) {
HyperLogLogPlusPlus getState() {
return counts;
}
private static final ObjectParser<Map<String, Object>, Void> PARSER = new ObjectParser<>(
"internal_cardinality", true, () -> new HashMap<>());

static {
declareCommonField(PARSER);
PARSER.declareLong((map, value) -> map.put(CommonFields.VALUE.getPreferredName(), value),
CommonFields.VALUE);
}

public static InternalCardinality parseXContentBody(final String name, XContentParser parser) {
Map<String, Object> map = PARSER.apply(parser, null);
final long cardinalityValue = (Long) map.getOrDefault(CommonFields.VALUE.getPreferredName(),
Double.POSITIVE_INFINITY);
@SuppressWarnings("unchecked")
final Map<String, Object> metaData = (Map<String, Object>) map
.get(CommonFields.META.getPreferredName());
return new InternalCardinality(name, cardinalityValue, Collections.emptyList(), metaData);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,30 @@

package org.elasticsearch.search.aggregations.metrics.cardinality;

import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.MockBigArrays;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.indices.breaker.NoneCircuitBreakerService;
import org.elasticsearch.rest.action.search.RestSearchAction;
import org.elasticsearch.search.aggregations.InternalAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;

public class InternalCardinalityTests extends InternalAggregationTestCase<InternalCardinality> {
private static List<HyperLogLogPlusPlus> algos;
private static int p;
Expand Down Expand Up @@ -73,6 +83,31 @@ protected void assertReduced(InternalCardinality reduced, List<InternalCardinali
}
}

public void testFromXContent() throws IOException {
InternalCardinality cardinality = createTestInstance();
ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
boolean humanReadable = randomBoolean();
XContentType xContentType = randomFrom(XContentType.values());
BytesReference originalBytes = toXContent(cardinality, xContentType, params, humanReadable);

InternalCardinality parsed;
try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
assertEquals(XContentParser.Token.FIELD_NAME, parser.nextToken());
assertEquals(cardinality.getWriteableName() + "#" + cardinality.getName(), parser.currentName());
assertEquals(XContentParser.Token.START_OBJECT, parser.nextToken());
parsed = InternalCardinality.parseXContentBody(cardinality.getName(), parser);
assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
assertNull(parser.nextToken());
}
assertEquals(cardinality.getName(), parsed.getName());
assertEquals(cardinality.getValue(), parsed.getValue(), Double.MIN_VALUE);
assertEquals(cardinality.getValueAsString(), parsed.getValueAsString());
assertEquals(cardinality.getMetaData(), parsed.getMetaData());
assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, params, humanReadable), xContentType);
}

@After
public void cleanup() {
Releasables.close(algos);
Expand Down