Class ExponentialHistogramMerger

java.lang.Object
org.elasticsearch.exponentialhistogram.ExponentialHistogramMerger
All Implemented Interfaces:
Closeable, AutoCloseable, org.apache.lucene.util.Accountable, Releasable

public class ExponentialHistogramMerger extends Object implements org.apache.lucene.util.Accountable, Releasable
Allows accumulating multiple ExponentialHistogram into a single one while keeping the bucket count in the result below a given limit.
  • Field Details

    • DEFAULT_MAX_HISTOGRAM_BUCKETS

      public static final int DEFAULT_MAX_HISTOGRAM_BUCKETS
      See Also:
  • Method Details

    • createFactory

      public static ExponentialHistogramMerger.Factory createFactory(ExponentialHistogramCircuitBreaker circuitBreaker)
      Creates a new factory with the OpenTelemetry SDK default bucket limit of DEFAULT_MAX_HISTOGRAM_BUCKETS.
      Parameters:
      circuitBreaker - the circuit breaker to use to limit memory allocations
    • createFactory

      public static ExponentialHistogramMerger.Factory createFactory(int bucketLimit, ExponentialHistogramCircuitBreaker circuitBreaker)
      Creates a new factory with the specified bucket limit.
      Parameters:
      bucketLimit - the maximum number of buckets the result histogram is allowed to have, must be at least 4
      circuitBreaker - the circuit breaker to use to limit memory allocations
    • create

      public static ExponentialHistogramMerger create(ExponentialHistogramCircuitBreaker circuitBreaker)
      Creates a new instance with the OpenTelemetry SDK default bucket limit of DEFAULT_MAX_HISTOGRAM_BUCKETS.
      Parameters:
      circuitBreaker - the circuit breaker to use to limit memory allocations
    • create

      public static ExponentialHistogramMerger create(int bucketLimit, ExponentialHistogramCircuitBreaker circuitBreaker)
      Creates a new instance with the specified bucket limit.
      Parameters:
      bucketLimit - the maximum number of buckets the result histogram is allowed to have, must be at least 4
      circuitBreaker - the circuit breaker to use to limit memory allocations
    • createWithMaxScale

      public static ExponentialHistogramMerger createWithMaxScale(int bucketLimit, int maxScale, ExponentialHistogramCircuitBreaker circuitBreaker)
    • close

      public void close()
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Specified by:
      close in interface Releasable
    • ramBytesUsed

      public long ramBytesUsed()
      Specified by:
      ramBytesUsed in interface org.apache.lucene.util.Accountable
    • getAndClear

      public ReleasableExponentialHistogram getAndClear()
      Returns the merged histogram and clears this merger. The caller takes ownership of the returned histogram and must ensure that close() is called.
      Returns:
      the merged histogram
    • get

      public ExponentialHistogram get()
      Gets the current merged histogram without clearing this merger. Note that the ownership of the returned histogram remains with this merger, so the caller must not close it. The returned histogram is only valid until the next call to add(ExponentialHistogram), or until the merger is closed.
      Returns:
      the current merged histogram
    • add

      public void add(ExponentialHistogram toAdd)
      Merges the given histogram into the current result.
      Parameters:
      toAdd - the histogram to merge
    • setToMerged

      public void setToMerged(ExponentialHistogram a, ExponentialHistogram b)
    • setToDifference

      public boolean setToDifference(ExponentialHistogram a, ExponentialHistogram b)
      Clears this merger and sets it to the histogram a minus the histogram b.

      This method is intended to compute the delta between two cumulative histograms from the same time series, where a is a later snapshot and b is an earlier snapshot. In cumulative histograms, bucket counts only increase over time, which means that subtracting b from a should never result in negative bucket counts. Note that this algorithm still is capable of dealing with cases where the histograms seem to be cumulative (a.count() >= b.count()), but actually are not. In this case the negative buckets will be clamped to a count of 0 and the remaining populate buckets will have their count scaled down to compensate for this.

      The algorithm provides the following guarantees if the histograms are actually cumulative: Given two exponential histograms b and c. The histogram a is the result of merging the histograms b and c. Then a - b will yield the histogram c, with the limitation that

      • a - b might have a smaller scale (=less precision) than c (but no lower than the scale of a)
      • a - b might have a greater zero threshold than c (but not greater than the zero threshold of a)
      • a - b might not preserve the exact minimum / maximum of c, but will provide an estimate in that case

      If the histograms are not cumulative, the following guarantees are provided instead:

      • result.valueCount() will be exactly a.valueCount() - b.valueCount()
      • result.sum() will be exactly a.sum() - b.count()
      • result.min() and result.max() will be sane values (e.g. not outside the min/max values of the inputs)
      • Each bucket in the result will correspond to input buckets where the count for a was greater than the count of b
      Parameters:
      a - the base histogram to subtract from
      b - the histogram to be subtracted
      Returns:
      true if the histograms were actually cumulative and the result is the exact difference, false if the histograms were not cumulative and the result only provides the weaker guarantees explained above