package com.pearson.entech.elasticsearch.search.facet.approx.datehistogram; import java.io.IOException; import org.apache.lucene.index.AtomicReaderContext; import org.apache.lucene.util.BytesRef; import org.elasticsearch.common.CacheRecycler; import org.elasticsearch.common.joda.TimeZoneRounding; import org.elasticsearch.common.trove.ExtTLongObjectHashMap; import org.elasticsearch.index.fielddata.BytesValues; import org.elasticsearch.index.fielddata.LongValues; import org.elasticsearch.index.fielddata.plain.LongArrayIndexFieldData; import org.elasticsearch.index.fielddata.plain.PagedBytesIndexFieldData; import org.elasticsearch.search.facet.FacetExecutor; import org.elasticsearch.search.facet.InternalFacet; import org.elasticsearch.search.facet.LongFacetAggregatorBase; import org.elasticsearch.search.facet.terms.strings.HashedAggregator; /** * Collect the distinct values per time interval. */ public class StringDistinctDateHistogramFacetExecutor extends FacetExecutor { private final LongArrayIndexFieldData keyIndexFieldData; private final PagedBytesIndexFieldData distinctIndexFieldData; private final TimeZoneRounding tzRounding; private final ComparatorType comparatorType; private final ExtTLongObjectHashMap<DistinctCountPayload> counts; private final int maxExactPerShard; public StringDistinctDateHistogramFacetExecutor(final LongArrayIndexFieldData keyIndexFieldData, final PagedBytesIndexFieldData distinctIndexFieldData, final TimeZoneRounding tzRounding, final ComparatorType comparatorType, final int maxExactPerShard) { this.comparatorType = comparatorType; this.keyIndexFieldData = keyIndexFieldData; this.distinctIndexFieldData = distinctIndexFieldData; this.counts = CacheRecycler.popLongObjectMap(); this.tzRounding = tzRounding; this.maxExactPerShard = maxExactPerShard; } @Override public Collector collector() { return new Collector(); } @Override public InternalFacet buildFacet(final String facetName) { final StringInternalDistinctDateHistogramFacet facet = new StringInternalDistinctDateHistogramFacet(facetName, comparatorType, counts, true); System.out.println("Built facet " + facet); return facet; } class Collector extends FacetExecutor.Collector { private LongValues keyValues; private final DateHistogramProc histoProc; public Collector() { this.histoProc = new DateHistogramProc(counts, tzRounding, maxExactPerShard); } @Override public void setNextReader(final AtomicReaderContext context) throws IOException { keyValues = keyIndexFieldData.load(context).getLongValues(); histoProc.valueValues = distinctIndexFieldData.load(context).getBytesValues(); } @Override public void collect(final int doc) throws IOException { histoProc.onDoc(doc, keyValues); } @Override public void postCollection() {} } /** * Collect the time intervals in value aggregators for each time interval found. * The value aggregator finally contains the facet entry. */ // TODO remove duplication between this and LongDistinctDateHistogramFacetExecutor public static class DateHistogramProc extends LongFacetAggregatorBase { BytesValues.WithOrdinals valueValues; private final int maxExactPerShard; private final TimeZoneRounding tzRounding; final ExtTLongObjectHashMap<DistinctCountPayload> counts; final ValueAggregator valueAggregator = new ValueAggregator(); public DateHistogramProc(final ExtTLongObjectHashMap<DistinctCountPayload> counts, final TimeZoneRounding tzRounding, final int maxExactPerShard) { this.tzRounding = tzRounding; this.counts = counts; this.maxExactPerShard = maxExactPerShard; } @Override public void onValue(final int docId, final long value) { final long time = tzRounding.calc(value); DistinctCountPayload count = counts.get(time); if(count == null) { count = new DistinctCountPayload(maxExactPerShard); counts.put(time, count); } valueAggregator.entry = count; valueAggregator.onDoc(docId, valueValues); } /* * aggregates the values in a set */ public final static class ValueAggregator extends HashedAggregator { DistinctCountPayload entry; @Override protected void onValue(final int docId, final BytesRef value, final int hashCode, final BytesValues values) { final String val = value.utf8ToString(); entry.update(val); } } } }