# Date range aggregation

**URL:** <https://discourse.hibernate.org/t/date-range-aggregation/3920>\
**Category:** Hibernate Search\
**Created:** [March 21, 2020, 2:29pm UTC](https://discourse.hibernate.org/t/date-range-aggregation/3920 "2020-03-21T14:29:47Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Alexis\_Cucumel](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/alexis_cucumel/32/687_2.png) [@Alexis\_Cucumel](https://discourse.hibernate.org/u/Alexis_Cucumel)\
**Post date:** [March 21, 2020, 2:29pm UTC](https://discourse.hibernate.org/t/date-range-aggregation/3920/1 "2020-03-21T14:29:47Z")

</div>

Hello,

I try to make a range query but i can’t figure out how to put alias on my dateRanges as i can do it directly in ElasticSearch :

```auto
"date_range": {
	"field": "randomDateField",
	 "ranges": [{ 
		 "key": "range1",
		 "to": "now-29d" 
	},
	{ 
		"key": "range2",
		"from": "now-25d",
		"to": "now-29d" 
	},
	{ 
		"key": "range3",
		"from": "now-20d",
		"to": "now-25d"
	},
	{ 
		"key": "range4",
		"from": "now-19d"
	}]
}

```

```auto
AggregationKey<Map<Range<Instant>, Long>> agg = AggregationKey.of( "myAgg" );
... 
.aggregation(agg, f -> f.range()
		.field("randomDateField", Instant.class, ValueConvert.NO)
		.range("range1", to, from) // i would like to have something like that here.
		.range("range2", to, from)

```

Maybe it can be done with some extension like .extension(ElasticsearchExtension.get()) or trick that i’am not aware of ?

thank for your help !

---

<div class="post-metadata">

**Author:** ![Alexis\_Cucumel](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/alexis_cucumel/32/687_2.png) [@Alexis\_Cucumel](https://discourse.hibernate.org/u/Alexis_Cucumel)\
**Post date:** [March 21, 2020, 11:00pm UTC](https://discourse.hibernate.org/t/date-range-aggregation/3920/2 "2020-03-21T23:00:46Z")

</div>

After some digging i found this part of the code :

```auto
@Override
		public void range(Range<? extends K> range) {
			JsonObject rangeJson = new JsonObject();
			Optional<? extends K> lowerBoundValue = range.getLowerBoundValue();
			if ( lowerBoundValue.isPresent() ) {
				if ( !RangeBoundInclusion.INCLUDED.equals( range.getLowerBoundInclusion() ) ) {
					throw log.elasticsearchRangeAggregationRequiresCanonicalFormForRanges( range );
				}
				rangeJson.add( "from", convertToFieldValue( lowerBoundValue.get() ) );
			}
			Optional<? extends K> upperBoundValue = range.getUpperBoundValue();
			if ( upperBoundValue.isPresent() ) {
				if ( !RangeBoundInclusion.EXCLUDED.equals( range.getUpperBoundInclusion() ) ) {
					throw log.elasticsearchRangeAggregationRequiresCanonicalFormForRanges( range );
				}
				rangeJson.add( "to", convertToFieldValue( upperBoundValue.get() ) );
			}
			// We need to request a keyed response,
			// because ranges are not always returned in the order they are submitted
			rangeJson.addProperty( "key", String.valueOf( rangesJson.size() ) );
			rangesInOrder.add( range.map( Function.identity() ) );
			rangesJson.add( rangeJson );
		}

```

I assume we can rely on the rangesJson.size() to help produce the expected ordered ranges in the result Aggregation Map and then i don’t really need to associate every range to a specific key.  
Anyway, i think it could be more comfortable to have a way to use a specific key, maybe with an extension specific to ElasticSearch if it’s not something usefull in lucene.

---

<div class="post-metadata">

**Author:** ![yrodiere](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.hibernate.org/yrodiere/32/1760_2.png) [@yrodiere](https://discourse.hibernate.org/u/yrodiere)\
**Post date:** [March 23, 2020, 8:01am UTC](https://discourse.hibernate.org/t/date-range-aggregation/3920/3 "2020-03-23T08:01:20Z")

</div>

Hello,

> [@Alexis\_Cucumel](#):
>
> I assume we can rely on the rangesJson.size() to help produce the expected ordered ranges in the result Aggregation Map and then i don’t really need to associate every range to a specific key.

Yes, you don’t have to worry about providing range keys yourself. The idea is that you use `Range` instances as keys, and Hibernate Search will do what’s necessary internally to handle the implementation details, and to return ranges in the order they were provided.

> [@Alexis\_Cucumel](#):
>
> Anyway, i think it could be more comfortable to have a way to use a specific key, maybe with an extension specific to ElasticSearch if it’s not something usefull in lucene.

If you have “business” keys that you translate to ranges, I can see how passing these keys to Hibernate Search and having Hibernate Search return these keys directly in the resulting map would come handy.  
For now you can just assume ranges are returned in the order they are defined, but that’s admittedly a bit awkward.

We could consider allowing to provide a custom key with each defined range. Implementation wise, it’s easy, be it for Lucene or Elasticsearch. Honestly, the real challenge will be how to present that in APIs… because we shouldn’t allow only _some_ ranges to have a key: either they all have a custom key and the aggregation type is `Map<CustomKey, Long>`, or none of them has and the aggregation type is `Map<Range<F>, Long>`.

I suppose something like this would do:

```auto
AggregationKey<Map<MyCustomKey, Long>> agg = AggregationKey.of( "myAgg" );
... 
.aggregation(agg, f -> f.range()
		.field("randomDateField", Instant.class, ValueConvert.NO)
		.providedKeys(MyCustomKey.class)
		.range(myCustomKey1, to1, from1)
		.range(myCustomKey2, to2, from2)

```

Or:

```auto
AggregationKey<Map<MyCustomKey, Long>> agg = AggregationKey.of( "myAgg" );
Map<MyCustomKey, Range<Instant>> ranges = ...;
... 
.aggregation(agg, f -> f.range()
		.field("randomDateField", Instant.class, ValueConvert.NO)
		.providedKeys(MyCustomKey.class)
		.ranges(ranges)

```

If you’re interested in this feature, could you please open a ticket? Thanks.
