<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>InfluxData Blog - Subashini Sukumar</title>
    <description>Posts by Subashini Sukumar on the InfluxData Blog</description>
    <link>https://www.influxdata.com/blog/author/subashini-sukumar/</link>
    <language>en-us</language>
    <lastBuildDate>Fri, 09 Jun 2023 07:00:00 +0000</lastBuildDate>
    <pubDate>Fri, 09 Jun 2023 07:00:00 +0000</pubDate>
    <ttl>1800</ttl>
    <item>
      <title>Downsampling to InfluxDB Cloud Dedicated with Java Flight SQL Client</title>
      <description>&lt;p&gt;&lt;a href="https://www.influxdata.com/products/influxdb-cloud/dedicated/"&gt;InfluxDB Cloud Dedicated&lt;/a&gt; is a hosted and managed InfluxDB Cloud cluster dedicated to a single tenant. The InfluxDB time series platform is designed to handle high write and query loads so you can use and leverage InfluxDB Cloud Dedicated for your specific time series use case. In this tutorial, we walk through the process of reading data from InfluxDB Cloud Dedicated using the Java Flight SQL client. The Java Flight SQL client is part of &lt;a href="https://www.influxdata.com/glossary/apache-arrow-flight-sql/"&gt;Apache Arrow Flight&lt;/a&gt;, a framework for building high-performance data services. It provides a way to efficiently transmit large datasets over gRPC, a modern high-performance RPC framework. Try querying InfluxDB Cloud Dedicated with the Java Flight SQL client for yourself with this &lt;a href="https://github.com/InfluxCommunity/Java_FlightSQL_Example"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="requirements-and-setup"&gt;Requirements and setup&lt;/h2&gt;

&lt;p&gt;This tutorial assumes that you already have an InfluxDB Cloud Dedicated account. It also assumes that you have &lt;a href="https://docs.docker.com/get-docker/"&gt;Docker&lt;/a&gt; available.&lt;/p&gt;

&lt;p&gt;Please keep your cluster URL handy.&lt;/p&gt;

&lt;p&gt;You will need to create the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A source database&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A target database&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Source token with Read/Write permissions&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Target token with Read/Write permissions&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During the initial setup, you need to load the data for downsampling. For the purpose of this tutorial, I have used the &lt;a href="https://github.com/influxdata/influxdb2-sample-data/blob/master/air-sensor-data/air-sensor-data-annotated.csv"&gt;NOAA air sensor dataset&lt;/a&gt;. However, other data sources such as Telegraf can be used. Here is a simple &lt;a href="https://github.com/influxdata/CloudDedicated/blob/main/telegraf.conf"&gt;Telegraf&lt;/a&gt; configuration to load the data. Check out the following documentation on &lt;a href="https://docs.influxdata.com/influxdb/cloud-dedicated/write-data/"&gt;writing data to InfluxDB Cloud Dedicated&lt;/a&gt; for other methods of writing data to InfluxDB Cloud.&lt;/p&gt;

&lt;h2 id="code-walkthrough"&gt;Code walkthrough&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Import required classes: We start by importing the required classes from Apache Arrow Flight and other necessary libraries.

&lt;pre&gt;&lt;code class="language-java"&gt;import org.apache.arrow.vector.VectorSchemaRoot;
import org.apache.arrow.vector.types.pojo.ArrowType;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.TemporalField;
import java.util.concurrent.CountDownLatch;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;

&lt;li class="mt-4"&gt;Define the main class: We define a CloudReadWriteExample class with a &lt;code class="language-java"&gt;main&lt;/code&gt; method where our code will execute.

