Connecting via Java

Connecting to StarTree Cloud via Java

Pinot provides a native java client to execute queries on the cluster. The client is tenant-aware, and able to direct queries to the correct broker.

Prerequisite

You can use the client by installing and including Maven or Gradle.

For information on how to install Maven, visit Installing Apache Maven (opens in a new tab).

Example of how to including the Maven dependency to use the client:

<dependency>
    <groupId>org.apache.pinot</groupId>
    <artifactId>pinot-java-client</artifactId>
    <version>1.0.0</version>
</dependency>

For information on how to install Gradle, visit Gradle Build Tool Installation (opens in a new tab).

Example of how to including the Gradle dependency to use the client:

include 'org.apache.pinot:pinot-java-client:0.5.0'

Usage

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

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

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

  public static void main(String[] args) {

    // pinot connection
    String brokerURL = "https://pinot.<random-string>.cp.s7e.startree.cloud"; // this URL should be available with you
    String pinotClusterName = "PinotCluster";
    JsonAsyncHttpPinotClientTransportFactory factory = new JsonAsyncHttpPinotClientTransportFactory();
    Connection pinotConnection = ConnectionFactory.fromHostList(Collections.singletonList(brokerURL), factory.buildTransport());

    String query = "SELECT COUNT(*) FROM myTable GROUP BY foo";

    // set queryType=sql for querying the sql endpoint
    Request pinotClientRequest = new Request("sql", query);
    ResultSetGroup pinotResultSetGroup = pinotConnection.execute(pinotClientRequest);
    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);
  }
}

Connection Factory

The client provides a ConnectionFactory class to create connections to a Pinot cluster. To create a connection, include a comma-separated list of the brokers in the cluster. For example, ("broker-1:1234", "broker-2:1234", ...);

Connection connection = ConnectionFactory.fromZookeeper
  ("some-zookeeper-server:2191/zookeeperPath");
Connection connection = ConnectionFactory.fromProperties("demo.properties");
Connection connection = ConnectionFactory.fromHostList(Collections.singletonList("https://pinot.<random-string>.cp.s7e.startree.cloud"), factory.buildTransport());

Query methods

Query using one of the following methods:

  • For blocking queries, use the following request format: Connection.execute(org.apache.pinot.client.Request)
  • For asynchronous queries that return a future object, use the following request format: Connection.executeAsync(org.apache.pinot.client.Request)
ResultSetGroup resultSetGroup =
  connection.execute(new Request("sql", "select * from foo..."));
// OR
Future<ResultSetGroup> futureResultSetGroup =
  connection.executeAsync(new Request("sql", "select * from foo..."));

To escape query parameters, you can use the PreparedStatement (which isn't stored, so won't decrease the subsequent query performance).

PreparedStatement statement =
    connection.prepareStatement(new Request("sql", "select * from foo where a = ?"));
statement.setString(1, "bar");
 
ResultSetGroup resultSetGroup = statement.execute();
// OR
Future<ResultSetGroup> futureResultSetGroup = statement.executeAsync();

Result set

Access results using various get methods on the first ResultSet with the getResultSet(int) method.

Request request = new Request("sql", "select foo, bar from baz where quux = 'quuux'");
ResultSetGroup resultSetGroup = connection.execute(request);
ResultSet resultSet = resultSetGroup.getResultSet(0);
 
for (int i = 0; i < resultSet.getRowCount(); ++i) {
  System.out.println("foo: " + resultSet.getString(i, 0));
  System.out.println("bar: " + resultSet.getInt(i, 1));
}

Authentication

Pinot supports basic HTTP authorization (opens in a new tab), 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 building from the latest Pinot snapshot. 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.

final String username = "admin";
final String password = "verysecret";
 
// Concatenate username and password and use base64 to encode the concatenated string
String plainCredentials = username + ":" + password;
String base64Credentials = new String(
    Base64.getEncoder().encode(plainCredentials.getBytes()));
 
String authorizationHeader = "Basic " + base64Credentials;
 
Map<String, String> headers = new HashMap();
headers.put("Authorization", authorizationHeader);
JsonAsyncHttpPinotClientTransportFactory factory =
    new JsonAsyncHttpPinotClientTransportFactory();
factory.setHeaders(headers);
PinotClientTransport clientTransport = factory
    .buildTransport();
 
Connection connection = ConnectionFactory.fromProperties(
        Collections.singletonList("localhost:8000"), clientTransport);
String query = "select count(*) FROM baseballStats limit 1";
 
ResultSetGroup rs = connection.execute(query);
System.out.println(rs);
connection.close();

Configuring client time-out

The following timeouts can be set:

  • brokerConnectTimeoutMs (default 2000)
  • brokerReadTimeoutMs (default 60000)
  • brokerHandshakeTimeoutMs (default 2000)
  • controllerConnectTimeoutMs (default 2000)
  • controllerReadTimeoutMs (default 60000)
  • controllerHandshakeTimeoutMs (default 2000)

Timeouts for the Java connector can be added as a connection properties. The following example configures a very low timeout of 10ms:

Properties connectionProperties = new Properties();
connectionProperties.setProperty("controllerReadTimeoutMs", "10");
connectionProperties.setProperty("controllerHandshakeTimeoutMs", "10");
connectionProperties.setProperty("controllerConnectTimeoutMs", "10");
connectionProperties.setProperty("brokerReadTimeoutMs", "10");
connectionProperties.setProperty("brokerHandshakeTimeoutMs", "10");
connectionProperties.setProperty("brokerConnectTimeoutMs", "10");
 
// Register new Pinot JDBC driver
DriverManager.registerDriver(new PinotDriver());
 
// Get a client connection and set the connection timeouts
Connection connection = DriverManager.getConnection(DB_URL, connectionProperties);
 
// Test that your query successfully times out
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("SELECT count(*) FROM baseballStats LIMIT 1;");
 
while (rs.next()) {
    String result = rs.getString("count(*)");
    System.out.println(result);
}