88package org .elasticsearch .xpack .exponentialhistogram ;
99
1010import org .apache .lucene .document .BinaryDocValuesField ;
11- import org .apache .lucene .document .Field ;
1211import org .apache .lucene .document .NumericDocValuesField ;
1312import org .apache .lucene .index .BinaryDocValues ;
13+ import org .apache .lucene .index .IndexableField ;
1414import org .apache .lucene .index .LeafReader ;
1515import org .apache .lucene .index .LeafReaderContext ;
1616import org .apache .lucene .index .NumericDocValues ;
3636import org .elasticsearch .index .mapper .FieldMapper ;
3737import org .elasticsearch .index .mapper .IgnoreMalformedStoredValues ;
3838import org .elasticsearch .index .mapper .IndexType ;
39+ import org .elasticsearch .index .mapper .LuceneDocument ;
3940import org .elasticsearch .index .mapper .MappedFieldType ;
4041import org .elasticsearch .index .mapper .MapperBuilderContext ;
4142import org .elasticsearch .index .mapper .SourceLoader ;
@@ -238,9 +239,10 @@ protected void parseCreateField(DocumentParserContext context) {
238239 throw new UnsupportedOperationException ("Parsing is implemented in parse(), this method should NEVER be called" );
239240 }
240241
241- static class ExponentialHistogramFieldType extends MappedFieldType {
242+ public static final class ExponentialHistogramFieldType extends MappedFieldType {
242243
243- ExponentialHistogramFieldType (String name , Map <String , String > meta ) {
244+ // Visible for testing
245+ public ExponentialHistogramFieldType (String name , Map <String , String > meta ) {
244246 super (name , IndexType .docValuesOnly (), false , meta );
245247 }
246248
@@ -445,37 +447,18 @@ public void parse(DocumentParserContext context) throws IOException {
445447 min = validateOrEstimateMin (min , zeroBucket , scale , negativeBuckets , positiveBuckets , totalValueCount , subParser );
446448 max = validateOrEstimateMax (max , zeroBucket , scale , negativeBuckets , positiveBuckets , totalValueCount , subParser );
447449
448- BytesStreamOutput histogramBytesOutput = new BytesStreamOutput ();
449- CompressedExponentialHistogram .writeHistogramBytes (histogramBytesOutput , scale , negativeBuckets , positiveBuckets );
450- BytesRef histoBytes = histogramBytesOutput .bytes ().toBytesRef ();
451-
452- Field histoField = new BinaryDocValuesField (fullPath (), histoBytes );
453- long thresholdAsLong = NumericUtils .doubleToSortableLong (zeroBucket .threshold ());
454- NumericDocValuesField zeroThresholdField = new NumericDocValuesField (zeroThresholdSubFieldName (fullPath ()), thresholdAsLong );
455- NumericDocValuesField valuesCountField = new NumericDocValuesField (valuesCountSubFieldName (fullPath ()), totalValueCount );
456- NumericDocValuesField sumField = new NumericDocValuesField (
457- valuesSumSubFieldName (fullPath ()),
458- NumericUtils .doubleToSortableLong (sum )
450+ HistogramDocValueFields docValues = buildDocValueFields (
451+ fullPath (),
452+ scale ,
453+ negativeBuckets ,
454+ positiveBuckets ,
455+ zeroBucket .threshold (),
456+ totalValueCount ,
457+ sum ,
458+ min ,
459+ max
459460 );
460-
461- context .doc ().addWithKey (fieldType ().name (), histoField );
462- context .doc ().add (zeroThresholdField );
463- context .doc ().add (valuesCountField );
464- context .doc ().add (sumField );
465- if (min != null ) {
466- NumericDocValuesField minField = new NumericDocValuesField (
467- valuesMinSubFieldName (fullPath ()),
468- NumericUtils .doubleToSortableLong (min )
469- );
470- context .doc ().add (minField );
471- }
472- if (max != null ) {
473- NumericDocValuesField maxField = new NumericDocValuesField (
474- valuesMaxSubFieldName (fullPath ()),
475- NumericUtils .doubleToSortableLong (max )
476- );
477- context .doc ().add (maxField );
478- }
461+ docValues .addToDoc (context .doc ());
479462
480463 } catch (Exception ex ) {
481464 if (ignoreMalformed .value () == false ) {
@@ -505,6 +488,88 @@ public void parse(DocumentParserContext context) throws IOException {
505488 context .path ().remove ();
506489 }
507490
491+ // Visible for testing, to construct realistic doc values in tests
492+ public static HistogramDocValueFields buildDocValueFields (
493+ String fieldName ,
494+ int scale ,
495+ List <IndexWithCount > negativeBuckets ,
496+ List <IndexWithCount > positiveBuckets ,
497+ double zeroThreshold ,
498+ long totalValueCount ,
499+ double sum ,
500+ @ Nullable Double min ,
501+ @ Nullable Double max
502+ ) throws IOException {
503+ BytesStreamOutput histogramBytesOutput = new BytesStreamOutput ();
504+ CompressedExponentialHistogram .writeHistogramBytes (histogramBytesOutput , scale , negativeBuckets , positiveBuckets );
505+ BytesRef histoBytes = histogramBytesOutput .bytes ().toBytesRef ();
506+
507+ BinaryDocValuesField histoField = new BinaryDocValuesField (fieldName , histoBytes );
508+ long thresholdAsLong = NumericUtils .doubleToSortableLong (zeroThreshold );
509+ NumericDocValuesField zeroThresholdField = new NumericDocValuesField (zeroThresholdSubFieldName (fieldName ), thresholdAsLong );
510+ NumericDocValuesField valuesCountField = new NumericDocValuesField (valuesCountSubFieldName (fieldName ), totalValueCount );
511+ NumericDocValuesField sumField = new NumericDocValuesField (
512+ valuesSumSubFieldName (fieldName ),
513+ NumericUtils .doubleToSortableLong (sum )
514+ );
515+ NumericDocValuesField minField = null ;
516+ if (min != null ) {
517+ minField = new NumericDocValuesField (valuesMinSubFieldName (fieldName ), NumericUtils .doubleToSortableLong (min ));
518+ }
519+ NumericDocValuesField maxField = null ;
520+ if (max != null ) {
521+ maxField = new NumericDocValuesField (valuesMaxSubFieldName (fieldName ), NumericUtils .doubleToSortableLong (max ));
522+ }
523+ HistogramDocValueFields docValues = new HistogramDocValueFields (
524+ histoField ,
525+ zeroThresholdField ,
526+ valuesCountField ,
527+ sumField ,
528+ minField ,
529+ maxField
530+ );
531+ return docValues ;
532+ }
533+
534+ // Visible for testing
535+ public record HistogramDocValueFields (
536+ BinaryDocValuesField histo ,
537+ NumericDocValuesField zeroThreshold ,
538+ NumericDocValuesField valuesCount ,
539+ NumericDocValuesField sumField ,
540+ @ Nullable NumericDocValuesField minField ,
541+ @ Nullable NumericDocValuesField maxField
542+ ) {
543+
544+ public void addToDoc (LuceneDocument doc ) {
545+ doc .addWithKey (histo .name (), histo );
546+ doc .add (zeroThreshold );
547+ doc .add (valuesCount );
548+ doc .add (sumField );
549+ if (minField != null ) {
550+ doc .add (minField );
551+ }
552+ if (maxField != null ) {
553+ doc .add (maxField );
554+ }
555+ }
556+
557+ public List <IndexableField > fieldsAsList () {
558+ List <IndexableField > fields = new ArrayList <>();
559+ fields .add (histo );
560+ fields .add (zeroThreshold );
561+ fields .add (valuesCount );
562+ fields .add (sumField );
563+ if (minField != null ) {
564+ fields .add (minField );
565+ }
566+ if (maxField != null ) {
567+ fields .add (maxField );
568+ }
569+ return fields ;
570+ }
571+ }
572+
508573 private Double validateOrEstimateSum (
509574 Double sum ,
510575 Integer scale ,
@@ -819,12 +884,12 @@ private static class DocValuesReader implements ExponentialHistogramValuesReader
819884 }
820885
821886 boolean hasAnyValues () {
822- return histoDocValues != null ;
887+ return valueCounts != null ;
823888 }
824889
825890 @ Override
826891 public boolean advanceExact (int docId ) throws IOException {
827- boolean isPresent = histoDocValues != null && histoDocValues .advanceExact (docId );
892+ boolean isPresent = valueCounts != null && valueCounts .advanceExact (docId );
828893 currentDocId = isPresent ? docId : -1 ;
829894 return isPresent ;
830895 }
@@ -834,10 +899,10 @@ public ExponentialHistogram histogramValue() throws IOException {
834899 if (currentDocId == -1 ) {
835900 throw new IllegalStateException ("No histogram present for current document" );
836901 }
902+ boolean histoPresent = histoDocValues .advanceExact (currentDocId );
837903 boolean zeroThresholdPresent = zeroThresholds .advanceExact (currentDocId );
838- boolean valueCountsPresent = valueCounts .advanceExact (currentDocId );
839904 boolean valueSumsPresent = valueSums .advanceExact (currentDocId );
840- assert zeroThresholdPresent && valueCountsPresent && valueSumsPresent ;
905+ assert zeroThresholdPresent && histoPresent && valueSumsPresent ;
841906
842907 BytesRef encodedHistogram = histoDocValues .binaryValue ();
843908 double zeroThreshold = NumericUtils .sortableLongToDouble (zeroThresholds .longValue ());
@@ -858,6 +923,11 @@ public ExponentialHistogram histogramValue() throws IOException {
858923 tempHistogram .reset (zeroThreshold , valueCount , valueSum , valueMin , valueMax , encodedHistogram );
859924 return tempHistogram ;
860925 }
926+
927+ @ Override
928+ public long valuesCountValue () throws IOException {
929+ return valueCounts .longValue ();
930+ }
861931 }
862932
863933 private class ExponentialHistogramSyntheticFieldLoader implements CompositeSyntheticFieldLoader .DocValuesLayer {
0 commit comments