Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
dd66c36
init parser for elasticsearch response
fupelaqu Oct 22, 2025
b2daf33
add generic search and multisearch api, add generic conversion of ela…
fupelaqu Oct 23, 2025
20b9522
add sql aggregation, add generic sql search response, update generic …
fupelaqu Oct 23, 2025
c38f36f
fix search for elasticsearch java clients (v8, v9)
fupelaqu Oct 23, 2025
f6dae77
update version to v0.10.0
fupelaqu Oct 23, 2025
a13dde2
cleaning the code related to aggregations
fupelaqu Oct 23, 2025
1366d55
add scroll api
fupelaqu Oct 24, 2025
fd43a03
finalize scroll api
fupelaqu Oct 25, 2025
915e06d
add support for PIT and search_after for es java clients
fupelaqu Oct 25, 2025
78dd1e0
add support for PIT and search_after for es 7.10+
fupelaqu Oct 25, 2025
d7b5b5f
add specifications for elasticsearch version
fupelaqu Oct 25, 2025
899fd96
add Thread-safe companion for RestHighLevelClient with lazy initializ…
fupelaqu Oct 25, 2025
22fc23d
add specifications for rest high level client companion
fupelaqu Oct 25, 2025
da33e49
add elastic client companion, update rest and jest client companions
fupelaqu Oct 26, 2025
512a9ec
update java client companions
fupelaqu Oct 26, 2025
f13e06e
update jest, rest and java client apis
fupelaqu Oct 26, 2025
c6f7d8c
update checks
fupelaqu Oct 26, 2025
4302c70
fix elastic config for scala 2.12
fupelaqu Oct 26, 2025
73dc79b
fix deprecated scala.collection.JavaConverters
fupelaqu Oct 26, 2025
71df60c
thread-safe (elastic client api) + use of embedded elastic test kit w…
fupelaqu Oct 26, 2025
d292117
take into account inner_hits within conversion, add first scroll tests
fupelaqu Oct 26, 2025
82db032
rename SQLSearchResponse ElasticResponse
fupelaqu Oct 27, 2025
7c19f41
rename ElasticQuery ElasticBridge
fupelaqu Oct 27, 2025
943eb9c
rename JSONQuery ElasticQuery
fupelaqu Oct 27, 2025
6187739
add logEvery to scroll config
fupelaqu Oct 27, 2025
294cd15
fix scroll as and elastic client specifications for scrolling
fupelaqu Oct 27, 2025
747553d
fix query with top hits, aggregate api with nested aggregations and a…
fupelaqu Oct 27, 2025
03075f1
fix query with top hits, aggregate api with nested aggregations and a…
fupelaqu Oct 27, 2025
4bfa196
update errors handling within aggregation api
fupelaqu Oct 27, 2025
b4f0f77
update SQL documentation
fupelaqu Oct 27, 2025
0c5bc91
comment CTE best practice (not yet implemented)
fupelaqu Oct 27, 2025
4e9a7f8
add SPI architecture to instantiate Elastic client api, add metrics a…
fupelaqu Oct 27, 2025
3f2feaf
finalize SPI architecture, update metrics collector, monitoring servi…
fupelaqu Oct 28, 2025
4dfba7a
remove persistence references within core module
fupelaqu Oct 28, 2025
20f2aa8
add persistence module
fupelaqu Oct 28, 2025
2900043
add missing license header
fupelaqu Oct 28, 2025
aca5496
add specific packages for bulk, metrics, monitoring and scroll
fupelaqu Oct 28, 2025
5204a3e
add minimalist exporter for Prometheus
fupelaqu Oct 28, 2025
512f823
extract all apis to use ElasticResult + update jest implementation ac…
fupelaqu Nov 3, 2025
9bef031
add rest high level client helpers, add BulkErrorAnalyzer, update res…
fupelaqu Nov 4, 2025
08971cb
add java client helpers, add ElasticsearchConversion, update java cli…
fupelaqu Nov 4, 2025
e1c9654
update AliasApi
fupelaqu Nov 5, 2025
f693dc7
add specifications for version, indices, settings and refresh apis
fupelaqu Nov 5, 2025
ade991d
do not accept comments within json
fupelaqu Nov 5, 2025
5442730
add trait to validate logs while testing
fupelaqu Nov 5, 2025
7b41c04
add mapping specifications
fupelaqu Nov 5, 2025
4a1a17c
remove unused imports
fupelaqu Nov 5, 2025
04b805b
rename ElasticsearchClient to JavaClient
fupelaqu Nov 5, 2025
9ce1980
update documentation adding client README.md and client common princi…
fupelaqu Nov 5, 2025
48238f6
update scroll api adding explicit UsePIT scroll strategy (taking into…
fupelaqu Nov 6, 2025
38ac608
add documentation for get api, update main README adding scroll api
fupelaqu Nov 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ jobs:
uses: sbt/setup-sbt@v1
- name: Set vm.max_map_count
run: sudo sysctl -w vm.max_map_count=262144
- name: Cross Compile
run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt + compile
- name: Run tests
run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt compile test

Expand All @@ -65,5 +67,5 @@ jobs:
# cache: 'sbt'
- name: Setup sbt launcher
uses: sbt/setup-sbt@v1
- name: Formatting
run: sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck
- name: Checks
run: sbt headerCheck scalafmtSbtCheck scalafmtCheck test:scalafmtCheck
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,34 @@
## Key Features

**Unified Elasticsearch API**
This project provides a trait-based interface (`ElasticClientApi`) that aggregates the core functionalities of Elasticsearch: indexing, searching, updating, deleting, mapping, aliases, refreshing, and more. This design abstracts the underlying client implementation and ensures compatibility across different Elasticsearch versions.
This project provides a trait-based interface (`ElasticClientApi`) that aggregates the core functionalities of Elasticsearch: [indexing](documentation/client/index.md), [updating](documentation/client/update.md), [deleting](documentation/client/delete.md), [bulk](documentation/client/bulk.md), [searching](documentation/client/search.md), [scrolling](documentation/client/scroll.md), [mapping](documentation/client/mappings.md), [aliases](documentation/client/aliases.md), [refreshing](documentation/client/refresh.md), and [more](documentation/client/README.md).
This design abstracts the underlying client implementation and ensures compatibility across different Elasticsearch versions.

- `JestClientApi`: For Elasticsearch 6 using the open-source [Jest client](https://github.com/searchbox-io/Jest).
- `JavaClientApi`: For Elasticsearch 8 and 9 using the official Java client.
- `RestHighLevelClientApi`: For Elasticsearch 6 and 7 using the official high-level REST client.
- `ElasticsearchClientApi`: For Elasticsearch 8 and 9 using the official Java client.
- `JestClientApi`: For Elasticsearch 6 using the open-source [Jest client](https://github.com/searchbox-io/Jest).

By relying on these concrete implementations, developers can switch between versions with minimal changes to their business logic.

**SQL to Elasticsearch Query Translation**
Elastic Client includes a parser capable of translating SQL `SELECT` queries into Elasticsearch queries. The parser produces an intermediate representation, which is then converted into [Elastic4s](https://github.com/sksamuel/elastic4s) DSL queries and ultimately into native Elasticsearch queries. This allows data engineers and analysts to express queries in familiar [SQL](documentation/README.md) syntax.
Elastic Client includes a parser capable of translating SQL `SELECT` queries into Elasticsearch queries. The parser produces an intermediate representation, which is then converted into [Elastic4s](https://github.com/sksamuel/elastic4s) DSL queries and ultimately into native Elasticsearch queries. This allows data engineers and analysts to express queries in familiar [SQL](documentation/sql/README.md) syntax.

**Dynamic Mapping Migration**
Elastic Client provides tools to analyze and compare existing mappings with new ones. If differences are detected, it can automatically perform safe migrations. This includes creating temporary indices, reindexing, and renaming — all while preserving data integrity. This eliminates the need for manual mapping migrations and reduces downtime.

**High-Performance Bulk API with Akka Streams**
Bulk operations leverage the power of Akka Streams to efficiently process and index large volumes of data. This stream-based approach improves performance, resilience, and backpressure handling, especially for real-time or high-throughput indexing scenarios.

**Scroll API with automatic Scroll Strategy detection**
The Scroll API is also integrated with Akka Streams, enabling efficient retrieval of large datasets in a streaming fashion. This allows applications to process search results incrementally, reducing memory consumption and improving responsiveness.
It automatically selects the optimal scrolling strategy (PIT + search_after, search_after, or classic scroll) based on your query and Elasticsearch version.

**Akka Persistence Integration**
The project offers seamless integration with Akka Persistence. This enables Elasticsearch indices to be updated reactively based on persistent events, offering a robust pattern for event-sourced systems.

## Roadmap

Future enhancements include expanding the SQL parser to support additional operations such as `INSERT`, `UPDATE`, and `DELETE`. The long-term vision is to deliver a fully functional, open-source **JDBC connector for Elasticsearch**, empowering users to interact with their data using standard SQL tooling.
Future enhancements include expanding the SQL parser to support additional operations such as `CREATE`, `ALTER`, `INSERT`, `UPDATE`, and `DELETE`. The long-term vision is to deliver a fully functional, open-source **JDBC connector for Elasticsearch**, empowering users to interact with their data using standard SQL tooling.

## License

Expand Down
33 changes: 31 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ThisBuild / organization := "app.softnetwork"

name := "softclient4es"

ThisBuild / version := "0.9.3"
ThisBuild / version := "0.10.0"

ThisBuild / scalaVersion := scala213

Expand Down Expand Up @@ -54,6 +54,22 @@ lazy val moduleSettings = Seq(

ThisBuild / javacOptions ++= Seq("-source", "1.8", "-target", "1.8")

ThisBuild / javaOptions ++= Seq(
"--add-opens=java.base/java.util=ALL-UNNAMED",
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
"--add-opens=java.base/java.lang=ALL-UNNAMED",
"--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
"--add-opens=java.base/java.math=ALL-UNNAMED",
"--add-opens=java.base/java.io=ALL-UNNAMED",
"--add-opens=java.base/java.net=ALL-UNNAMED",
"--add-opens=java.base/java.nio=ALL-UNNAMED",
"--add-opens=java.base/java.text=ALL-UNNAMED",
"--add-opens=java.base/java.time=ALL-UNNAMED",
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
)

Test / javaOptions ++= (javaOptions.value)

ThisBuild / resolvers ++= Seq(
"Softnetwork Server" at "https://softnetwork.jfrog.io/artifactory/releases/",
"Softnetwork Snapshots" at "https://softnetwork.jfrog.io/artifactory/snapshots/",
Expand All @@ -75,6 +91,7 @@ val json4s = Seq(
).map(_.excludeAll(jacksonExclusions: _*))

ThisBuild / libraryDependencies ++= Seq(
"org.scala-lang.modules" %% "scala-collection-compat" % "2.11.0",
"org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2"
) // ++ configDependencies ++ json4s ++ logging

Expand All @@ -101,6 +118,17 @@ lazy val core = project
sql % "compile->compile;test->test;it->it"
)

lazy val persistence = project
.in(file("persistence"))
.configs(IntegrationTest)
.settings(
Defaults.itSettings,
moduleSettings
)
.dependsOn(
core % "compile->compile;test->test;it->it"
)

def copyTestkit(esVersion: String): Def.Initialize[Task[Unit]] = Def.task {
val src = file("core/testkit")
val target = baseDirectory.value
Expand Down Expand Up @@ -136,7 +164,7 @@ def testkitProject(esVersion: String, ss: Def.SettingsDefinition*): Project = {
.settings(ss: _*)
.enablePlugins(BuildInfoPlugin)
.dependsOn(
core % "compile->compile;test->test;it->it"
persistence % "compile->compile;test->test;it->it"
)
}

Expand Down Expand Up @@ -383,6 +411,7 @@ lazy val root = project
.aggregate(
sql,
core,
persistence,
es6,
es7,
es8,
Expand Down
27 changes: 22 additions & 5 deletions core/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,32 @@ organization := "app.softnetwork.elastic"

name := "softclient4es-core"

val configDependencies = Seq(
"com.typesafe" % "config" % Versions.typesafeConfig
val akka = Seq(
"com.typesafe.akka" %% "akka-actor" % Versions.akka,
"com.typesafe.akka" %% "akka-cluster-sharding-typed" % Versions.akka,
"com.typesafe.akka" %% "akka-slf4j" % Versions.akka,
"com.typesafe.akka" %% "akka-discovery" % Versions.akka,
"com.typesafe.akka" %% "akka-stream" % Versions.akka
)

val typesafeConfig = Seq(
"com.typesafe" % "config" % Versions.typesafeConfig,
"com.github.kxbmap" %% "configs" % Versions.kxbmap
)

val http = Seq(
"org.apache.httpcomponents" % "httpcore" % "4.4.12" % "provided"
)

val json4s = Seq(
"org.json4s" %% "json4s-jackson" % Versions.json4s,
"org.json4s" %% "json4s-ext" % Versions.json4s
).map(_.excludeAll(jacksonExclusions *))

libraryDependencies ++= configDependencies ++
json4s :+ "com.google.code.gson" % "gson" % Versions.gson :+
("app.softnetwork.persistence" %% "persistence-core" % Versions.genericPersistence excludeAll (jacksonExclusions *))
val mockito = Seq(
"org.mockito" %% "mockito-scala" % "1.17.12" % Test
)

libraryDependencies ++= akka ++ typesafeConfig ++ http ++
json4s ++ mockito :+ "com.google.code.gson" % "gson" % Versions.gson :+
"com.typesafe.scala-logging" %% "scala-logging" % Versions.scalaLogging
29 changes: 25 additions & 4 deletions core/src/main/resources/softnetwork-elastic.conf
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
elastic {
ip = "localhost"
ip = ${?ELASTIC_IP}
# Connection settings
host = "localhost"
host = ${?ELASTIC_HOST}
host = ${?ELASTIC_IP} # Alternative environment variable for host IP for backward compatibility
port = 9200
port = ${?ELASTIC_PORT}

# Authentication
credentials {
url = "http://"${elastic.ip}":"${elastic.port}
url = "http://"${elastic.host}":"${elastic.port}
username = ""
password = ""

Expand All @@ -15,7 +18,25 @@ elastic {

}

# Performance
multithreaded = true
discovery-enabled = false
connection-timeout = 5s
socket-timeout = 30s

# Cluster discovery
discovery {
enabled = false
frequency = 5m
}

# Metrics and Monitoring
metrics {
enabled = true
monitoring {
enabled = true
interval = 30s
failure-rate-threshold = 10.0 # Alert if > 10% failures
latency-threshold = 1000.0 # Alert if average latency > 1000ms
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
/*
* Copyright 2025 SOFTNETWORK
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app.softnetwork.elastic.client

import com.typesafe.config.{Config, ConfigFactory}
import com.typesafe.scalalogging.StrictLogging
import configs.Configs

import java.time.Duration

/** Complete Elasticsearch client configuration.
*
* @param credentials
* Connection credentials (url, username, password)
* @param multithreaded
* Enables multi-threaded mode for parallel operations
* @param discovery
* Automatic cluster node discovery configuration
* @param connectionTimeout
* Connection timeout to the cluster
* @param socketTimeout
* Socket operation timeout
* @param metrics
* Metrics and monitoring configuration
*/
case class ElasticConfig(
credentials: ElasticCredentials = ElasticCredentials(),
multithreaded: Boolean = true,
discoveryEnabled: Boolean = false
discovery: DiscoveryConfig,
connectionTimeout: Duration,
socketTimeout: Duration,
metrics: MetricsConfig
)

object ElasticConfig extends StrictLogging {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,35 @@

package app.softnetwork.elastic.client

import app.softnetwork.elastic.client.metrics.MetricsConfig
import com.typesafe.config.{Config, ConfigFactory}
import com.typesafe.scalalogging.StrictLogging
import configs.ConfigReader

import java.time.Duration

/** Complete Elasticsearch client configuration.
*
* @param credentials
* Connection credentials (url, username, password)
* @param multithreaded
* Enables multi-threaded mode for parallel operations
* @param discovery
* Automatic cluster node discovery configuration
* @param connectionTimeout
* Connection timeout to the cluster
* @param socketTimeout
* Socket operation timeout
* @param metrics
* Metrics and monitoring configuration
*/
case class ElasticConfig(
credentials: ElasticCredentials = ElasticCredentials(),
multithreaded: Boolean = true,
discoveryEnabled: Boolean = false
discovery: DiscoveryConfig,
connectionTimeout: Duration,
socketTimeout: Duration,
metrics: MetricsConfig
)

object ElasticConfig extends StrictLogging {
Expand Down
Loading