Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: update onboarding steps for Java v3 client #6994

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 109 additions & 17 deletions src/homepageExperience/components/steps/java/ExecuteQuerySql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,105 @@ FROM 'census'
WHERE time >= now() - interval '1 hour'
AND ('bees' IS NOT NULL OR 'ants' IS NOT NULL) order by time asc`

const query = `String sql = "SELECT * " +
"FROM 'census' " +
"WHERE time >= now() - interval '1 hour' " +
"AND ('bees' IS NOT NULL OR 'ants' IS NOT NULL) order by time asc";
const query = ` String sql = "SELECT * " +
"FROM 'census' " +
"WHERE time >= now() - interval '5 minutes' " +
"AND ('$species1' IS NOT NULL OR '$species2' IS NOT NULL) order by time asc";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we updating this query due to a failure with the test dataset, or is this simply designed to illustrate a different principle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query parameters are a feature added in the 0.6.0 client library release from March of last year.

The text above the snippet briefly introduces them: "The following code replaces the fixed values of "bees" and "ants" with the parameters $species1 and $species2."

We thought users would like to be made aware of this feature. A number of users requested it and are now using it.


System.out.printf("| %-5s | %-5s | %-8s | %-30s |%n", "ants", "bees", "location", "time");
try (Stream<Object[]> stream = client.query(sql, new QueryOptions("${bucket}", QueryType.SQL))) {
stream.forEach(row -> System.out.printf("| %-5s | %-5s | %-8s | %-30s |%n", row[0], row[1], row[2], row[3]));
}
System.out.printf("| %-5s | %-5s | %-8s | %-30s |%n", "ants", "bees", "location", "time");

try (Stream<PointValues> ps = client.queryPoints(sql,
Map.of(
"species1", "bees",
"species2", "ants"), // Set Query Parameters
new QueryOptions("${bucket}", QueryType.SQL))) { // Set Query Options
ps.forEach(pv ->
System.out.printf("| %-5s | %-5s | %-8s | %-30s |%n",
IntOrDefault(pv, "ants", 0),
IntOrDefault(pv,"bees", 0),
pv.getTag("location"),
InstantTime(pv, Instant.ofEpochSecond(0))));
}
`

const queryPreview = `| ants | bees | location | time |
| null | 23 | Klamath | 2023-06-02T10:21:21.083529279 |
| 30 | null | Portland | 2023-06-02T10:21:22.276295461 |
| null | 28 | Klamath | 2023-06-02T10:21:23.462901032 |
| 32 | null | Portland | 2023-06-02T10:21:24.608998154 |
| null | 29 | Klamath | 2023-06-02T10:21:25.762346305 |
| 40 | null | Portland | 2023-06-02T10:21:26.901005154 |
| 0 | 23 | Klamath | 2024-12-18T15:58:07.275779579Z |
| 30 | 0 | Portland | 2024-12-18T15:58:08.275779579Z |
| 0 | 28 | Klamath | 2024-12-18T15:58:09.275779579Z |
| 32 | 0 | Portland | 2024-12-18T15:58:10.275779579Z |
| 0 | 29 | Klamath | 2024-12-18T15:58:11.275779579Z |
| 40 | 0 | Portland | 2024-12-18T15:58:12.275779579Z |
`

const staticHelpers = ` private static long IntOrDefault(final PointValues pointValues,
final String key,
final long defaultValue){
Long result = pointValues.getIntegerField(key);
return result == null ? defaultValue : result;
}

private static Instant InstantTime(final PointValues pointValues,
final Instant replacement){
Number raw = pointValues.getTimestamp();
if(raw == null) {
if (replacement == null){
return Instant.ofEpochSecond(0);
}
return replacement;
}
long stamp = raw.longValue();
long sec = stamp / 1000000000;
long nanos = stamp % 1000000000;
return Instant.ofEpochSecond(sec, nanos);
}
`

