arrow-left

All pages
gitbookPowered by GitBook
1 of 5

Loading...

Loading...

Loading...

Loading...

Loading...

External Clients

A lot of times the user wants to query data from an external application instead of using the inbuilt query explorer. Pinot provides external query client for this purpose. All of the clients have pretty standard interfaces so that the learning curve is minimum.

Currently Pinot provides the following clients

JDBCchevron-right
Javachevron-right
Pythonchevron-right
Golangchevron-right

Python

hashtag
Python DB-API and SQLAlchemy dialect for Pinot

Applications can use this python client library to query Apache Pinot.

Pypi Repo: https://pypi.org/project/pinotdb/arrow-up-right

Source Code Repo: https://github.com/python-pinot-dbapi/pinot-dbapiarrow-up-right

hashtag
Installation

Please note:

  • pinotdb version >= 0.3.2 uses the Pinot SQL API (added in Pinot >= 0.3.0) and drops support for PQL API. So this client requires Pinot server version >= 0.3.0 in order to access Pinot.

  • pinotdb version in 0.2.x uses the Pinot PQL API, which works with pinot version <= 0.3.0, but may miss some new SQL query features added in newer Pinot version.

hashtag
Usage

hashtag
Using the DB API to query Pinot Broker directly:

hashtag
Using SQLAlchemy:

The db engine connection string is formated like this: pinot://:?controller=://:/

hashtag
Examples with Pinot Quickstart

hashtag
Clone the Pinot DB repository

hashtag
Pinot Batch Quickstart

Run below command to start Pinot Batch Quickstart in docker and expose Pinot controller port 9000 and Pinot broker port 8000.

Once pinot batch quickstart is up, you can run the sample code snippet to query Pinot:

Sample Output:

Using parameters:

hashtag

hashtag
Pinot Hybrid Quickstart

Run the command below to start Pinot Hybrid Quickstart in docker and expose Pinot controller port 9000 and Pinot broker port 8000.

Below is an example to query against Pinot Quickstart Hybrid:

pip install pinotdb
from pinotdb import connect

conn = connect(host='localhost', port=8099, path='/query/sql', scheme='http')
curs = conn.cursor()
curs.execute("""
    SELECT place,
           CAST(REGEXP_EXTRACT(place, '(.*),', 1) AS FLOAT) AS lat,
           CAST(REGEXP_EXTRACT(place, ',(.*)', 1) AS FLOAT) AS lon
      FROM places
     LIMIT 10
""")
for row in curs:
    print(row)
from sqlalchemy import *
from sqlalchemy.engine import create_engine
from sqlalchemy.schema import *

engine = create_engine('pinot://localhost:8099/query/sql?controller=http://localhost:9000/')  # uses HTTP by default :(
# engine = create_engine('pinot+http://localhost:8099/query/sql?controller=http://localhost:9000/')
# engine = create_engine('pinot+https://localhost:8099/query/sql?controller=http://localhost:9000/')

places = Table('places', MetaData(bind=engine), autoload=True)
print(select([func.count('*')], from_obj=places).scalar())
git clone [email protected]:python-pinot-dbapi/pinot-dbapi.git
cd pinot-dbapi
docker run \
  --name pinot-quickstart \
  -p 2123:2123 \
  -p 9000:9000 \
  -p 8000:8000 \
  apachepinot/pinot:latest QuickStart -type batch
python3 examples/pinot-quickstart-batch.py
Sending SQL to Pinot: SELECT * FROM baseballStats LIMIT 5
[0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 'NL', 11, 11, 'aardsda01', 'David Allan', 1, 0, 0, 0, 0, 0, 0, 'SFN', 0, 2004]
[2, 45, 0, 0, 0, 0, 0, 0, 0, 0, 'NL', 45, 43, 'aardsda01', 'David Allan', 1, 0, 0, 0, 1, 0, 0, 'CHN', 0, 2006]
[0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'AL', 25, 2, 'aardsda01', 'David Allan', 1, 0, 0, 0, 0, 0, 0, 'CHA', 0, 2007]
[1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 'AL', 47, 5, 'aardsda01', 'David Allan', 1, 0, 0, 0, 0, 0, 1, 'BOS', 0, 2008]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'AL', 73, 3, 'aardsda01', 'David Allan', 1, 0, 0, 0, 0, 0, 0, 'SEA', 0, 2009]

