Core+ Java Client
The Core+ client allows you to connect to Persistent Queries using the Community Core engine in the Deephaven Enterprise system. You may connect to a new temporary Persistent Query or one of the Persistent Queries you have access to on the server.
The Java client is available in two packages: client-flight
and client-barrage
.
- The
client-flight
package is a Java 8 compatible minimal client that lets you access static snapshots of Deephaven tables using the Arrow Flight protocol. - The
client-barrage
package requires at least Java 11, but also includes Deephaven's Barrage flight extension. This allows you to use the full power of the ticking Deephaven engine.
This Gradle script configures a Gradle application project to use the client-barrage
library.
Note
This example requires that you have access to Deephaven's artifactory and an API Key to connect to it. You must also update the dhcVersion
and dheVersion
variables to reflect the version of Deephaven that you are connecting to.
plugins {
id 'application'
}
def dhcVersion="0.33.6"
def dheVersion="1.20231218.432"
// Note that you should NOT store your API key in a build.gradle file that could end up committed to version control.
// A better location would be a gradle.properties file
def artifactoryAPIKey="YOUR API KEY HERE"
repositories {
mavenCentral()
maven {
credentials {
username = artifactoryUser ?: System.getProperty('user.name')
password = artifactoryAPIKey ?: ''
}
url "https://illumon.jfrog.io/illumon/libs-customer"
}
maven {
credentials {
username = artifactoryUser ?: System.getProperty('user.name')
password = artifactoryAPIKey ?: ''
}
url "https://illumon.jfrog.io/illumon/libs-build"
}
}
dependencies {
// DHC dependencies
implementation platform("io.deephaven:deephaven-bom:${dhcVersion}")
runtimeOnly "io.deephaven:deephaven-log-to-slf4j"
runtimeOnly 'ch.qos.logback:logback-classic:1.4.5'
// END DHC dependencies
implementation "iris:client-barrage:$dheVersion"
}
application {
mainClassName = 'io.deephaven.enterprise.dnd.client.example.ClientExample'
applicationDefaultJvmArgs = ["-DDeephavenEnterprise.rootFile=iris-common.prop",
"-DConfiguration.rootFile=deephaven.prop",
"--add-opens=java.base/java.nio=ALL-UNNAMED"]
}
To get started, you must first direct Deephaven to load properties via a URL.
The URL is the same one you would use to configure launcher instances. Typically, this means port 8000
when your system is configured to use Envoy or port 8123
without Envoy.
Setting the properties URL must be done before any other Deephaven classes are used, otherwise static fields in classes fail to initialize.
final String serverUrl = "https://deephaven-host:8000";
// Configure the Configuration library to load configuration files via HTTP from the specified URL
HttpUrlPropertyInputStreamLoader.setServerUrl(serverUrl);
Next, create a session that will load the connection configuration from the URL:
// Create the session factory for Barrage. This creates the connections to the server and downloads the
// configuration.
final DndSessionFactoryBarrage sessionFactory = new DndSessionFactoryBarrage(serverUrl + "/iris/connection.json");
// Create the session factory for Flight. This creates the connections to the server and downloads the
// configuration.
final DndSessionFactoryFlight sessionFactory = new DndSessionFactoryFlight(serverUrl + "/iris/connection.json");
You must then authenticate with a username and password:
sessionFactory.password("user", "password");
Or using a private key:
sessionFactory.privateKey("/path/to/key_base64.txt");
At this point, you can connect to an existing Persistent Query. The session object contains a few basic methods for interacting with tables and also provides access to the base SessionImpl
which can be used to directly interact with the worker.
final DndSessionBarrage session = sessionFactory.persistentQuery("MyTestQuery");
Alternatively, you could create a new temporary Persistent Query to host your worker:
final DndSessionBarrage session = sessionFactory.newWorker("ExampleTestWorker", 2, 600_000, 10_000);
final DndSessionFlight session = sessionFactory.persistentQuery("MyTestQuery");
Alternatively, you could create a new temporary Persistent Query to host your worker:
final DndSessionFlight session = sessionFactory.newWorker("ExampleTestWorker", 2, 600_000, 10_000);
If you need more precise control of Persistent Query options you can create a configuration object builder directly
final PersistentQueryConfigMessage.Builder builder = sessionFactory.createPersistentQueryConfig("ExampleTestWorker", 2, 600_000);
builder.addViewerGroups("MyViewers");
builder.addAdminGroups("SomeUser");
builder.addExtraJvmArguments("-DMy.Extra.Param=27");
session = sessionFactory.newWorker(builder.build(), 10_000);
Manipulating tables
You can fetch and manipulate tables from the query by creating a TableSpec
object using one of the session's four roots, then subscribe to it using the methods below.
Method | Description |
---|---|
catalogTable() | A table containing the full catalog of available database tables. |
scopeTable(String name) | A named table in the query scope. |
historicalTable(String namespace, String tableName) | A static Historical table from the database. |
liveTable(String namespace, String tableName) | A live table from the database. |
For example:
// This is an example of a batch operation based on a table in the existing query's scope.
final TableSpec testTable1 = DndSession.scopeTable("TestTable").where("Value > 4");
The TableSpec
does not send any data to the client. You may perform operations like where, sort, naturalJoin, etc. on a TableSpec
, producing a new TableSpec
object.
When the subscribeTo()
or snapshotOf()
methods are called, then the server performs the operations described in the TableSpec
and returns the resultant data.
// This creates a ticking (Live) barrage subscription
final Table testTableSubscription = session.subscribeTo(testTable1);
// This creates a static barrage snapshot
final Table testTableSnapshot = session.snapshotOf(testTable1);
The Table is a client side object that has a copy of all the data from the server. The Barrage protocol replicates consistent updates to the client. The Deephaven engine runs locally within the client, so any Table operations like where
, sort
or update
are executed on the client not within the worker.
// This creates a FlightStream of the table
final FlightStream stream = session.streamOf(testTable1);
This snippet will produce a FlightStream
which is a static snapshot of the source table.
Executing Scripts
You may also wish to execute blocks of script code on the worker using the executeCode()
method:
// You can also execute arbitrary script code on the server. This one creates a variable we can fetch below
session.executeCode("pel = db.live_table(namespace=\"DbInternal\", table_name=\"ProcessEventLog\").where(\"Date=today()\").tail(2)");
final Table fromExCode = session.snapshotOf(DndSession.scopeTable("pel"));
Cleanup
The connection, session, and tables fetched from a Deephaven query all consume resources, and care must be taken to close and release them when you are finished.
Every Table, Session, and the SessionFactory has a .close()
method that you should invoke when you are done with each object.
Note
Barrage tables have additional state tracking that must be cleaned up. When using the Barrage client, be sure to first close tables through the session, before invoking .close()
on the tables themselves.
session.closeTable(myTable);
myTable.close();
Accessing the full Deephaven Community API
If you want more sophisticated interactions with the query worker, you may retrieve the underlying SessionImpl
from the session using the .session()
method.
See the Community Documentation for more details.