1212import org .apache .lucene .document .NumericDocValuesField ;
1313import org .apache .lucene .index .BinaryDocValues ;
1414import org .apache .lucene .index .LeafReader ;
15+ import org .apache .lucene .index .LeafReaderContext ;
1516import org .apache .lucene .index .NumericDocValues ;
1617import org .apache .lucene .search .Query ;
18+ import org .apache .lucene .search .SortField ;
1719import org .apache .lucene .util .BytesRef ;
1820import org .apache .lucene .util .NumericUtils ;
1921import org .elasticsearch .common .Explicit ;
2022import org .elasticsearch .common .io .stream .BytesStreamOutput ;
23+ import org .elasticsearch .common .util .BigArrays ;
2124import org .elasticsearch .common .util .FeatureFlag ;
25+ import org .elasticsearch .core .Nullable ;
2226import org .elasticsearch .exponentialhistogram .ExponentialHistogram ;
2327import org .elasticsearch .exponentialhistogram .ExponentialHistogramUtils ;
2428import org .elasticsearch .exponentialhistogram .ExponentialHistogramXContent ;
2529import org .elasticsearch .exponentialhistogram .ZeroBucket ;
2630import org .elasticsearch .index .fielddata .FieldDataContext ;
2731import org .elasticsearch .index .fielddata .IndexFieldData ;
32+ import org .elasticsearch .index .fielddata .SortedBinaryDocValues ;
2833import org .elasticsearch .index .mapper .CompositeSyntheticFieldLoader ;
2934import org .elasticsearch .index .mapper .DocumentParserContext ;
3035import org .elasticsearch .index .mapper .DocumentParsingException ;
3641import org .elasticsearch .index .mapper .SourceValueFetcher ;
3742import org .elasticsearch .index .mapper .ValueFetcher ;
3843import org .elasticsearch .index .query .SearchExecutionContext ;
44+ import org .elasticsearch .script .field .DocValuesScriptFieldFactory ;
45+ import org .elasticsearch .search .DocValueFormat ;
46+ import org .elasticsearch .search .MultiValueMode ;
47+ import org .elasticsearch .search .sort .BucketedSort ;
48+ import org .elasticsearch .search .sort .SortOrder ;
3949import org .elasticsearch .xcontent .CopyingXContentParser ;
4050import org .elasticsearch .xcontent .ParseField ;
4151import org .elasticsearch .xcontent .XContentBuilder ;
4252import org .elasticsearch .xcontent .XContentParser ;
4353import org .elasticsearch .xcontent .XContentSubParser ;
54+ import org .elasticsearch .xpack .exponentialhistogram .fielddata .ExponentialHistogramValuesReader ;
55+ import org .elasticsearch .xpack .exponentialhistogram .fielddata .IndexExponentialHistogramFieldData ;
56+ import org .elasticsearch .xpack .exponentialhistogram .fielddata .LeafExponentialHistogramFieldData ;
4457
4558import java .io .IOException ;
4659import java .util .ArrayList ;
@@ -242,12 +255,69 @@ public ValueFetcher valueFetcher(SearchExecutionContext context, String format)
242255
243256 @ Override
244257 public boolean isAggregatable () {
245- return false ;
258+ return true ;
246259 }
247260
248261 @ Override
249262 public IndexFieldData .Builder fielddataBuilder (FieldDataContext fieldDataContext ) {
250- throw new IllegalArgumentException ("The [" + CONTENT_TYPE + "] field does not support this operation currently" );
263+ return (cache , breakerService ) -> new IndexExponentialHistogramFieldData (name ()) {
264+ @ Override
265+ public LeafExponentialHistogramFieldData load (LeafReaderContext context ) {
266+ return new LeafExponentialHistogramFieldData () {
267+ @ Override
268+ public ExponentialHistogramValuesReader getHistogramValues () throws IOException {
269+ return new DocValuesReader (context .reader (), fieldName );
270+ }
271+
272+ @ Override
273+ public DocValuesScriptFieldFactory getScriptFieldFactory (String name ) {
274+ throw new UnsupportedOperationException ("The [" + CONTENT_TYPE + "] field does not " + "support scripts" );
275+ }
276+
277+ @ Override
278+ public SortedBinaryDocValues getBytesValues () {
279+ throw new UnsupportedOperationException (
280+ "String representation of doc values " + "for [" + CONTENT_TYPE + "] fields is not supported"
281+ );
282+ }
283+
284+ @ Override
285+ public long ramBytesUsed () {
286+ return 0 ; // No dynamic allocations
287+ }
288+ };
289+ }
290+
291+ @ Override
292+ public LeafExponentialHistogramFieldData loadDirect (LeafReaderContext context ) throws Exception {
293+ return load (context );
294+ }
295+
296+ @ Override
297+ public SortField sortField (
298+ Object missingValue ,
299+ MultiValueMode sortMode ,
300+ XFieldComparatorSource .Nested nested ,
301+ boolean reverse
302+ ) {
303+ throw new UnsupportedOperationException ("can't sort on the [" + CONTENT_TYPE + "] field" );
304+ }
305+
306+ @ Override
307+ public BucketedSort newBucketedSort (
308+ BigArrays bigArrays ,
309+ Object missingValue ,
310+ MultiValueMode sortMode ,
311+ XFieldComparatorSource .Nested nested ,
312+ SortOrder sortOrder ,
313+ DocValueFormat format ,
314+ int bucketSize ,
315+ BucketedSort .ExtraData extra
316+ ) {
317+ throw new IllegalArgumentException ("can't sort on the [" + CONTENT_TYPE + "] field" );
318+ }
319+
320+ };
251321 }
252322
253323 @ Override
@@ -721,76 +791,102 @@ protected FieldMapper.SyntheticSourceSupport syntheticSourceSupport() {
721791 );
722792 }
723793
794+ private static class DocValuesReader implements ExponentialHistogramValuesReader {
795+
796+ private final BinaryDocValues histoDocValues ;
797+ private final NumericDocValues zeroThresholds ;
798+ private final NumericDocValues valueCounts ;
799+ private final NumericDocValues valueSums ;
800+ private final NumericDocValues valueMinima ;
801+ private final NumericDocValues valueMaxima ;
802+
803+ private int currentDocId = -1 ;
804+ private final CompressedExponentialHistogram tempHistogram = new CompressedExponentialHistogram ();
805+
806+ DocValuesReader (LeafReader leafReader , String fullPath ) throws IOException {
807+ histoDocValues = leafReader .getBinaryDocValues (fullPath );
808+ zeroThresholds = leafReader .getNumericDocValues (zeroThresholdSubFieldName (fullPath ));
809+ valueCounts = leafReader .getNumericDocValues (valuesCountSubFieldName (fullPath ));
810+ valueSums = leafReader .getNumericDocValues (valuesSumSubFieldName (fullPath ));
811+ valueMinima = leafReader .getNumericDocValues (valuesMinSubFieldName (fullPath ));
812+ valueMaxima = leafReader .getNumericDocValues (valuesMaxSubFieldName (fullPath ));
813+ }
814+
815+ boolean hasAnyValues () {
816+ return histoDocValues != null ;
817+ }
818+
819+ @ Override
820+ public boolean advanceExact (int docId ) throws IOException {
821+ boolean isPresent = histoDocValues != null && histoDocValues .advanceExact (docId );
822+ currentDocId = isPresent ? docId : -1 ;
823+ return isPresent ;
824+ }
825+
826+ @ Override
827+ public ExponentialHistogram histogramValue () throws IOException {
828+ if (currentDocId == -1 ) {
829+ throw new IllegalStateException ("No histogram present for current document" );
830+ }
831+ boolean zeroThresholdPresent = zeroThresholds .advanceExact (currentDocId );
832+ boolean valueCountsPresent = valueCounts .advanceExact (currentDocId );
833+ boolean valueSumsPresent = valueSums .advanceExact (currentDocId );
834+ assert zeroThresholdPresent && valueCountsPresent && valueSumsPresent ;
835+
836+ BytesRef encodedHistogram = histoDocValues .binaryValue ();
837+ double zeroThreshold = NumericUtils .sortableLongToDouble (zeroThresholds .longValue ());
838+ long valueCount = valueCounts .longValue ();
839+ double valueSum = NumericUtils .sortableLongToDouble (valueSums .longValue ());
840+ double valueMin ;
841+ if (valueMinima != null && valueMinima .advanceExact (currentDocId )) {
842+ valueMin = NumericUtils .sortableLongToDouble (valueMinima .longValue ());
843+ } else {
844+ valueMin = Double .NaN ;
845+ }
846+ double valueMax ;
847+ if (valueMaxima != null && valueMaxima .advanceExact (currentDocId )) {
848+ valueMax = NumericUtils .sortableLongToDouble (valueMaxima .longValue ());
849+ } else {
850+ valueMax = Double .NaN ;
851+ }
852+ tempHistogram .reset (zeroThreshold , valueCount , valueSum , valueMin , valueMax , encodedHistogram );
853+ return tempHistogram ;
854+ }
855+ }
856+
724857 private class ExponentialHistogramSyntheticFieldLoader implements CompositeSyntheticFieldLoader .DocValuesLayer {
725858
726- private final CompressedExponentialHistogram histogram = new CompressedExponentialHistogram ();
727- private BytesRef binaryValue ;
728- private double zeroThreshold ;
729- private long valueCount ;
730- private double valueSum ;
731- private double valueMin ;
732- private double valueMax ;
859+ @ Nullable
860+ private ExponentialHistogram currentHistogram ;
733861
734862 @ Override
735863 public SourceLoader .SyntheticFieldLoader .DocValuesLoader docValuesLoader (LeafReader leafReader , int [] docIdsInLeaf )
736864 throws IOException {
737- BinaryDocValues histoDocValues = leafReader .getBinaryDocValues (fieldType ().name ());
738- if (histoDocValues == null ) {
739- // No values in this leaf
740- binaryValue = null ;
865+ DocValuesReader histogramReader = new DocValuesReader (leafReader , fullPath ());
866+ if (histogramReader .hasAnyValues () == false ) {
741867 return null ;
742868 }
743- NumericDocValues zeroThresholds = leafReader .getNumericDocValues (zeroThresholdSubFieldName (fullPath ()));
744- NumericDocValues valueCounts = leafReader .getNumericDocValues (valuesCountSubFieldName (fullPath ()));
745- NumericDocValues valueSums = leafReader .getNumericDocValues (valuesSumSubFieldName (fullPath ()));
746- NumericDocValues valueMinima = leafReader .getNumericDocValues (valuesMinSubFieldName (fullPath ()));
747- NumericDocValues valueMaxima = leafReader .getNumericDocValues (valuesMaxSubFieldName (fullPath ()));
748- assert zeroThresholds != null ;
749- assert valueCounts != null ;
750- assert valueSums != null ;
751869 return docId -> {
752- if (histoDocValues .advanceExact (docId )) {
753-
754- boolean zeroThresholdPresent = zeroThresholds .advanceExact (docId );
755- boolean valueCountsPresent = valueCounts .advanceExact (docId );
756- boolean valueSumsPresent = valueSums .advanceExact (docId );
757- assert zeroThresholdPresent && valueCountsPresent && valueSumsPresent ;
758-
759- binaryValue = histoDocValues .binaryValue ();
760- zeroThreshold = NumericUtils .sortableLongToDouble (zeroThresholds .longValue ());
761- valueCount = valueCounts .longValue ();
762- valueSum = NumericUtils .sortableLongToDouble (valueSums .longValue ());
763-
764- if (valueMinima != null && valueMinima .advanceExact (docId )) {
765- valueMin = NumericUtils .sortableLongToDouble (valueMinima .longValue ());
766- } else {
767- valueMin = Double .NaN ;
768- }
769- if (valueMaxima != null && valueMaxima .advanceExact (docId )) {
770- valueMax = NumericUtils .sortableLongToDouble (valueMaxima .longValue ());
771- } else {
772- valueMax = Double .NaN ;
773- }
870+ if (histogramReader .advanceExact (docId )) {
871+ currentHistogram = histogramReader .histogramValue ();
774872 return true ;
775873 }
776- binaryValue = null ;
874+ currentHistogram = null ;
777875 return false ;
778876 };
779877 }
780878
781879 @ Override
782880 public boolean hasValue () {
783- return binaryValue != null ;
881+ return currentHistogram != null ;
784882 }
785883
786884 @ Override
787885 public void write (XContentBuilder b ) throws IOException {
788- if (binaryValue == null ) {
886+ if (currentHistogram == null ) {
789887 return ;
790888 }
791-
792- histogram .reset (zeroThreshold , valueCount , valueSum , valueMin , valueMax , binaryValue );
793- ExponentialHistogramXContent .serialize (b , histogram );
889+ ExponentialHistogramXContent .serialize (b , currentHistogram );
794890 }
795891
796892 @ Override
@@ -800,7 +896,7 @@ public String fieldName() {
800896
801897 @ Override
802898 public long valueCount () {
803- return binaryValue != null ? 1 : 0 ;
899+ return currentHistogram != null ? 1 : 0 ;
804900 }
805901 };
806902
0 commit comments