Skip to content

Commit 4299685

Browse files
authored
Merge pull request #44 from SOFTNETWORK-APP/fix/elasticConversionAndAliases
- Fix Issue #42 - Fix Issue #43
2 parents d953e38 + 083a0bb commit 4299685

4 files changed

Lines changed: 69 additions & 15 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ For programmatic access, add SoftClient4ES to your project:
205205
resolvers += "Softnetwork" at "https://softnetwork.jfrog.io/artifactory/releases/"
206206

207207
// Choose your Elasticsearch version
208-
libraryDependencies += "app.softnetwork.elastic" %% "softclient4es8-java-client" % "0.17.3"
208+
libraryDependencies += "app.softnetwork.elastic" %% "softclient4es8-java-client" % "0.17.4"
209209
// Add the community extensions for materialized views (optional)
210210
libraryDependencies += "app.softnetwork.elastic" %% "softclient4es-community-extensions" % "0.1.1"
211211
```

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ ThisBuild / organization := "app.softnetwork"
2020

2121
name := "softclient4es"
2222

23-
ThisBuild / version := "0.17-SNAPSHOT"
23+
ThisBuild / version := "0.17.4"
2424

2525
ThisBuild / scalaVersion := scala213
2626

core/src/main/scala/app/softnetwork/elastic/client/ElasticConversion.scala

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -166,24 +166,28 @@ trait ElasticConversion {
166166
val ret = parseAggregations(aggs, ListMap.empty, fieldAliases, aggregations)
167167
val groupedRows: Map[String, Seq[ListMap[String, Any]]] =
168168
ret.groupBy(_.getOrElse("bucket_root", "").toString)
169-
groupedRows.values.foldLeft(Seq(ListMap.empty[String, Any])) { (acc, group) =>
170-
for {
171-
accMap <- acc
172-
groupMap <- group
173-
} yield accMap ++ groupMap
174-
}
169+
groupedRows.values
170+
.foldLeft(Seq(ListMap.empty[String, Any])) { (acc, group) =>
171+
for {
172+
accMap <- acc
173+
groupMap <- group
174+
} yield accMap ++ groupMap
175+
}
176+
.map(_ - "bucket_root")
175177

176178
case (Some(hits), Some(aggs)) if hits.isEmpty =>
177179
// Case 3 : aggregations with no hits
178180
val ret = parseAggregations(aggs, ListMap.empty, fieldAliases, aggregations)
179181
val groupedRows: Map[String, Seq[ListMap[String, Any]]] =
180182
ret.groupBy(_.getOrElse("bucket_root", "").toString)
181-
groupedRows.values.foldLeft(Seq(ListMap.empty[String, Any])) { (acc, group) =>
182-
for {
183-
accMap <- acc
184-
groupMap <- group
185-
} yield accMap ++ groupMap
186-
}
183+
groupedRows.values
184+
.foldLeft(Seq(ListMap.empty[String, Any])) { (acc, group) =>
185+
for {
186+
accMap <- acc
187+
groupMap <- group
188+
} yield accMap ++ groupMap
189+
}
190+
.map(_ - "bucket_root")
187191

188192
case (Some(hits), Some(aggs)) if hits.nonEmpty =>
189193
// Case 4 : Hits + global aggregations + top_hits aggregations
@@ -204,7 +208,9 @@ trait ElasticConversion {
204208
}
205209

206210
// Normalize all rows at the end, after all transformations (flattening, aggregation merging)
207-
rows.map(row => normalizeRow(row, fields))
211+
// Filter out "*" from fields — it is an artifact of COUNT(*) and not a real column
212+
val effectiveFields = fields.filterNot(_ == "*")
213+
rows.map(row => normalizeRow(row, effectiveFields))
208214
}
209215

210216
def findKeyValue(path: String, map: Map[String, Any]): Option[Any] = {

core/src/test/scala/app/softnetwork/elastic/client/ElasticConversionSpec.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,54 @@ class ElasticConversionSpec extends AnyFlatSpec with Matchers with ElasticConver
655655
}
656656
}
657657

658+
it should "parse global aggregation COUNT(*) without GROUP BY" in {
659+
// Simulates: SELECT COUNT(*) FROM ecommerce
660+
// ES response for a global value_count aggregation (no buckets, no GROUP BY)
661+
val results =
662+
"""{
663+
| "took": 3,
664+
| "timed_out": false,
665+
| "hits": { "total": { "value": 20, "relation": "eq" }, "hits": [] },
666+
| "aggregations": {
667+
| "COUNT(*)" : {
668+
| "value": 20
669+
| }
670+
| }
671+
|}""".stripMargin
672+
673+
val aggregations = ListMap(
674+
"COUNT(*)" -> ClientAggregation(
675+
aggName = "COUNT(*)",
676+
aggType = AggregationType.Count,
677+
distinct = false,
678+
sourceField = "*",
679+
windowing = false,
680+
bucketPath = "",
681+
bucketRoot = ""
682+
)
683+
)
684+
685+
// fields as produced by the SQL parser: "*" (artifact) + "COUNT(*)" (actual column)
686+
val fields = Seq("*", "COUNT(*)")
687+
688+
parseResponse(results, ListMap.empty, aggregations, fields) match {
689+
case Success(rows) =>
690+
rows.foreach(println)
691+
rows.size shouldBe 1
692+
val row = rows.head
693+
// Issue #002: bucket_root must not leak into the output
694+
row.keys should not contain "bucket_root"
695+
// Issue #003: "*" must not appear as a column
696+
row.keys should not contain "*"
697+
// Only the aggregation column should be present
698+
row.keys should contain("COUNT(*)")
699+
row("COUNT(*)") shouldBe 20L
700+
row.size shouldBe 1
701+
case Failure(error) =>
702+
throw error
703+
}
704+
}
705+
658706
it should "parse window results with distinct partitions" in {
659707
val results =
660708
"""

0 commit comments

Comments
 (0)