Sending SQL to Pinot: SELECT playerName, sum(runs) FROM baseballStats WHERE yearID>=2000 GROUP BY playerName LIMIT 5
['Scott Michael', 26.0]
['Justin Morgan', 0.0]
['Jason Andre', 0.0]
['Jeffrey Ellis', 0.0]
['Maximiliano R.', 16.0]

Sending SQL to Pinot: SELECT playerName,sum(runs) AS sum_runs FROM baseballStats WHERE yearID>=2000 GROUP BY playerName ORDER BY sum_runs DESC LIMIT 5
['Adrian', 1820.0]
['Jose Antonio', 1692.0]
['Rafael', 1565.0]
['Brian Michael', 1500.0]
['Alexander Emmanuel', 1426.0]
from pinotdb import connect

conn = connect(host='localhost', port=8000, path='/query/sql', scheme='http')
curs = conn.cursor()

curs.execute("""
    SELECT * 
    FROM baseballStats
    WHERE league IN (%(leagues)s)
    """, {"leagues": ["AA", "NL"]})
for row in curs:
    print(row)
    
curs.execute("""
    SELECT *
    FROM baseballStats
    WHERE baseOnBalls > (%(score)d)
    """, {"score": 0})
for row in curs:
    print(row)
docker run \
  --name pinot-quickstart \
  -p 2123:2123 \
  -p 9000:9000 \
  -p 8000:8000 \
  apachepinot/pinot:latest QuickStart -type hybrid