&lt;pre&gt;&lt;code class="language-java"&gt;public class CloudReadWriteExample {
  public static void main(String[] args) {&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Set up the connection configurations: We expect that the following variables are set in ENV:

&lt;p&gt;&lt;b&gt;Source/target host&lt;/b&gt;: The source host is the Cloud Dedicated cluster URL without the protocol (“https://”) and the target host is the cluster URL &lt;b&gt;with&lt;/b&gt; the protocol (“https://”)&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Source/Target database&lt;/b&gt;: In this example, the source database stores the air sensor data before downsampling and the target database stores the downsampled data.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Source/target token&lt;/b&gt;: Tokens for the source and target databases, respectively.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Query&lt;/b&gt;: In this example, the query variable contains the downsampling query. You can replace it with any query based on your requirement.&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-java"&gt; //ReadConfigs
    private static final String SOURCE_HOST = System.getenv("SOURCE_URL");
    private static final String SOURCE_HOST = System.getenv("SOURCE_HOST");
    private static final String READ_TOKEN = System.getenv("READ_TOKEN");
    private static final String SOURCE_DATABASE_NAME = System.getenv("SOURCE_DATABASE_NAME");
    private static final String DOWNSAMPLE_QUERY = System.getenv("DOWNSAMPLE_QUERY");

    //WriteConfigs
    private static final String TARGET_CLUSTER_URL = System.getenv("TARGET_URL");
    private static final String TARGET_CLUSTER_URL = System.getenv("TARGET_CLUSTER_URL");
    private static final String WRITE_TOKEN = System.getenv("WRITE_TOKEN");
    private static final String TARGET_DATABASE_NAME = System.getenv("TARGET_DATABASE_NAME");
    private static final String TARGET_TABLE_NAME = System.getenv("TARGET_TABLE_NAME");&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Create an interceptor that injects header metadata, in this case the database name, in every request.

&lt;pre&gt;&lt;code class="language-java"&gt;FlightClientMiddleware.Factory f = info -&amp;gt; new FlightClientMiddleware() {
            @Override
            public void onBeforeSendingHeaders(CallHeaders outgoingHeaders) {
                outgoingHeaders.insert("database", SOURCE_DATABASE_NAME);
            }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Create a ‘Location’ object using the &lt;code class="language-java"&gt;forGrpcTls&lt;/code&gt; method, which sets up the connection with gRPC and Transport Layer Security (TLS) encryption.

&lt;pre&gt;&lt;code class="language-java"&gt;Location location = Location.forGrpcTls(SOURCE_HOST, 443);&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Authentication: We set up the authentication using the &lt;code class="language-java"&gt;BearerCredentialWriter&lt;/code&gt; and &lt;code class="language-java"&gt;CredentialCallOption&lt;/code&gt; classes. Replace 'READ_TOKEN' with your actual Cloud Dedicated (i.e., source database) authentication token.

&lt;pre&gt;&lt;code class="language-java"&gt;CredentialCallOption auth = new CredentialCallOption(new BearerCredentialWriter(READ_TOKEN));&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;After successful authentication, &lt;code class="language-java"&gt;execute&lt;/code&gt; returns a &lt;code class="language-java"&gt;FlightInfo&lt;/code&gt; object that contains metadata and an endpoints list. Each endpoint contains the following:

- A list of addresses where you can retrieve the data.

- A &lt;code class="language-java"&gt;ticket&lt;/code&gt; value that identifies the data to retrieve.

&lt;pre&gt;&lt;code class="language-java"&gt;FlightInfo flightInfo = sqlClient.execute(DOWNSAMPLE_QUERY, auth);

     // Extract the Flight ticket from the response.
     Ticket ticket = flightInfo.getEndpoints().get(0).getTicket();&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Retrieve the stream data of the query from the endpoint.

&lt;pre&gt;&lt;code class="language-java"&gt; // Pass the ticket to request the Arrow stream data from the endpoint.
        final FlightStream stream = sqlClient.getStream(ticket, auth);&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;Create the InfluxDB &lt;code class="language-java"&gt;WriteApi&lt;/code&gt; function using following code:

&lt;pre&gt;&lt;code class="language-java"&gt;WriteApi writeApi = influxDBClient.makeWriteApi(WriteOptions.builder()
                        .batchSize(5000)
                        .flushInterval(1000)&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;The code below iterates over the stream data, prepares measurement for each row, and writes the prepared point into the target database.

&lt;pre&gt;&lt;code class="language-java"&gt; while (stream.next()) {
            try {
                // Get the current vector data from the stream.
                final VectorSchemaRoot root = stream.getRoot();
                System.out.println(root.contentToTSVString());

                InfluxDBClient influxDBClient = InfluxDBClientFactory.create(TARGET_CLUSTER_URL, WRITE_TOKEN.toCharArray(), "", TARGET_DATABASE_NAME);
                CountDownLatch countDownLatch = new CountDownLatch(1);
                try (WriteApi writeApi = influxDBClient.makeWriteApi(WriteOptions.builder()
                        .batchSize(5000)
                        .flushInterval(1000)
                        .backpressureStrategy(BackpressureOverflowStrategy.DROP_OLDEST)
                        .bufferLimit(10000)
                        .jitterInterval(1000)
                        .retryInterval(5000)
                        .build())) {
                    writeApi.listenEvents(WriteSuccessEvent.class, (value) -&amp;gt; countDownLatch.countDown());
                    writeAsPoints(writeApi, root);
                    writeApi.flush();
                }
            } catch (Exception e) {
                // Handle exceptions.
                System.out.println("Error executing FlightSqlClient: " + e.getMessage());
            }
        }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;

&lt;li class="mt-4"&gt;The code below is a utility method to prepare a measurement from each row from &lt;code class="language-java"&gt;ArrowStream&lt;/code&gt; data.

&lt;pre&gt;&lt;code class="language-java"&gt;private void writeAsPoints(WriteApi writeApi, VectorSchemaRoot root) {
        int fields = root.getSchema().getFields().size();
        for(int i = 0; i &amp;lt; rowCount; i++) {
            Point point = Point.measurement(TARGET_TABLE_NAME);
            for (int j=0;j&amp;lt;fields;j++) {
                String fieldName = root.getSchema().getFields().get(j).getName();
                ArrowType fieldType = root.getSchema().getFields().get(j).getType();
                if (fieldName.equalsIgnoreCase("time") &amp;amp;&amp;amp; fieldType instanceof ArrowType.Timestamp) {
                    point.time(((LocalDateTime) root.getFieldVectors().get(j)
                        .getObject(i)).atZone(ZoneId.systemDefault()).toInstant(), WritePrecision.NS);
                } else {
                    point.addField(fieldName, root.getFieldVectors().get(j).getObject(i).toString());
                }
            }
            writeApi.writePoint(TARGET_DATABASE_NAME, TARGET_TABLE_NAME, point);
        }
    }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
  &lt;/ol&gt;

&lt;p&gt;You can find the full script &lt;a href="https://github.com/InfluxCommunity/Java_FlightSQL_Example"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="query-perform-downsampling-and-write-data-back-to-influxdb-cloud-dedicated-with-java-flight-sql"&gt;Query, perform downsampling, and write data back to InfluxDB Cloud Dedicated with Java Flight SQL&lt;/h2&gt;

&lt;p&gt;To run the example in the corresponding repo, follow the following steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Clone the repo and cd into it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Run &lt;code class="language-java"&gt;docker build -t myimage&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Run &lt;code class="language-java"&gt;docker run myimage&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="visualizing-the-data-with-grafana"&gt;Visualizing the data with Grafana&lt;/h2&gt;

&lt;p&gt;Use  &lt;a href="https://www.influxdata.com/grafana/"&gt;Grafana&lt;/a&gt; to query and visualize data stored in an InfluxDB Cloud Dedicated database. InfluxDB Cloud Dedicated supports both SQL and InfluxQL query languages. Install the &lt;a href="https://grafana.com/grafana/plugins/influxdata-flightsql-datasource/"&gt;Grafana FlightSQL plugin&lt;/a&gt; to query InfluxDB with SQL using the Flight SQL protocol.&lt;/p&gt;

&lt;p&gt;This &lt;a href="https://docs.influxdata.com/influxdb/cloud-dedicated/query-data/tools/grafana/"&gt;Grafana installation&lt;/a&gt; link provides instructions on how to install Grafana and visualize the data.&lt;/p&gt;

&lt;h2 id="querying-the-data-with-grafana"&gt;Querying the data with Grafana&lt;/h2&gt;

&lt;p&gt;You can use the Flight SQL connection data source to query the data in a Cloud Dedicated database.&lt;/p&gt;

&lt;p&gt;&lt;img src="//images.ctfassets.net/o7xu9whrs0u9/3wi4lLmZdJmJ3G46iM0bVI/a02f81940acf7f98135e0603b9c25c2a/downsampling-influxdb-cloud-dedicated-java-flight-sql-client.png" alt="downsampling-influxdb-cloud-dedicated-java-flight-sql-client" /&gt;&lt;/p&gt;

&lt;h2 id="resources-and-conclusion"&gt;Resources and conclusion&lt;/h2&gt;

&lt;p&gt;Take a look at the following documentation. It helped me build this example, and it can help you on your journey with querying InfluxDB Cloud Dedicated:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Reference documentation for  &lt;a href="https://arrow.apache.org/docs/dev/java/reference/"&gt;Arrow Flight&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Reference documentation for &lt;a href="https://arrow.apache.org/docs/dev/java/reference/org/apache/arrow/flight/sql/FlightSqlClient.html"&gt;Arrow Flight SQL for the Java Client&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;InfluxDB Cloud documentation for &lt;a href="https://docs.influxdata.com/influxdb/cloud-serverless/query-data/execute-queries/flight-sql/"&gt;Querying data with Arrow Flight SQL in Python&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A blog post on &lt;a href="https://www.influxdata.com/blog/influxdb-flight-sql-pandas-jupyter-notebooks-tutorial/"&gt;InfluxDB, Flight SQL, Pandas, and Jupyter Notebooks Tutorial&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A blog post on &lt;a href="https://www.influxdata.com/blog/tldr-influxdb-tech-tips-downsampling-flight-sql-aws-lambda/"&gt;Downsampling with Flight SQL and AWS Lambda&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I hope this blog post inspires you to explore InfluxDB Cloud Dedicated and take advantage of Flight SQL to transport large datasets from InfluxDB for data processing with the tools of your choice. If you need any help, please reach out using our &lt;a href="https://community.influxdata.com/"&gt;community site&lt;/a&gt; or &lt;a href="https://influxdata.com/slack"&gt;Slack&lt;/a&gt; channel. I’d love to hear about what you’re trying to achieve and what features you’d like InfluxDB to have.&lt;/p&gt;
</description>
      <pubDate>Fri, 09 Jun 2023 07:00:00 +0000</pubDate>
      <link>https://www.influxdata.com/blog/downsampling-influxdb-cloud-dedicated-java-flight-sql-client/</link>
      <guid isPermaLink="true">https://www.influxdata.com/blog/downsampling-influxdb-cloud-dedicated-java-flight-sql-client/</guid>
      <category>Product</category>
      <author>Subashini Sukumar (InfluxData)</author>
    </item>
  </channel>
</rss>
