Skip to content

Commit 3fe79c3

Browse files
authored
Merge pull request #22 from SOFTNETWORK-APP/feature/select
- update client apis so as to use generic elastic result - add elastic client companion - add and implement scroll api : - ✅ Retry with exponential backoff - ✅ Automatic tie-breaker for search_after - ✅ PIT (Point In Time) support for consistent snapshots - ✅ Configurable batch size - ✅ Shard failure detection - ✅ Resource cleanup - ✅ Detailed error messages - add and implement metrics and monitoring - add and implement SPI architecture for elastic client api - add specific module for persistence - fix deprecated scala.collection.JavaConverters - choose scroll strategy based on query type and underlying Elasticsearch version - add documentation for all apis
2 parents d3c49d6 + 38ac608 commit 3fe79c3

File tree

196 files changed

+56860
-8645
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

196 files changed

+56860
-8645
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
uses: sbt/setup-sbt@v1
4545
- name: Set vm.max_map_count
4646
run: sudo sysctl -w vm.max_map_count=262144
47+
- name: Cross Compile
48+
run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt + compile
4749
- name: Run tests
4850
run: SBT_OPTS="-Xss4M -Xms1g -Xmx4g -Dfile.encoding=UTF-8" sbt compile test
4951

@@ -65,5 +67,5 @@ jobs:
6567
# cache: 'sbt'
6668
- name: Setup sbt launcher
6769
uses: sbt/setup-sbt@v1
68-
- name: Formatting
69-
run: sbt scalafmtSbtCheck scalafmtCheck test:scalafmtCheck
70+
- name: Checks
71+
run: sbt headerCheck scalafmtSbtCheck scalafmtCheck test:scalafmtCheck

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,34 @@
1111
## Key Features
1212

1313
**Unified Elasticsearch API**
14-
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.
14+
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).
15+
This design abstracts the underlying client implementation and ensures compatibility across different Elasticsearch versions.
1516

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

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

2223
**SQL to Elasticsearch Query Translation**
23-
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.
24+
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.
2425

2526
**Dynamic Mapping Migration**
2627
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.
2728

2829
**High-Performance Bulk API with Akka Streams**
2930
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.
3031

32+
**Scroll API with automatic Scroll Strategy detection**
33+
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.
34+
It automatically selects the optimal scrolling strategy (PIT + search_after, search_after, or classic scroll) based on your query and Elasticsearch version.
35+
3136
**Akka Persistence Integration**
3237
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.
3338

3439
## Roadmap
3540

36-
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.
41+
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.
3742

3843
## License
3944

build.sbt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ ThisBuild / organization := "app.softnetwork"
1919

2020
name := "softclient4es"
2121

22-
ThisBuild / version := "0.9.3"
22+
ThisBuild / version := "0.10.0"
2323

2424
ThisBuild / scalaVersion := scala213
2525