python3 examples/pinot-quickstart-hybrid.py
Sending SQL to Pinot: SELECT * FROM airlineStats LIMIT 5
[171, 153, 19393, 0, 8, 8, 1433, '1400-1459', 0, 1425, 1240, 165, 'null', 0, 'WN', -2147483648, 1, 27, 17540, 0, 2, 2, 1242, '1200-1259', 0, 'MDW', 13232, 1323202, 30977, 'Chicago, IL', 'IL', 17, 'Illinois', 41, 861, 4, -2147483648, [-2147483648], 0, [-2147483648], ['null'], -2147483648, -2147483648, [-2147483648], -2147483648, ['null'], [-2147483648], [-2147483648], [-2147483648], 0, -2147483648, '2014-01-27', 402, 1, -2147483648, -2147483648, 1, -2147483648, 'BOS', 10721, 1072102, 30721, 'Boston, MA', 'MA', 25, 'Massachusetts', 13, 1, ['null'], -2147483648, 'N556WN', 6, 12, -2147483648, 'WN', -2147483648, 1254, 1427, 2014]
[183, 141, 20398, 1, 17, 17, 1302, '1200-1259', 1, 1245, 1005, 160, 'null', 0, 'MQ', 0, 1, 27, 17540, 0, -6, 0, 959, '1000-1059', -1, 'CMH', 11066, 1106603, 31066, 'Columbus, OH', 'OH', 39, 'Ohio', 44, 990, 4, -2147483648, [-2147483648], 0, [-2147483648], ['null'], -2147483648, -2147483648, [-2147483648], -2147483648, ['null'], [-2147483648], [-2147483648], [-2147483648], 0, -2147483648, '2014-01-27', 3574, 1, 0, -2147483648, 1, 17, 'MIA', 13303, 1330303, 32467, 'Miami, FL', 'FL', 12, 'Florida', 33, 1, ['null'], 0, 'N605MQ', 13, 29, -2147483648, 'MQ', 0, 1028, 1249, 2014]
[-2147483648, -2147483648, 20304, -2147483648, -2147483648, -2147483648, -2147483648, '2100-2159', -2147483648, 2131, 2005, 146, 'null', 0, 'OO', -2147483648, 1, 27, 17541, 1, 52, 52, 2057, '2000-2059', 3, 'COS', 11109, 1110902, 30189, 'Colorado Springs, CO', 'CO', 8, 'Colorado', 82, 809, 4, -2147483648, [11292], 1, [1129202], ['DEN'], -2147483648, 73, [9], 0, ['null'], [9], [-2147483648], [2304], 1, -2147483648, '2014-01-27', 5554, 1, -2147483648, -2147483648, 1, -2147483648, 'IAH', 12266, 1226603, 31453, 'Houston, TX', 'TX', 48, 'Texas', 74, 1, ['SEA', 'PSC', 'PHX', 'MSY', 'ATL', 'TYS', 'DEN', 'CHS', 'PDX', 'LAX', 'EWR', 'SFO', 'PIT', 'RDU', 'RAP', 'LSE', 'SAN', 'SBN', 'IAH', 'OAK', 'BRO', 'JFK', 'SAT', 'ORD', 'ACY', 'DFW', 'BWI'], -2147483648, 'N795SK', -2147483648, 19, -2147483648, 'OO', -2147483648, 2116, -2147483648, 2014]
[153, 125, 20436, 1, 41, 41, 1442, '1400-1459', 2, 1401, 1035, 146, 'null', 0, 'F9', 2, 1, 27, 17541, 1, 34, 34, 1109, '1000-1059', 2, 'DEN', 11292, 1129202, 30325, 'Denver, CO', 'CO', 8, 'Colorado', 82, 967, 4, -2147483648, [-2147483648], 0, [-2147483648], ['null'], -2147483648, -2147483648, [-2147483648], -2147483648, ['null'], [-2147483648], [-2147483648], [-2147483648], 0, -2147483648, '2014-01-27', 658, 1, 8, -2147483648, 1, 31, 'SFO', 14771, 1477101, 32457, 'San Francisco, CA', 'CA', 6, 'California', 91, 1, ['null'], 0, 'N923FR', 11, 17, -2147483648, 'F9', 0, 1126, 1431, 2014]
[-2147483648, -2147483648, 20304, -2147483648, -2147483648, -2147483648, -2147483648, '1400-1459', -2147483648, 1432, 1314, 78, 'B', 1, 'OO', -2147483648, 1, 27, 17541, -2147483648, -2147483648, -2147483648, -2147483648, '1300-1359', -2147483648, 'EAU', 11471, 1147103, 31471, 'Eau Claire, WI', 'WI', 55, 'Wisconsin', 45, 268, 2, -2147483648, [-2147483648], 0, [-2147483648], ['null'], -2147483648, -2147483648, [-2147483648], -2147483648, ['null'], [-2147483648], [-2147483648], [-2147483648], 0, -2147483648, '2014-01-27', 5455, 1, -2147483648, -2147483648, 1, -2147483648, 'ORD', 13930, 1393003, 30977, 'Chicago, IL', 'IL', 17, 'Illinois', 41, 1, ['null'], -2147483648, 'N903SW', -2147483648, -2147483648, -2147483648, 'OO', -2147483648, -2147483648, -2147483648, 2014]

Sending SQL to Pinot: SELECT count(*) FROM airlineStats LIMIT 5
[17772]

Sending SQL to Pinot: SELECT AirlineID, sum(Cancelled) FROM airlineStats WHERE Year > 2010 GROUP BY AirlineID LIMIT 5
[20409, 40.0]
[19930, 16.0]
[19805, 60.0]
[19790, 115.0]
[20366, 172.0]

Sending SQL to Pinot: select OriginCityName, max(Flights) from airlineStats group by OriginCityName ORDER BY max(Flights) DESC LIMIT 5
['Casper, WY', 1.0]
['Deadhorse, AK', 1.0]
['Austin, TX', 1.0]
['Chicago, IL', 1.0]
['Monterey, CA', 1.0]

Sending SQL to Pinot: SELECT OriginCityName, sum(Cancelled) AS sum_cancelled FROM airlineStats WHERE Year>2010 GROUP BY OriginCityName ORDER BY sum_cancelled DESC LIMIT 5
['Chicago, IL', 178.0]
['Atlanta, GA', 111.0]
['New York, NY', 65.0]
['Houston, TX', 62.0]
['Denver, CO', 49.0]

