← All posts
SQL for Elasticsearch · Part 6

Connect DBeaver to Elasticsearch. Yes, Really.

A JDBC Type 4 driver that lets DBeaver, DataGrip and Superset query Elasticsearch as if it were a database.

·5 min read

This is Part 6 of the SoftClient4ES series. Previously: Elasticsearch Queries That Never Break in Production, Stop Rewriting Your Elasticsearch Code Every Version Upgrade, It’s 3 AM. Production Is Down. Your Only Tool Is curl., Elasticsearch Schema Management Was Hell. Then Someone Typed SQL., and A 47-Line curl Script to Insert One Document. Seriously.

The BI Gap

A data analytics team uses Elasticsearch to store millions of customer events. They need weekly reports, ad-hoc queries, and dashboards.

Their current workflow:

1. Analyst writes requirements in a Jira ticket
2. Developer translates requirements into Elasticsearch JSON DSL
3. Developer runs query, exports results to CSV
4. Analyst opens CSV in Excel
5. Analyst realizes they need a different grouping
6. Go back to step 1
Average turnaround: 2-3 days per query.

The analyst knows SQL. The data is in Elasticsearch. The gap between the two is a developer acting as a human translator.

What if the analyst could just… connect directly?

One JAR. One Connection String. Full SQL.

The SoftClient4ES JDBC driver turns Elasticsearch into a SQL database that any JDBC-compatible tool can query.

JDBC URL: jdbc:elastic://localhost:9200
Driver class: app.softnetwork.elastic.jdbc.ElasticDriver

That’s it. Two lines of configuration. No Elasticsearch knowledge required on the client side.

Setting Up DBeaver (Step by Step)

Step 1: Download the Driver JAR

Download the self-contained fat JAR for your Elasticsearch version:

Elasticsearch VersionArtifact
ES 6.xsoftclient4es6-jdbc-driver-0.3.0.jar
ES 7.xsoftclient4es7-jdbc-driver-0.3.0.jar
ES 8.xsoftclient4es8-jdbc-driver-0.3.0.jar
ES 9.xsoftclient4es9-jdbc-driver-0.3.0.jar

One JAR. No external dependencies. No Scala version suffix. Works with any JVM (Java 8+).

Step 2: Add a New Driver in DBeaver

  1. Open DBeaver > Database > Driver Manager
  2. Click New
  3. Fill in:
  • Driver Name: SoftClient4ES
  • Class Name: app.softnetwork.elastic.jdbc.ElasticDriver
  • URL Template: jdbc:elastic://{host}:{port}
  • Default Port: 9200
  1. Go to the Libraries tab

  2. Click Add File and select the downloaded JAR

  3. Click OK

Step 3: Create a Connection

  1. Database > New Database Connection
  2. Select the SoftClient4ES driver
  3. Enter your Elasticsearch host and port
  4. Click Test Connection — should succeed immediately
  5. Click Finish

Step 4: Query

SELECT
customer_segment,
COUNT(*) as order_count,
SUM(amount) as total_revenue,
AVG(amount) as avg_order_value
FROM orders
WHERE status = 'completed'
AND created_at >= '2025-01-01'
GROUP BY customer_segment
ORDER BY total_revenue DESC;

In DBeaver. With syntax highlighting. With export to CSV, Excel, or JSON.

The analyst went from “file a Jira ticket” to “run the query yourself” in under five minutes.

Connection URL Parameters

The JDBC URL supports a range of connection parameters:

jdbc:elastic://host:port?param=value&param2=value2
ParameterDescriptionExample
user / usernameAuthentication usernameuser=admin
passwordAuthentication passwordpassword=secret
sslEnable HTTPSssl=true
apiKey / api-keyAPI key authenticationapiKey=mykey123
bearerToken / bearer-tokenBearer token authenticationbearerToken=tok123
connectionTimeout / connection-timeoutConnection timeoutconnectionTimeout=10s
socketTimeout / socket-timeoutSocket/read timeoutsocketTimeout=60s

Authentication examples:

