@Override
  public InternalAggregation buildAggregation(long owningBucketOrdinal) {
    assert owningBucketOrdinal == 0;
    List<InternalHistogram.Bucket> buckets =
        new ArrayList<InternalHistogram.Bucket>((int) bucketOrds.size());
    for (long i = 0; i < bucketOrds.capacity(); ++i) {
      final long ord = bucketOrds.id(i);
      if (ord < 0) {
        continue; // slot is not allocated
      }
      buckets.add(
          histogramFactory.createBucket(
              rounding.valueForKey(bucketOrds.key(i)),
              bucketDocCount(ord),
              bucketAggregations(ord),
              valuesSource.formatter()));
    }

    CollectionUtil.introSort(buckets, order.comparator());

    // value source will be null for unmapped fields
    ValueFormatter formatter = valuesSource != null ? valuesSource.formatter() : null;
    InternalHistogram.EmptyBucketInfo emptyBucketInfo =
        minDocCount == 0
            ? new InternalHistogram.EmptyBucketInfo(rounding, buildEmptySubAggregations())
            : null;
    return histogramFactory.create(
        name, buckets, order, minDocCount, emptyBucketInfo, formatter, keyed);
  }
  @Override
  public InternalAggregation buildAggregation(long owningBucketOrdinal) throws IOException {
    assert owningBucketOrdinal == 0;
    List<InternalHistogram.Bucket> buckets = new ArrayList<>((int) bucketOrds.size());
    for (long i = 0; i < bucketOrds.size(); i++) {
      buckets.add(
          histogramFactory.createBucket(
              rounding.valueForKey(bucketOrds.get(i)),
              bucketDocCount(i),
              bucketAggregations(i),
              keyed,
              formatter));
    }

    // the contract of the histogram aggregation is that shards must return buckets ordered by key
    // in ascending order
    CollectionUtil.introSort(buckets, InternalOrder.KEY_ASC.comparator());

    // value source will be null for unmapped fields
    InternalHistogram.EmptyBucketInfo emptyBucketInfo =
        minDocCount == 0
            ? new InternalHistogram.EmptyBucketInfo(
                rounding, buildEmptySubAggregations(), extendedBounds)
            : null;
    return histogramFactory.create(
        name,
        buckets,
        order,
        minDocCount,
        emptyBucketInfo,
        formatter,
        keyed,
        pipelineAggregators(),
        metaData());
  }
 @Override
 public InternalAggregation buildEmptyAggregation() {
   ValueFormatter formatter = valuesSource != null ? valuesSource.formatter() : null;
   InternalHistogram.EmptyBucketInfo emptyBucketInfo =
       minDocCount == 0
           ? new InternalHistogram.EmptyBucketInfo(rounding, buildEmptySubAggregations())
           : null;
   return histogramFactory.create(
       name, Collections.emptyList(), order, minDocCount, emptyBucketInfo, formatter, keyed);
 }
 public Factory(
     String name,
     ValuesSourceConfig<NumericValuesSource> valueSourceConfig,
     Rounding rounding,
     InternalOrder order,
     boolean keyed,
     long minDocCount,
     InternalHistogram.Factory<?> histogramFactory) {
   super(name, histogramFactory.type(), valueSourceConfig);
   this.rounding = rounding;
   this.order = order;
   this.keyed = keyed;
   this.minDocCount = minDocCount;
   this.histogramFactory = histogramFactory;
 }
 @Override
 public InternalAggregation buildEmptyAggregation() {
   InternalHistogram.EmptyBucketInfo emptyBucketInfo =
       minDocCount == 0
           ? new InternalHistogram.EmptyBucketInfo(
               rounding, buildEmptySubAggregations(), extendedBounds)
           : null;
   return histogramFactory.create(
       name,
       Collections.emptyList(),
       order,
       minDocCount,
       emptyBucketInfo,
       formatter,
       keyed,
       pipelineAggregators(),
       metaData());
 }