Sending Count(*) SQL to Pinot
17773

Sending SQL: "SELECT OriginCityName, sum(Cancelled) AS sum_cancelled FROM "airlineStats" WHERE Year>2010 GROUP BY OriginCityName ORDER BY sum_cancelled DESC LIMIT 5" to Pinot
[('Chicago, IL', 178.0), ('Atlanta, GA', 111.0), ('New York, NY', 65.0), ('Houston, TX', 62.0), ('Denver, CO', 49.0)]

JDBC

Pinot offers standard JDBC interface to query the database. This makes it easier to integrate Pinot with other applications such as Tableau.

hashtag
Installation

You can include the JDBC dependency in your code as follows -

<dependency>
    <groupId>org.apache.
include 'org.apache.pinot:pinot-jdbc-client:0.8.0'

You can also compile the into a JAR and place the JAR in the Drivers directory of your application.

There is no need to register the driver manually as it will automatically register itself at the startup of the application.

hashtag
Usage

Here's an example of how to use the pinot-jdbc-client for querying. The client only requires the controller URL.

You can also use PreparedStatements. The placeholder parameters are represented using ? ** (question mark) symbol.

hashtag
Authentication

Pinot supports , which can be enabled for your cluster using configuration. To support basic HTTP authorization in your client-side JDBC applications, make sure you are using Pinot JDBC 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 JDBC client.

hashtag
Configuring client time-out

The following timeouts can be set:

  • brokerConnectTimeoutMs (default 2000)

  • brokerReadTimeoutMs (default 60000)

  • brokerHandshakeTimeoutMs (default 2000)

Timeouts for the JDBC connector can be added as a parameter to the JDBC Connection URL. The following example enables https and configures a very low timeout of 10ms:

hashtag
Configuring client time-out

The following timeouts can be set:

  • brokerConnectTimeoutMs (default 2000)

  • brokerReadTimeoutMs (default 60000)

  • brokerHandshakeTimeoutMs (default 2000)

Timeouts for the JDBC connector can be added as a parameter to the JDBC Connection URL. The following example enables https and configures a very low timeout of 10ms:

hashtag
Limitation

The JDBC client doesn't support INSERT, DELETE or UPDATE statements due to the database limitations. You can only use the client to query the database. The driver is also not completely ANSI SQL 92 compliant.

circle-exclamation

If you want to use JDBC driver to integrate Pinot with other applications, do make sure to check JDBC ConnectionMetadata in your code. This will help in determining which features cannot be supported by Pinot since it is an OLAP database.