@@ -54,6 +54,22 @@ lazy val moduleSettings = Seq(
5454

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

57+
ThisBuild / javaOptions ++= Seq(
58+
"--add-opens=java.base/java.util=ALL-UNNAMED",
59+
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
60+
"--add-opens=java.base/java.lang=ALL-UNNAMED",
61+
"--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
62+
"--add-opens=java.base/java.math=ALL-UNNAMED",
63+
"--add-opens=java.base/java.io=ALL-UNNAMED",
64+
"--add-opens=java.base/java.net=ALL-UNNAMED",
65+
"--add-opens=java.base/java.nio=ALL-UNNAMED",
66+
"--add-opens=java.base/java.text=ALL-UNNAMED",
67+
"--add-opens=java.base/java.time=ALL-UNNAMED",
68+
"--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
69+
)
70+
71+
Test / javaOptions ++= (javaOptions.value)
72+
5773
ThisBuild / resolvers ++= Seq(
5874
"Softnetwork Server" at "https://softnetwork.jfrog.io/artifactory/releases/",
5975
"Softnetwork Snapshots" at "https://softnetwork.jfrog.io/artifactory/snapshots/",
@@ -75,6 +91,7 @@ val json4s = Seq(
7591
).map(_.excludeAll(jacksonExclusions: _*))
7692

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

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

121+
lazy val persistence = project
122+
.in(file("persistence"))
123+
.configs(IntegrationTest)
124+
.settings(
125+
Defaults.itSettings,
126+
moduleSettings
127+
)
128+
.dependsOn(
129+
core % "compile->compile;test->test;it->it"
130+
)
131+
104132
def copyTestkit(esVersion: String): Def.Initialize[Task[Unit]] = Def.task {
105133
val src = file("core/testkit")
106134
val target = baseDirectory.value
@@ -136,7 +164,7 @@ def testkitProject(esVersion: String, ss: Def.SettingsDefinition*): Project = {
136164
.settings(ss: _*)
137165
.enablePlugins(BuildInfoPlugin)
138166
.dependsOn(
139-
core % "compile->compile;test->test;it->it"
167+
persistence % "compile->compile;test->test;it->it"
140168
)
141169
}
142170

@@ -383,6 +411,7 @@ lazy val root = project
383411
.aggregate(
384412
sql,
385413
core,
414+
persistence,
386415
es6,
387416
es7,
388417
es8,

core/build.sbt

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,32 @@ organization := "app.softnetwork.elastic"
44

55
name := "softclient4es-core"
66

7-
val configDependencies = Seq(
8-
"com.typesafe" % "config" % Versions.typesafeConfig
7+
val akka = Seq(
8+
"com.typesafe.akka" %% "akka-actor" % Versions.akka,
9+
"com.typesafe.akka" %% "akka-cluster-sharding-typed" % Versions.akka,
10+
"com.typesafe.akka" %% "akka-slf4j" % Versions.akka,
11+
"com.typesafe.akka" %% "akka-discovery" % Versions.akka,
12+
"com.typesafe.akka" %% "akka-stream" % Versions.akka
13+
)
14+
15+
val typesafeConfig = Seq(
16+
"com.typesafe" % "config" % Versions.typesafeConfig,
17+
"com.github.kxbmap" %% "configs" % Versions.kxbmap
18+
)
19+
20+
val http = Seq(
21+
"org.apache.httpcomponents" % "httpcore" % "4.4.12" % "provided"
922
)
1023

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

16-
libraryDependencies ++= configDependencies ++
17-
json4s :+ "com.google.code.gson" % "gson" % Versions.gson :+
18-
("app.softnetwork.persistence" %% "persistence-core" % Versions.genericPersistence excludeAll (jacksonExclusions *))
29+
val mockito = Seq(
30+
"org.mockito" %% "mockito-scala" % "1.17.12" % Test
31+
)
32+
33+
libraryDependencies ++= akka ++ typesafeConfig ++ http ++
34+
json4s ++ mockito :+ "com.google.code.gson" % "gson" % Versions.gson :+
35+
"com.typesafe.scala-logging" %% "scala-logging" % Versions.scalaLogging
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
elastic {
2-
ip = "localhost"
3-
ip = ${?ELASTIC_IP}
2+
# Connection settings
3+
host = "localhost"
4+
host = ${?ELASTIC_HOST}
5+
host = ${?ELASTIC_IP} # Alternative environment variable for host IP for backward compatibility
46
port = 9200
57
port = ${?ELASTIC_PORT}
68

9+
# Authentication
710
credentials {
8-
url = "http://"${elastic.ip}":"${elastic.port}
11+
url = "http://"${elastic.host}":"${elastic.port}
912
username = ""
1013
password = ""
1114

@@ -15,7 +18,25 @@ elastic {
1518

1619
}
1720

21+
# Performance
1822
multithreaded = true
19-
discovery-enabled = false
23+
connection-timeout = 5s
24+
socket-timeout = 30s
2025

26+
# Cluster discovery
27+
discovery {
28+
enabled = false
29+
frequency = 5m
30+
}
31+
32+
# Metrics and Monitoring
33+
metrics {
34+
enabled = true
35+
monitoring {
36+
enabled = true
37+
interval = 30s
38+
failure-rate-threshold = 10.0 # Alert if > 10% failures
39+
latency-threshold = 1000.0 # Alert if average latency > 1000ms
40+
}
41+
}
2142
}

core/src/main/scala-2.12/app/softnetwork/elastic/client/ElasticConfig.scala

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,49 @@
1+
/*
2+
* Copyright 2025 SOFTNETWORK
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
117
package app.softnetwork.elastic.client
218

319
import com.typesafe.config.{Config, ConfigFactory}
420
import com.typesafe.scalalogging.StrictLogging
521
import configs.Configs
622

23+
import java.time.Duration
24+
25+
/** Complete Elasticsearch client configuration.
26+
*
27+
* @param credentials
28+
* Connection credentials (url, username, password)
29+
* @param multithreaded
30+
* Enables multi-threaded mode for parallel operations
31+
* @param discovery
32+
* Automatic cluster node discovery configuration
33+
* @param connectionTimeout
34+
* Connection timeout to the cluster
35+
* @param socketTimeout
36+
* Socket operation timeout
37+
* @param metrics
38+
* Metrics and monitoring configuration
39+
*/
740
case class ElasticConfig(
841
credentials: ElasticCredentials = ElasticCredentials(),
942
multithreaded: Boolean = true,
10-
discoveryEnabled: Boolean = false
43+
discovery: DiscoveryConfig,
44+
connectionTimeout: Duration,
45+
socketTimeout: Duration,
46+
metrics: MetricsConfig
1147
)
1248

1349
object ElasticConfig extends StrictLogging {

core/src/main/scala-2.13/app/softnetwork/elastic/client/ElasticConfig.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,35 @@
1616

1717
package app.softnetwork.elastic.client
1818

19+
import app.softnetwork.elastic.client.metrics.MetricsConfig
1920
import com.typesafe.config.{Config, ConfigFactory}
2021
import com.typesafe.scalalogging.StrictLogging
2122
import configs.ConfigReader
2223

24+
import java.time.Duration
25+
26+
/** Complete Elasticsearch client configuration.
27+
*
28+
* @param credentials
29+
* Connection credentials (url, username, password)
30+
* @param multithreaded
31+
* Enables multi-threaded mode for parallel operations
32+
* @param discovery
33+
* Automatic cluster node discovery configuration
34+
* @param connectionTimeout
35+
* Connection timeout to the cluster
36+
* @param socketTimeout
37+
* Socket operation timeout
38+
* @param metrics
39+
* Metrics and monitoring configuration
40+
*/
2341
case class ElasticConfig(
2442
credentials: ElasticCredentials = ElasticCredentials(),
2543
multithreaded: Boolean = true,
26-
discoveryEnabled: Boolean = false
44+
discovery: DiscoveryConfig,
45+
connectionTimeout: Duration,
46+
socketTimeout: Duration,
47+
metrics: MetricsConfig
2748
)
2849

2950
object ElasticConfig extends StrictLogging {

0 commit comments

Comments
 (0)