From 8578f5f470fb7f9980fad74429b9533932fdc8b8 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 18 Sep 2026 17:28:19 -0400 Subject: [PATCH 1/2] docs(bigquery): add QueryArrow code sample and document JDK 17+ JVM requirements --- java-bigquery/README.md | 1 + .../com/google/cloud/bigquery/BigQuery.java | 16 ++++ .../java/com/example/bigquery/QueryArrow.java | 80 +++++++++++++++++++ .../com/example/bigquery/QueryArrowIT.java | 61 ++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java create mode 100644 java-bigquery/samples/snippets/src/test/java/com/example/bigquery/QueryArrowIT.java diff --git a/java-bigquery/README.md b/java-bigquery/README.md index 0305dd937b54..ce3126e9ae19 100644 --- a/java-bigquery/README.md +++ b/java-bigquery/README.md @@ -197,6 +197,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-bigquery/tree | Load Partitioned Table | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/LoadPartitionedTable.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/LoadPartitionedTable.java) | | Load Table Clustered | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/LoadTableClustered.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/LoadTableClustered.java) | | Nested Repeated Schema | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/NestedRepeatedSchema.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/NestedRepeatedSchema.java) | +| Query Arrow | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java) | | Query Batch | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/QueryBatch.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/QueryBatch.java) | | Query Clustered Table | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/QueryClusteredTable.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/QueryClusteredTable.java) | | Query Destination Table Cmek | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/QueryDestinationTableCmek.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/QueryDestinationTableCmek.java) | diff --git a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java index 7ca564912c43..b5c278a0a146 100644 --- a/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java +++ b/java-bigquery/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java @@ -1650,6 +1650,14 @@ TableResult query(QueryJobConfiguration configuration, JobId jobId, JobOption... *

Prerequisite: Requires the BigQuery Storage Read API ({@code * bigquerystorage.googleapis.com}) to be enabled on your GCP project. * + *

JVM Requirements (Java 16+): Apache Arrow uses internal {@code java.nio} + * DirectByteBuffer access for off-heap buffer management. Applications running on Java 16 or + * newer must supply the following JVM argument: + * + *

{@code
+   * --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED
+   * }
+ * * @param configuration the query configuration * @param options query options * @return an {@link ArrowQueryResult} streaming Arrow vectors @@ -1675,6 +1683,14 @@ default ArrowQueryResult queryArrow(QueryJobConfiguration configuration, JobOpti *

Prerequisite: Requires the BigQuery Storage Read API ({@code * bigquerystorage.googleapis.com}) to be enabled on your GCP project. * + *

JVM Requirements (Java 16+): Apache Arrow uses internal {@code java.nio} + * DirectByteBuffer access for off-heap buffer management. Applications running on Java 16 or + * newer must supply the following JVM argument: + * + *

{@code
+   * --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED
+   * }
+ * * @param configuration the query configuration * @param jobId the job ID to use * @param options query options diff --git a/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java b/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java new file mode 100644 index 000000000000..51a7b89ff5c7 --- /dev/null +++ b/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java @@ -0,0 +1,80 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.bigquery; + +// [START bigquery_query_arrow] + +import com.google.cloud.bigquery.ArrowQueryResult; +import com.google.cloud.bigquery.BigQuery; +import com.google.cloud.bigquery.BigQueryException; +import com.google.cloud.bigquery.BigQueryOptions; +import com.google.cloud.bigquery.QueryJobConfiguration; +import org.apache.arrow.vector.FieldVector; +import org.apache.arrow.vector.VectorSchemaRoot; + +public class QueryArrow { + + public static void main(String[] args) { + // TODO(developer): Replace this query before running the sample. + String query = + "SELECT corpus, count(*) as corpus_count " + + "FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;"; + queryArrow(query); + } + + /** + * Runs a query and streams Apache Arrow {@link VectorSchemaRoot} batches directly for zero-copy + * vector access. + * + *

JVM Requirements (Java 16+): Applications running on Java 16 or newer must supply the + * following JVM option to allow Apache Arrow's memory allocator access to internal + * DirectByteBuffer: + * + *

{@code --add-opens=java.base/java.nio=org.apache.arrow.memory.core,ALL-UNNAMED}
+ */ + public static void queryArrow(String query) { + try { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService(); + + // Create the query configuration. + QueryJobConfiguration queryConfig = QueryJobConfiguration.newBuilder(query).build(); + + // Execute the query using queryArrow. Always close ArrowQueryResult to free off-heap memory. + try (ArrowQueryResult result = bigquery.queryArrow(queryConfig)) { + long totalRows = 0; + for (VectorSchemaRoot root : result) { + int rowCount = root.getRowCount(); + totalRows += rowCount; + FieldVector corpusVector = root.getVector("corpus"); + FieldVector countVector = root.getVector("corpus_count"); + + for (int i = 0; i < rowCount; i++) { + System.out.print("corpus:" + corpusVector.getObject(i)); + System.out.print(", count:" + countVector.getObject(i)); + System.out.println(); + } + } + System.out.println("Arrow query ran successfully. Total rows: " + totalRows); + } + } catch (BigQueryException | InterruptedException e) { + System.out.println("Arrow query did not run \n" + e.toString()); + } + } +} +// [END bigquery_query_arrow] diff --git a/java-bigquery/samples/snippets/src/test/java/com/example/bigquery/QueryArrowIT.java b/java-bigquery/samples/snippets/src/test/java/com/example/bigquery/QueryArrowIT.java new file mode 100644 index 000000000000..66e76d95f16d --- /dev/null +++ b/java-bigquery/samples/snippets/src/test/java/com/example/bigquery/QueryArrowIT.java @@ -0,0 +1,61 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.bigquery; + +import static com.google.common.truth.Truth.assertThat; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class QueryArrowIT { + + private final Logger log = Logger.getLogger(this.getClass().getName()); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + // restores print statements in the original method + System.out.flush(); + System.setOut(originalPrintStream); + log.log(Level.INFO, "\n" + bout.toString()); + } + + @Test + public void testQueryArrow() { + String query = + "SELECT corpus, count(*) as corpus_count " + + "FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;"; + + QueryArrow.queryArrow(query); + assertThat(bout.toString()).contains("Arrow query ran successfully"); + } +} From eb5f424c2c719b711aa31a54acb802647d166088 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 18 Sep 2026 17:47:30 -0400 Subject: [PATCH 2/2] fix(bigquery): restore interrupted status in QueryArrow sample --- .../src/main/java/com/example/bigquery/QueryArrow.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java b/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java index 51a7b89ff5c7..b79508dd3363 100644 --- a/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java +++ b/java-bigquery/samples/snippets/src/main/java/com/example/bigquery/QueryArrow.java @@ -72,8 +72,11 @@ public static void queryArrow(String query) { } System.out.println("Arrow query ran successfully. Total rows: " + totalRows); } - } catch (BigQueryException | InterruptedException e) { + } catch (BigQueryException e) { System.out.println("Arrow query did not run \n" + e.toString()); + } catch (InterruptedException e) { + System.out.println("Arrow query was interrupted \n" + e.toString()); + Thread.currentThread().interrupt(); } } }