controllerConnectTimeoutMs (default 2000)
  • controllerReadTimeoutMs (default 60000)

  • controllerHandshakeTimeoutMs (default 2000)

  • controllerConnectTimeoutMs (default 2000)
  • controllerReadTimeoutMs (default 60000)

  • controllerHandshakeTimeoutMs (default 2000)

  • pinot
    </
    groupId
    >
    <artifactId>pinot-jdbc-client</artifactId>
    <version>0.8.0</version>
    </dependency>
    JDBC codearrow-up-right
    basic HTTP authorization
    public static final String DB_URL = "jdbc:pinot://localhost:9000"
    DriverManager.registerDriver(new PinotDriver());
    Connection conn = DriverManager.getConnection(DB_URL);
    Statement statement = conn.createStatement();
    Integer limitResults = 10;
    ResultSet rs = statement.executeQuery(String.format("SELECT UPPER(playerName) AS name FROM baseballStats LIMIT %d", limitResults));
    Set<String> results = new HashSet<>();
    
    while(rs.next()){
     String playerName = rs.getString("name");
     results.add(playerName);
    }
    
    conn.close();
    Connection conn = DriverManager.getConnection(DB_URL);
    PreparedStatement statement = conn.prepareStatement("SELECT UPPER(playerName) AS name FROM baseballStats WHERE age = ?");
    statement.setInt(1, 20);
    
    ResultSet rs = statement.executeQuery();
    Set<String> results = new HashSet<>();
    
    while(rs.next()){
     String playerName = rs.getString("name");
     results.add(playerName);
    }
    
    conn.close();
    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()));
    
    // Create authorization header
    String authorizationHeader = "Basic " + base64Credentials;
    Properties connectionProperties = new Properties();
    connectionProperties.setProperty("headers.Authorization", authorizationHeader);
    
    // Register new Pinot JDBC driver
    DriverManager.registerDriver(new PinotDriver());
    
    // Get a client connection and set the encoded authorization header
    Connection connection = DriverManager.getConnection(DB_URL, connectionProperties);
    
    // Test that your query successfully authenticates
    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);
    }
    final String DB_URL = "jdbc:pinot://hostname?brokerConnectTimeoutMs=10&brokerReadTimeoutMs=10&brokerHandshakeTimeoutMs=10&controllerConnectTimeoutMs=10&controllerReadTimeoutMs=10&scheme=https";

    Java

    Pinot provides a native java client to execute queries on the cluster. The client makes it easier for user to query data. The client is also tenant-aware and thus is able to redirect the queries to the correct broker.

    hashtag
    Installation

    You can use the client by including the following dependency -

    <dependency>
        <groupId>org.apache.
    
    include 'org.apache.pinot:pinot-java-client:0.5.0'

    You can also build locally and use it.

    circle-info

    Basic authorization for the JDBC client is not supported in Pinot JDBC 0.9.3 release or earlier. The JDBC client has been upgraded to support basic authentication in the Pinot 0.10.0 snapshot, which can currently be built from source.

    You will not need to update your Pinot cluster to 0.10.0+ to support basic authentication, only the JDBC and Java client JARs.

    hashtag
    Usage

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

    hashtag
    Connection Factory

    The client provides a ConnectionFactory class to create connections to a Pinot cluster. The factory supports the following methods to create a connection -

    • Zookeeper (Recommended) - Comma seperated list of zookeeper of the cluster. This is the recommended method which can redirect queries to appropriate brokers based on tenant/table.

    • Broker list - Comma seperated list of the brokers in the cluster. This should only be used in standalone setups or for POC, unless you have a load balancer setup for brokers.

    • Controller URL - (v 0.11.0+) Controller URL. This will use periodic controller API calls to keep the table level broker list updated (hence there might be delay b/w the broker mapping changing and the client state getting updated).

    Here's an example demonstrating all methods of Connection factory -

    hashtag
    Query Methods

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

    • Connection.execute(org.apache.pinot.client.Request) for blocking queries

    • Connection.executeAsync(org.apache.pinot.client.Request) 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.

    hashtag
    Result Set

    Results can be obtained with the various get methods in the first ResultSet, obtained through the getResultSet(int) method:

    hashtag
    PQL Queries

    If queryFormat pql is used in the Request, there are some differences in how the results can be accessed, depending on the query.

    In the case of aggregation, each aggregation function is within its own ResultSet. A query with multiple aggregation function will return one result set per aggregation function, as they are computed in parallel.

    In case of aggregation with GROUP BY, there will be as many ResultSets as the number of aggregations, each of which will contain multiple results grouped by a grouping key.

    circle-exclamation

    This section is only applicable for PQL endpoint, which is deprecated and will be deleted soon. For more information about the endpoints, visit .

    hashtag
    Authentication

    Pinot supports , 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.

    hashtag
    Configuring client time-out

    The following timeouts can be set:

    • brokerConnectTimeoutMs (default 2000)

    • brokerReadTimeoutMs (default 60000)

    • brokerHandshakeTimeoutMs (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 file - You can also put the broker list as brokerList in a properties file and provide the path to that file to the factory. This should only be used in standalone setups or for POC, unless you have a load balancer setup for brokers.

  • controllerConnectTimeoutMs (default 2000)
  • controllerReadTimeoutMs (default 60000)

  • controllerHandshakeTimeoutMs (default 2000)

  • pinot
    </
    groupId
    >
    <artifactId>pinot-java-client</artifactId>
    <version>0.9.3</version>
    </dependency>
    the code for java clientarrow-up-right
    Querying Pinot
    basic HTTP authorization
    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 zkUrl = "localhost:2181";
        String pinotClusterName = "PinotCluster";
        Connection pinotConnection = ConnectionFactory.fromZookeeper(zkUrl + "/" + pinotClusterName);
    
        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 connection = ConnectionFactory.fromZookeeper
      ("some-zookeeper-server:2191/zookeeperPath");
    
    Connection connection = ConnectionFactory.fromProperties("demo.properties");
    
    Connection connection = ConnectionFactory.fromHostList
      ("broker-1:1234", "broker-2:1234", ...);
    
    Connection connection = ConnectionFactory.fromController
        ("http", "controller-url", 9000)
    ResultSetGroup resultSetGroup = 
      connection.execute(new Request("sql", "select * from foo..."));
    // OR
    Future<ResultSetGroup> futureResultSetGroup = 
      connection.executeAsync(new Request("sql", "select * from foo..."));
    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();
    Request request = new Request("sql", "select foo, bar from baz where quux = 'quuux'");
    ResultSetGroup resultSetGroup = connection.execute(request);
    ResultSet resultTableResultSet = pinotResultSetGroup.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));
    }
    ResultSetGroup resultSetGroup = 
        connection.execute(new Request("pql", "select max(foo), min(foo) from bar"));
    
    System.out.println("Number of result groups:" +
        resultSetGroup.getResultSetCount(); // 2, min(foo) and max(foo)
    ResultSet resultSetMax = resultSetGroup.getResultSet(0);
    System.out.println("Max foo: " + resultSetMax.getInt(0));
    ResultSet resultSetMin = resultSetGroup.getResultSet(1);
    System.out.println("Min foo: " + resultSetMin.getInt(0));
    ResultSetGroup resultSetGroup = 
        connection.execute(
            new Request("pql", "select min(foo), max(foo) from bar group by baz"));
    
    System.out.println("Number of result groups:" +
        resultSetGroup.getResultSetCount(); // 2, min(foo) and max(foo)
    
    ResultSet minResultSet = resultSetGroup.getResultSet(0);
    for(int i = 0; i < minResultSet.length(); ++i) {
        System.out.println("Minimum foo for " + minResultSet.getGroupKeyString(i, 1) +
            ": " + minResultSet.getInt(i));
    }
    
    ResultSet maxResultSet = resultSetGroup.getResultSet(1);
    for(int i = 0; i < maxResultSet.length(); ++i) {
        System.out.println("Maximum foo for " + maxResultSet.getGroupKeyString(i, 1) +
            ": " + maxResultSet.getInt(i));
    }
    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();
    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);
    }

    Golang

    Pinot Client for Golang

    Pinot also provides a native go clientarrow-up-right to query database directly from go application.

    hashtag
    Installation

    Please follow this Pinot Quickstartarrow-up-right link to install and start Pinot batch QuickStart locally.

    Check out Client library Github Repo

    Build and run the example application to query from Pinot Batch Quickstart

    hashtag
    Usage

    hashtag
    Create a Pinot Connection

    Pinot client could be initialized through:

    hashtag
    1. Zookeeper Path.

    hashtag
    2. A list of broker addresses.

    hashtag
    3. ClientConfig

    hashtag
    Query Pinot

    Please see this for your reference.

    Code snippet:

    hashtag
    Response Format

    Query Response is defined as the struct of following:

    Note that AggregationResults and SelectionResults are holders for PQL queries.

    Meanwhile ResultTable is the holder for SQL queries. ResultTable is defined as:

    RespSchema is defined as:

    There are multiple functions defined for ResultTable, like:

    Sample Usage is

    bin/quick-start-batch.sh
    git clone [email protected]:startreedata/pinot-client-go.git
    cd pinot-client-go
    examplearrow-up-right
    herearrow-up-right
    go build ./examples/batch-quickstart
    ./batch-quickstart
    pinotClient := pinot.NewFromZookeeper([]string{"localhost:2123"}, "", "QuickStartCluster")
    pinotClient := pinot.NewFromBrokerList([]string{"localhost:8000"})
    pinotClient := pinot.NewWithConfig(&pinot.ClientConfig{
    	ZkConfig: &pinot.ZookeeperConfig{
    		ZookeeperPath:     zkPath,
    		PathPrefix:        strings.Join([]string{zkPathPrefix, pinotCluster}, "/"),
    		SessionTimeoutSec: defaultZkSessionTimeoutSec,
    	},
        ExtraHTTPHeader: map[string]string{
            "extra-header":"value",
        },
    })
    pinotClient, err := pinot.NewFromZookeeper([]string{"localhost:2123"}, "", "QuickStartCluster")
    if err != nil {
        log.Error(err)
    }
    brokerResp, err := pinotClient.ExecuteSQL("baseballStats", "select count(*) as cnt, sum(homeRuns) as sum_homeRuns from baseballStats group by teamID limit 10")
    if err != nil {
        log.Error(err)
    }
    log.Infof("Query Stats: response time - %d ms, scanned docs - %d, total docs - %d", brokerResp.TimeUsedMs, brokerResp.NumDocsScanned, brokerResp.TotalDocs)
    type BrokerResponse struct {
    	AggregationResults          []*AggregationResult `json:"aggregationResults,omitempty"`
    	SelectionResults            *SelectionResults    `json:"SelectionResults,omitempty"`
    	ResultTable                 *ResultTable         `json:"resultTable,omitempty"`
    	Exceptions                  []Exception          `json:"exceptions"`
    	TraceInfo                   map[string]string    `json:"traceInfo,omitempty"`
    	NumServersQueried           int                  `json:"numServersQueried"`
    	NumServersResponded         int                  `json:"numServersResponded"`
    	NumSegmentsQueried          int                  `json:"numSegmentsQueried"`
    	NumSegmentsProcessed        int                  `json:"numSegmentsProcessed"`
    	NumSegmentsMatched          int                  `json:"numSegmentsMatched"`
    	NumConsumingSegmentsQueried int                  `json:"numConsumingSegmentsQueried"`
    	NumDocsScanned              int64                `json:"numDocsScanned"`
    	NumEntriesScannedInFilter   int64                `json:"numEntriesScannedInFilter"`
    	NumEntriesScannedPostFilter int64                `json:"numEntriesScannedPostFilter"`
    	NumGroupsLimitReached       bool                 `json:"numGroupsLimitReached"`
    	TotalDocs                   int64                `json:"totalDocs"`
    	TimeUsedMs                  int                  `json:"timeUsedMs"`
    	MinConsumingFreshnessTimeMs int64                `json:"minConsumingFreshnessTimeMs"`
    }
    // ResultTable is a ResultTable
    type ResultTable struct {
    	DataSchema RespSchema      `json:"dataSchema"`
    	Rows       [][]interface{} `json:"rows"`
    }
    // RespSchema is response schema
    type RespSchema struct {
    	ColumnDataTypes []string `json:"columnDataTypes"`
    	ColumnNames     []string `json:"columnNames"`
    }
    func (r ResultTable) GetRowCount() int
    func (r ResultTable) GetColumnCount() int
    func (r ResultTable) GetColumnName(columnIndex int) string
    func (r ResultTable) GetColumnDataType(columnIndex int) string
    func (r ResultTable) Get(rowIndex int, columnIndex int) interface{}
    func (r ResultTable) GetString(rowIndex int, columnIndex int) string
    func (r ResultTable) GetInt(rowIndex int, columnIndex int) int
    func (r ResultTable) GetLong(rowIndex int, columnIndex int) int64
    func (r ResultTable) GetFloat(rowIndex int, columnIndex int) float32
    func (r ResultTable) GetDouble(rowIndex int, columnIndex int) float64
    // Print Response Schema
    for c := 0; c < brokerResp.ResultTable.GetColumnCount(); c++ {
      fmt.Printf("%s(%s)\t", brokerResp.ResultTable.GetColumnName(c), brokerResp.ResultTable.GetColumnDataType(c))
    }
    fmt.Println()
    
    // Print Row Table
    for r := 0; r < brokerResp.ResultTable.GetRowCount(); r++ {
      for c := 0; c < brokerResp.ResultTable.GetColumnCount(); c++ {
        fmt.Printf("%v\t", brokerResp.ResultTable.Get(r, c))
      }
      fmt.Println()
    }