For the complete documentation index, see llms.txt. This page is also available as Markdown.

Java

Pinot provides a native Java query client for broker-routed SQL queries. The client is tenant-aware, supports blocking and async execution, and can discover brokers through ZooKeeper or the controller.

For controller REST operations such as table, schema, segment, tenant, instance, or task management, use the Java admin client.

Installation

You can use the client by including the following dependency:

<dependency>
    <groupId>org.apache.pinot</groupId>
    <artifactId>pinot-java-client</artifactId>
    <version>1.4.0</version>
</dependency>
include 'org.apache.pinot:pinot-java-client:1.4.0'

You can also build the code for java client locally and use it.

Basic authorization is supported in the JDBC and Java clients since Pinot 0.10.0. Make sure you are using client JARs from that release or later.

Usage

Here's an example of how to use pinot-java-client to query Pinot.

import org.apache.pinot.client.Connection;
import org.apache.pinot.client.ConnectionFactory;
import org.apache.pinot.client.ResultSetGroup;
import org.apache.pinot.client.ResultSet;

/**
 * Demonstrates the use of pinot-java-client to query Pinot from Java.
 */
public class PinotClientExample {

  public static void main(String[] args) {

    // Pinot connection
    String zkUrl = "localhost:2181";
    String pinotClusterName = "PinotCluster";
    Connection pinotConnection = ConnectionFactory.fromZookeeper(zkUrl + "/" + pinotClusterName);

    String query = "SELECT COUNT(*) FROM myTable GROUP BY foo";
    ResultSetGroup pinotResultSetGroup = pinotConnection.execute(query);
    ResultSet resultTableResultSet = pinotResultSetGroup.getResultSet(0);

    int numRows = resultTableResultSet.getRowCount();
    int numColumns = resultTableResultSet.getColumnCount();
    String columnValue = resultTableResultSet.getString(0, 1);
    String columnName = resultTableResultSet.getColumnName(1);

    System.out.println("ColumnName: " + columnName + ", ColumnValue: " + columnValue);
  }
}

ConnectionFactory

The client provides a ConnectionFactory class to create connections to a Pinot cluster. The current source supports the following query-connection patterns:

  • ZooKeeper (recommended): ConnectionFactory.fromZookeeper(...) dynamically resolves brokers from Helix external view and routes queries by table.

  • Broker list: ConnectionFactory.fromHostList(...) uses a fixed broker list. This is mainly useful for simple deployments, load-balanced brokers, or local testing.

  • Controller address: ConnectionFactory.fromController(...) periodically refreshes broker mappings from the controller instead of watching ZooKeeper directly.

  • Properties object: ConnectionFactory.fromProperties(Properties) reads a brokerList property and builds a fixed broker-list connection.

For fromController(...) and fromControllerGrpc(...), pass the controller as host:port. The client applies http or https from the scheme property.

If your Pinot cluster is running inside Kubernetes and you're trying to connect to it from outside Kubernetes, the Zookeeper method will probably return internal host names that can't be resolved. For Kubernetes deployments, it's therefore recommended to pass in the host-name of a load balancer sitting in front of the brokers.

Example:

gRPC Connections

The Java client also exposes gRPC broker connections via ConnectionFactory.fromControllerGrpc(...), fromZookeeperGrpc(...), and fromHostListGrpc(...).

The gRPC transport properties below are read directly from the connection Properties through GrpcConfig. TLS settings use the tls.* namespace, not pinot.*.tls.*.

Property
Default
Notes

usePlainText

true

Use plaintext gRPC transport. Set to false to enable TLS.

maxInboundMessageSizeBytes

134217728 (128 MB)

Maximum inbound gRPC message size accepted by the client.

channelKeepAliveTimeSeconds

-1 (disabled)

Keepalive ping interval. Set a positive value to enable keepalive.

channelKeepAliveTimeoutSeconds

20

Timeout waiting for keepalive acknowledgements.

channelKeepAliveWithoutCalls

true

Allows keepalive pings even without active RPCs.

channelShutdownTimeoutSeconds

10

How long the client waits for the gRPC channel to terminate on close.

tls.keystore.type

JVM default keystore type (KeyStore.getDefaultType())

Client keystore type for mutual TLS.

tls.keystore.path

None

Client keystore path for mutual TLS.

tls.keystore.password

None

Client keystore password.

tls.truststore.type

JVM default keystore type (KeyStore.getDefaultType())

Truststore type used to validate the broker certificate.

tls.truststore.path

None

Truststore path used to validate the broker certificate.

tls.truststore.password

None

Truststore password.

tls.ssl.provider

JDK

SSL provider used when building the gRPC client SSL context.