return (
<>
<h1>Execute a SQL Query</h1>
<p>
The query transport makes use of Apache Arrow Flight to shorten
processing time. When executing queries Arrow needs access to internal
JVM resources. This means setting the following JVM argument:{' '}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might correct "means" to "This requires setting the following JVM argument"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

<code>--add-opens=java.base/java.nio=ALL-UNNAMED</code>
</p>
<h2>Java</h2>
<p>
With straightforward Java this can be done with an environment variable:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should qualify whether the script is 'straightforward' since it should speak for itself -- "This can be done with an environment variable" should be enough.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

</p>
<CodeSnippet
language="bash"
onCopy={logCopyCodeSnippet}
showCopyControl={false}
text='export JDK_JAVA_OPTIONS="--add-opens=java.base/java.nio=ALL-UNNAMED"'
/>
<h2>Maven</h2>
<p>
This argument can also be added to <code>MAVEN_OPTS</code>:
</p>
<CodeSnippet
language="bash"
onCopy={logCopyCodeSnippet}
showCopyControl={false}
text='export MAVEN_OPTS="--add-opens=java.base/java.nio=ALL-UNNAMED"'
/>
<h2>Gradle</h2>
<p>
With gradle this can be added to the build file, e.g. in{' '}
<code>build.gradle.kts</code>:
</p>
<CodeSnippet
language="kotlin"
onCopy={logCopyCodeSnippet}
showCopyControl={false}
text='...
application {
mainClass = "example.InfluxClientExample"
applicationDefaultJvmArgs = listOf("--add-opens=java.base/java.nio=ALL-UNNAMED")
}
...'
/>

<p>
Now let's query the data we wrote into the database with SQL. Here is
what our query looks like on its own:
Expand All @@ -57,11 +133,27 @@ try (Stream<Object[]> stream = client.query(sql, new QueryOptions("${bucket}", Q
with a "census" measurement and either "bees" or "ants" fields.
</p>
<p>
Let's use that SQL query in our <code>Java</code> code to show us the
results of what we have written.
The client API will pass through null values for mismatched or missing
tags, fields and timestamps. In anticipation of this possibility copy
the following static helper methods to the <em>bottom</em> of the{' '}
<code>InfluxClientExample</code> class.
</p>
<CodeSnippet
language="java"
onCopy={logCopyCodeSnippet}
text={staticHelpers}
/>
<p>
Now let's use the model SQL query in our <code>Java</code> code to show
us the results of what we have written. Furthermore, let's use the SQL
query parameters feature of the client library to make query calls more
dynamic.
</p>
<p>
Add the following code to the <code>WriteQueryExample</code> class:
The following code replaces the fixed values of "bees" and "ants" with
the parameters <code>$species1</code> and <code>$species2</code>. Add it
to the <code>InfluxClientExample</code> class <em>after</em> the write
code added in the previous step:
</p>
<CodeSnippet language="java" onCopy={logCopyCodeSnippet} text={query} />
<p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ import java.time.Instant;
import java.util.stream.Stream;

import com.influxdb.v3.client.InfluxDBClient;
import com.influxdb.v3.client.Point;
import com.influxdb.v3.client.query.QueryOptions;
import com.influxdb.v3.client.query.QueryType;
import com.influxdb.v3.client.write.Point;
import com.influxdb.v3.client.write.WriteOptions;

public final class WriteQueryExample {
public final class InfluxClientExample {

public static void main(final String[] args) throws Exception {
String hostUrl = "${url}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ export const InstallDependenciesSql: FC = () => {
}

const mavenDependency = `<dependency>
<groupId>com.influxdb</groupId>
<artifactId>influxdb3-java</artifactId>
<version>0.2.0</version>
</dependency>`
<groupId>com.influxdb</groupId>
<artifactId>influxdb3-java</artifactId>
<version>1.0.0</version>
</dependency>`
const gradleDependency = `dependencies {
implementation "com.influxdb:influxdb3-java:0.2.0"
implementation("com.influxdb:influxdb3-java:1.0.0")
}`
return (
<>
Expand Down
98 changes: 70 additions & 28 deletions src/homepageExperience/components/steps/java/WriteDataSql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,36 +49,57 @@ export const WriteDataSqlComponent = (props: OwnProps) => {
onSelectBucket(bucket.name)
}, [bucket, onSelectBucket])

const codeSnippet = `String database = "${bucket.name}";
const internalClass = ` static class CensusRecord {
String location;
String species;
int count;

Point[] points = new Point[] {
Point.measurement("census")
.addTag("location", "Klamath")
.addField("bees", 23),
Point.measurement("census")
.addTag("location", "Portland")
.addField("ants", 30),
Point.measurement("census")
.addTag("location", "Klamath")
.addField("bees", 28),
Point.measurement("census")
.addTag("location", "Portland")
.addField("ants", 32),
Point.measurement("census")
.addTag("location", "Klamath")
.addField("bees", 29),
Point.measurement("census")
.addTag("location", "Portland")
.addField("ants", 40)
};
public CensusRecord(String location, String species, int count) {
this.location = location;
this.species = species;
this.count = count;
}

for (Point point : points) {
client.writePoint(point, new WriteOptions.Builder().database(database).build());

Thread.sleep(1000); // separate points by 1 second
}
public String getLocation() {
return location;
}

public String getSpecies() {
return species;
}

public int getCount() {
return count;
}
}`

const dataPrep = ` String database = "${bucket.name}";

List<CensusRecord> records = Arrays.asList(
new CensusRecord("Klamath", "bees", 23),
new CensusRecord("Portland", "ants", 30),
new CensusRecord("Klamath", "bees", 28),
new CensusRecord("Portland", "ants", 32),
new CensusRecord("Klamath", "bees", 29),
new CensusRecord("Portland", "ants", 40)
);

List<Point> points = new ArrayList<>();

System.out.println("Complete. Return to the InfluxDB UI.");
Instant stamp = Instant.now().minusSeconds(records.size());

for (CensusRecord record : records) {
points.add(Point.measurement("census")
.setTag("location", record.getLocation())
.setIntegerField(record.getSpecies(), record.getCount())
.setTimestamp(stamp)
);
stamp = stamp.plusSeconds(1);
}`

const codeSnippet = ` client.writePoints(points, new WriteOptions.Builder().database(database).build());

System.out.println("Complete. Return to the InfluxDB UI.");
`

return (
Expand Down Expand Up @@ -239,7 +260,28 @@ System.out.println("Complete. Return to the InfluxDB UI.");
let's write this data into our bucket.
</p>
<p>
Add the following code to the <code>WriteQueryExample</code> class:
First, add the following internal class to the
<code>InfluxClientExample</code> <em>above</em> the <code>main</code>{' '}
method:
</p>
<CodeSnippet
language="java"
onCopy={logCopyCodeSnippet}
text={internalClass}
/>
<p>
Then, copy the following data preparation statements, into the{' '}
<code>main</code> method <em>above</em> the{' '}
<code>try(InfluxDBClient ...)</code> block:
</p>
<CodeSnippet
language="java"
onCopy={logCopyCodeSnippet}
text={dataPrep}
/>
<p>
Finally, add the following code <em>within</em> the{' '}
<code>try(InfluxDBClient ...)</code> block:
</p>
<CodeSnippet
language="java"
Expand Down
Loading