# Basic auth
jdbc:elastic://es-prod:9200?user=admin&password=secret
# API key
jdbc:elastic://es-prod:9200?apiKey=mykey123
# Bearer token + SSL
jdbc:elastic://es-prod:9200?ssl=true&bearerToken=my-token
# Custom timeouts
jdbc:elastic://es-prod:9200?connectionTimeout=10s&socketTimeout=120s

What Works Through JDBC

Everything. The JDBC driver exposes the full SoftClient4ES SQL surface.

DDL (Schema Management)

CREATE TABLE products (
id KEYWORD NOT NULL,
name VARCHAR,
price DOUBLE DEFAULT 0.0,
PRIMARY KEY (id)
);
ALTER TABLE products ADD COLUMN IF NOT EXISTS stock INT;
DESCRIBE TABLE products;
SHOW TABLES LIKE 'product%';
SHOW CREATE TABLE products;

DML (Data Operations)

INSERT INTO products (id, name, price)
VALUES ('p1', 'Laptop', 999.99);
UPDATE products SET price = 899.99 WHERE id = 'p1';
DELETE FROM products WHERE stock = 0;
COPY INTO products FROM '/data/catalog.jsonl';

DQL (Queries)

SELECT name, price
FROM products
WHERE price > 100
ORDER BY price DESC
LIMIT 50;
SELECT category, COUNT(*) as product_count, AVG(price) as avg_price
FROM products
GROUP BY category
HAVING COUNT(*) > 5;

Materialized Views

-- Automatic refresh (requires ES license)
CREATE MATERIALIZED VIEW orders_with_customers_mv
REFRESH EVERY 8 SECONDS
WITH (delay = '1s', user_latency = '1s')
AS
SELECT o.id, o.amount, c.name AS customer_name
FROM orders AS o
JOIN customers AS c ON o.customer_id = c.id;
-- Without ES license: schedule this yourself (cron, Airflow, etc.)
REFRESH MATERIALIZED VIEW orders_with_customers_mv;
SELECT * FROM orders_with_customers_mv
WHERE customer_name = 'Alice';

Supported Tools

ToolStatusUse Case
DBeaverTestedAd-hoc queries, data exploration, export
DataGripTestedDeveloper SQL IDE
Apache SupersetTestedDashboards, BI reporting (dedicated dialect)
TableauCompatibleDashboards, BI reporting
Power BICompatibleDashboards, BI reporting
DbVisualizerCompatibleDatabase management
Any JDBC appCompatibleJava, Scala, Kotlin applications

Programmatic JDBC Usage

Maven / Gradle / sbt

<!-- Maven -->
<dependency>
<groupId>app.softnetwork.elastic</groupId>
<artifactId>softclient4es8-jdbc-driver</artifactId>
<version>0.3.0</version>
</dependency>
// Gradle
implementation 'app.softnetwork.elastic:softclient4es8-jdbc-driver:0.3.0'
// sbt
resolvers += "Softnetwork" at "https://softnetwork.jfrog.io/artifactory/releases/"
libraryDependencies += "app.softnetwork.elastic" % "softclient4es8-jdbc-driver" % "0.3.0"

Note: The artifact has no _2.12 or _2.13 suffix — it’s Scala-version-independent.

Java Example

import java.sql.*;
// Connection (driver auto-registers via SPI)
Connection conn = DriverManager.getConnection(
"jdbc:elastic://localhost:9200"
);
// Query
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT name, price FROM products WHERE price > 100 ORDER BY price DESC"
);
while (rs.next()) {
System.out.println(rs.getString("name") + " - $" + rs.getDouble("price"));
}
// DML
int count = stmt.executeUpdate(
"INSERT INTO products (id, name, price) VALUES ('p42', 'Widget', 19.99)"
);
System.out.println("Inserted: " + count);
// PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(
"SELECT * FROM products WHERE category = ? AND price > ?"
);
pstmt.setString(1, "Electronics");
pstmt.setDouble(2, 50.0);
ResultSet rs2 = pstmt.executeQuery();
// Cleanup
rs.close();
stmt.close();
conn.close();