tls.insecure

false

Skip broker certificate verification. Only appropriate for non-production testing.

tls.protocols

JVM TLS defaults

Comma-separated TLS protocol allowlist such as TLSv1.2,TLSv1.3.

For default metadata such as auth headers, use the headers.<name> property prefix. Query-specific gRPC metadata such as blockRowSize, compression, and encoding should be passed in the metadata map for execute(..., metadataMap) or executeGrpc(..., metadataMap).

Query Methods

You can run the query in both blocking as well as async manner. Use

  • Connection.execute(String) for blocking queries

  • Connection.executeAsync(String) for asynchronous queries that return a future object.

You can also use PreparedStatement to escape query parameters. We don't store the Prepared Statement in the database and hence it won't increase the subsequent query performance.

Connection.execute(...) also has overloads that accept an explicit table name or iterable of table names. Those overloads let the client choose the broker without re-parsing SQL.

Cursor Pagination

The HTTP transport behind Connection implements cursor pagination. Use openCursor(query, pageSize) when a query can return a large result set and you want page-by-page navigation instead of loading everything into one response.

The cursor API supports:

  • getCurrentPage() to inspect the currently loaded page

  • next() / nextAsync() and previous() / previousAsync() for navigation

  • seekToPage() / seekToPageAsync() for direct page jumps

  • getCursorId(), getCurrentPageNumber(), getTotalRows(), and isExpired() for cursor metadata

  • close() to delete the server-side cursor and free resources

Cursor pagination is available only when the underlying transport implements CursorCapable, which the default HTTP transport does.

Result Set

Results can be obtained with the various getter methods on the first ResultSet, obtained through getResultSet(int):

Authentication

Pinot supports basic HTTP authorization, which can be enabled for your cluster using configuration. To support basic HTTP authorization in your client-side Java applications, make sure you are using Pinot Java Client 0.10.0 or later. The following code snippet shows you how to connect to and query a Pinot cluster that has basic HTTP authorization enabled when using the Java client.

Connection Properties

The Java query client reads the following connection properties directly from Properties:

Property
Default
Used by
Notes

brokerConnectTimeoutMs

2000

HTTP broker transport

Broker connect timeout in milliseconds

brokerReadTimeoutMs

60000

HTTP broker transport and cursor fetches

Broker read timeout in milliseconds

brokerHandshakeTimeoutMs

2000

HTTP broker transport

TLS handshake timeout in milliseconds

controllerConnectTimeoutMs

2000

Controller-based broker cache

Controller connect timeout for fromController(...)

controllerReadTimeoutMs

60000

Controller-based broker cache

Controller read timeout for broker-map refresh

controllerHandshakeTimeoutMs

2000

Controller-based broker cache

Controller TLS handshake timeout

headers.<name>

None

HTTP broker transport and controller broker cache

Adds default HTTP headers such as headers.Authorization

scheme

http

HTTP broker transport and controller broker cache

Set to https for TLS-enabled brokers and controller

queryOptions

Empty string

HTTP broker transport

Injected into the JSON request body as Pinot query options

useMultistageEngine

false

HTTP broker transport

Switches HTTP requests from /query/sql to /query

appId

None

HTTP broker transport and controller broker cache

Prefixes the generated user agent string

failOnExceptions

true

Connection

Throw PinotClientException when the broker response includes query-processing exceptions

preferTLS

false

ZooKeeper-based broker discovery

Prefer broker TLS ports when discovering brokers from Helix

useGrpcPort

false

ZooKeeper/controller broker discovery

Prefer broker gRPC ports when building broker lists

pinot.java_client.tls.*

None

HTTP broker transport and controller broker cache

TLS config namespace consumed by TlsUtils.extractTlsConfig(...)

brokerTlsV10Enabled

false

HTTP broker transport

Re-enable TLSv1.0 for broker requests

controllerTlsV10Enabled

false

Controller broker cache

Re-enable TLSv1.0 for controller requests

Example:

When you customize JsonAsyncHttpPinotClientTransportFactory directly, the scheme property only overrides the factory when you set scheme in Properties. If scheme is absent, withConnectionProperties(...) keeps any scheme you already set on the factory and falls back to http only when neither the factory nor the properties specify one.

Request Tracing

The Java client (JsonAsyncHttpPinotClientTransport) automatically attaches an X-Correlation-Id header — a unique UUID per request — to every HTTP query. This ID:

  • Is logged at DEBUG level by the client under org.apache.pinot.client

  • Appears in broker access logs, enabling end-to-end tracing across proxies and load balancers

No configuration is required. To see correlation IDs in client logs, set the log level:

Last updated

Was this helpful?