@@ -2,18 +2,22 @@ package app.softnetwork.elastic.sql.bridge
22
33import app .softnetwork .elastic .sql .{
44 AggregateFunction ,
5+ Asc ,
56 Avg ,
7+ BucketSelectorScript ,
68 Count ,
79 ElasticBoolQuery ,
810 Max ,
911 Min ,
1012 SQLBucket ,
1113 SQLCriteria ,
1214 SQLField ,
15+ SortOrder ,
1316 Sum
1417}
1518import com .sksamuel .elastic4s .ElasticApi .{
1619 avgAgg ,
20+ bucketSelectorAggregation ,
1721 cardinalityAgg ,
1822 filterAgg ,
1923 maxAgg ,
@@ -23,11 +27,13 @@ import com.sksamuel.elastic4s.ElasticApi.{
2327 termsAgg ,
2428 valueCountAgg
2529}
30+ import com .sksamuel .elastic4s .script .Script
2631import com .sksamuel .elastic4s .searches .aggs .{
2732 Aggregation ,
2833 FilterAggregation ,
2934 NestedAggregation ,
30- TermsAggregation
35+ TermsAggregation ,
36+ TermsOrder
3137}
3238
3339import scala .language .implicitConversions
@@ -42,17 +48,24 @@ case class ElasticAggregation(
4248 nestedAgg : Option [NestedAggregation ] = None ,
4349 filteredAgg : Option [FilterAggregation ] = None ,
4450 aggType : AggregateFunction ,
45- agg : Aggregation
51+ agg : Aggregation ,
52+ direction : Option [SortOrder ] = None
4653) {
4754 val nested : Boolean = nestedAgg.nonEmpty
4855 val filtered : Boolean = filteredAgg.nonEmpty
4956}
5057
5158object ElasticAggregation {
52- def apply (sqlAgg : SQLField , filter : Option [SQLCriteria ]): ElasticAggregation = {
59+ def apply (
60+ sqlAgg : SQLField ,
61+ having : Option [SQLCriteria ],
62+ bucketsDirection : Map [String , SortOrder ]
63+ ): ElasticAggregation = {
5364 import sqlAgg ._
5465 val sourceField = identifier.name
5566
67+ val direction = bucketsDirection.get(identifier.identifierName)
68+
5669 val field = fieldAlias match {
5770 case Some (alias) => alias.alias
5871 case _ => sourceField
@@ -92,7 +105,7 @@ object ElasticAggregation {
92105 val filteredAggName = " filtered_agg"
93106
94107 val filteredAgg : Option [FilterAggregation ] =
95- filter match {
108+ having match {
96109 case Some (f) =>
97110 val boolQuery = Option (ElasticBoolQuery (group = true ))
98111 Some (
@@ -135,44 +148,60 @@ object ElasticAggregation {
135148 nestedAgg = nestedAgg,
136149 filteredAgg = filteredAgg,
137150 aggType = aggType,
138- agg = _agg
151+ agg = _agg,
152+ direction = direction
139153 )
140154 }
141155
142- /*
143- def apply(
156+ def buildBuckets (
144157 buckets : Seq [SQLBucket ],
158+ bucketsDirection : Map [String , SortOrder ],
145159 aggregations : Seq [Aggregation ],
146- current: Option[TermsAggregation]
160+ aggregationsDirection : Map [String , SortOrder ],
161+ having : Option [SQLCriteria ]
147162 ): Option [TermsAggregation ] = {
148- buckets match {
149- case Nil =>
150- current.map(_.copy(subaggs = aggregations))
151- case bucket +: tail =>
152- val agg = termsAgg(bucket.name, s"${bucket.identifier.name}.keyword")
153- current match {
154- case Some(a) =>
155- apply(tail, aggregations, Some(agg)) match {
156- case Some(subAgg) =>
157- Some(a.copy(subaggs = a.subaggs :+ subAgg))
158- case _ => Some(a)
159- }
163+ Console .println(bucketsDirection)
164+ buckets.reverse.foldLeft(Option .empty[TermsAggregation ]) { (current, bucket) =>
165+ val agg = {
166+ bucketsDirection.get(bucket.identifier.identifierName) match {
167+ case Some (direction) =>
168+ termsAgg(bucket.name, s " ${bucket.identifier.name}.keyword " )
169+ .order(Seq (direction match {
170+ case Asc => TermsOrder (bucket.name, asc = true )
171+ case _ => TermsOrder (bucket.name, asc = false )
172+ }))
160173 case None =>
161- apply(tail, aggregations, Some(agg) )
174+ termsAgg(bucket.name, s " ${bucket.identifier.name} .keyword " )
162175 }
163- }
164- }
165- */
166-
167- def buildBuckets (
168- buckets : Seq [SQLBucket ],
169- aggregations : Seq [Aggregation ]
170- ): Option [TermsAggregation ] = {
171- buckets.reverse.foldLeft(Option .empty[TermsAggregation ]) { (current, bucket) =>
172- val agg = termsAgg(bucket.name, s " ${bucket.identifier.name}.keyword " )
176+ }
173177 current match {
174178 case Some (subAgg) => Some (agg.copy(subaggs = Seq (subAgg)))
175- case None => Some (agg.copy(subaggs = aggregations))
179+ case None =>
180+ val aggregationsWithOrder : Seq [TermsOrder ] = aggregationsDirection.toSeq.map { kv =>
181+ kv._2 match {
182+ case Asc => TermsOrder (kv._1, asc = true )
183+ case _ => TermsOrder (kv._1, asc = false )
184+ }
185+ }
186+ val withAggregationOrders =
187+ if (aggregationsWithOrder.nonEmpty)
188+ agg.order(aggregationsWithOrder)
189+ else
190+ agg
191+ val withHaving = having match {
192+ case Some (criteria) =>
193+ import BucketSelectorScript ._
194+ val script = toPainless(criteria)
195+ val bucketsPath = extractBucketsPath(criteria)
196+
197+ val bucketSelector =
198+ bucketSelectorAggregation(" having_filter" , Script (script), bucketsPath)
199+
200+ withAggregationOrders.copy(subaggs = aggregations :+ bucketSelector)
201+
202+ case None => withAggregationOrders.copy(subaggs = aggregations)
203+ }
204+ Some (withHaving)
176205 }
177206 }
178207 }
0 commit comments