Kotlin Example

DriverManager.getConnection("jdbc:elastic://localhost:9200").use { conn ->
conn.createStatement().use { stmt ->
val rs = stmt.executeQuery("SELECT name, price FROM products ORDER BY price DESC LIMIT 10")
while (rs.next()) {
println("${rs.getString("name")} — $${rs.getDouble("price")}")
}
}
}

Architecture

┌──────────────┐ JDBC ┌──────────────────────┐ REST API ┌───────────────┐
│ DBeaver │ ────────────── │ SoftClient4ES │ ──────────────── │ Elasticsearch │
│ Tableau │ SQL over │ JDBC Driver │ Optimized DSL │ 6/7/8/9 │
│ DataGrip │ JDBC │ (fat JAR, no deps) │ │ │
│ Your App │ │ │ │ │
└──────────────┘ └──────────────────────┘ └───────────────┘

The driver is a pure JDBC Type 4 driver — no native libraries, no middleware. Your application sends SQL; the driver translates it to optimized Elasticsearch REST API calls and returns standard JDBC ResultSets.

Key architectural decisions:

  • Self-contained fat JAR: All dependencies bundled. Drop it into DBeaver’s driver folder and go.
  • Per-connection ActorSystem: Each JDBC connection manages its own lifecycle — no shared state, no concurrency issues.
  • Client-side PreparedStatement: Parameter substitution happens before SQL parsing — supports all Java date/time types with proper escaping.
  • Streaming under the hood: Large result sets use Akka Streams internally, materialized to JDBC ResultSets.

Editions

The JDBC driver is available as a free community edition:

FeatureCommunity (free)ProEnterprise
Full DDL / DML / DQLYesYesYes
JDBC driverYesYesYes
Materialized ViewsYes (1 view)Yes (50 views)Unlimited
Priority supportYes

The community driver JAR includes the community extensions library (materialized views, capped at 1).

Before & After

ScenarioBeforeAfter
Analyst needs a reportFile Jira ticket → wait 2-3 daysOpen DBeaver → query directly
Data explorationAsk a developer to translate to JSON DSLWrite SQL, iterate instantly
Dashboard creationExport pipeline: ES → CSV → Excel → TableauTableau → JDBC → ES (live)
Application integrationCustom REST client + JSON parsingStandard JDBC (DriverManager.getConnection)
Team onboardingLearn Elasticsearch Query DSLUse SQL (everyone knows it)

Getting Started

Quick Test (REPL)

Terminal window
# Install the REPL
curl -fsSL https://raw.githubusercontent.com/SOFTNETWORK-APP/softclient4es/main/install.sh | bash
# Connect and verify SQL works
softclient4es --host localhost --port 9200
sql> SHOW TABLES;
sql> SELECT COUNT(*) FROM your_index;
sql> exit
Goodbye!

DBeaver Setup

  1. Download the JAR for your ES version
  2. Add it as a driver in DBeaver (Driver Manager > New)
  3. Create a connection: jdbc:elastic://your-host:9200
  4. Start querying

Java/Scala Application

  1. Add the Maven/Gradle/sbt dependency
  2. DriverManager.getConnection("jdbc:elastic://host:9200")
  3. Use standard JDBC API

Resources

How long does your team wait for data extracts from Elasticsearch? If the answer involves Jira tickets and developer time, there might be a faster way.

P.S. — The JDBC driver works on Elasticsearch 6, 7, 8, and 9. One JAR per ES version. No Scala dependency. Drop it in and go.

Next in the series: JOINs in Elasticsearch? One SQL Statement. Zero Application Code. — how materialized views bring real JOINs, precomputed aggregations, and continuous refresh to Elasticsearch.

This post first appeared on Medium. This is the maintained version — free to read, no account, and corrected as the product moves.

Try it on your own cluster

SoftClient4ES runs SQL — DDL, DML, queries, cross-index JOINs and materialized views — on Elasticsearch 6 through 9.