This is an automated email from the ASF dual-hosted git repository.
ahmedabualsaud pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/beam.git
The following commit(s) were added to refs/heads/master by this push:
new e85df7942df Add Managed Iceberg example (#32678)
e85df7942df is described below
commit e85df7942df028969c8d43c64ecb0261e4de65d3
Author: Ahmed Abualsaud <[email protected]>
AuthorDate: Mon Nov 4 12:41:52 2024 +0300
Add Managed Iceberg example (#32678)
* add iceberg example
* runtime dependency
* update to let the sink create tables
* remove dependencies
---
examples/java/build.gradle | 4 +
.../examples/cookbook/IcebergTaxiExamples.java | 119 +++++++++++++++++++++
2 files changed, 123 insertions(+)
diff --git a/examples/java/build.gradle b/examples/java/build.gradle
index af91fa83fe9..4f1902cf167 100644
--- a/examples/java/build.gradle
+++ b/examples/java/build.gradle
@@ -66,6 +66,8 @@ dependencies {
implementation project(":sdks:java:extensions:python")
implementation project(":sdks:java:io:google-cloud-platform")
implementation project(":sdks:java:io:kafka")
+ runtimeOnly project(":sdks:java:io:iceberg")
+ implementation project(":sdks:java:managed")
implementation project(":sdks:java:extensions:ml")
implementation library.java.avro
implementation library.java.bigdataoss_util
@@ -100,6 +102,8 @@ dependencies {
implementation "org.apache.httpcomponents:httpcore:4.4.13"
implementation "com.fasterxml.jackson.core:jackson-annotations:2.14.1"
implementation "com.fasterxml.jackson.core:jackson-core:2.14.1"
+ runtimeOnly library.java.hadoop_client
+ runtimeOnly library.java.bigdataoss_gcs_connector
testImplementation project(path: ":runners:direct-java", configuration:
"shadow")
testImplementation project(":sdks:java:io:google-cloud-platform")
testImplementation project(":sdks:java:extensions:ml")
diff --git
a/examples/java/src/main/java/org/apache/beam/examples/cookbook/IcebergTaxiExamples.java
b/examples/java/src/main/java/org/apache/beam/examples/cookbook/IcebergTaxiExamples.java
new file mode 100644
index 00000000000..446d11d03be
--- /dev/null
+++
b/examples/java/src/main/java/org/apache/beam/examples/cookbook/IcebergTaxiExamples.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.beam.examples.cookbook;
+
+import java.util.Arrays;
+import java.util.Map;
+import org.apache.beam.sdk.Pipeline;
+import org.apache.beam.sdk.extensions.gcp.options.GcpOptions;
+import org.apache.beam.sdk.io.gcp.pubsub.PubsubIO;
+import org.apache.beam.sdk.managed.Managed;
+import org.apache.beam.sdk.options.Default;
+import org.apache.beam.sdk.options.Description;
+import org.apache.beam.sdk.options.PipelineOptionsFactory;
+import org.apache.beam.sdk.options.Validation;
+import org.apache.beam.sdk.schemas.Schema;
+import org.apache.beam.sdk.schemas.transforms.Filter;
+import org.apache.beam.sdk.transforms.JsonToRow;
+import org.apache.beam.sdk.values.Row;
+import
org.apache.beam.vendor.guava.v32_1_2_jre.com.google.common.collect.ImmutableMap;
+
+/**
+ * Reads real-time NYC taxi ride information from {@code
+ * projects/pubsub-public-data/topics/taxirides-realtime} and writes to
Iceberg tables using Beam's
+ * {@link Managed} IcebergIO sink.
+ *
+ * <p>This is a streaming pipeline that writes records to Iceberg tables
dynamically, depending on
+ * each record's passenger count. New tables are created as needed. We set a
triggering frequency of
+ * 10s; at around this interval, the sink will accumulate records and write
them to the appropriate
+ * table, creating a new snapshot each time.
+ */
+public class IcebergTaxiExamples {
+ private static final String TAXI_RIDES_TOPIC =
+ "projects/pubsub-public-data/topics/taxirides-realtime";
+ private static final Schema TAXI_RIDE_INFO_SCHEMA =
+ Schema.builder()
+ .addStringField("ride_id")
+ .addInt32Field("point_idx")
+ .addDoubleField("latitude")
+ .addDoubleField("longitude")
+ .addStringField("timestamp")
+ .addDoubleField("meter_reading")
+ .addDoubleField("meter_increment")
+ .addStringField("ride_status")
+ .addInt32Field("passenger_count")
+ .build();
+
+ public static void main(String[] args) {
+ IcebergPipelineOptions options =
+ PipelineOptionsFactory.fromArgs(args).as(IcebergPipelineOptions.class);
+ options.setProject("apache-beam-testing");
+
+ // each record's 'passenger_count' value will be substituted in to
determine
+ // its final table destination
+ // e.g. an event with 3 passengers will be written to
'iceberg_taxi.3_passengers'
+ String tableIdentifierTemplate =
"iceberg_taxi.{passenger_count}_passengers";
+
+ Map<String, String> catalogProps =
+ ImmutableMap.<String, String>builder()
+ .put("catalog-impl", options.getCatalogImpl())
+ .put("warehouse", options.getWarehouse())
+ .build();
+ Map<String, Object> icebergWriteConfig =
+ ImmutableMap.<String, Object>builder()
+ .put("table", tableIdentifierTemplate)
+ .put("catalog_name", options.getCatalogName())
+ .put("catalog_properties", catalogProps)
+ .put("triggering_frequency_seconds", 10)
+ // perform a final filter to only write these two columns
+ .put("keep", Arrays.asList("ride_id", "meter_reading"))
+ .build();
+
+ Pipeline p = Pipeline.create(options);
+ p
+ // Read taxi ride data
+ .apply(PubsubIO.readStrings().fromTopic(TAXI_RIDES_TOPIC))
+ // Convert JSON strings to Beam Rows
+ .apply(JsonToRow.withSchema(TAXI_RIDE_INFO_SCHEMA))
+ // Filter to only include drop-offs
+ .apply(Filter.<Row>create().whereFieldName("ride_status",
"dropoff"::equals))
+ // Write to Iceberg tables
+ .apply(Managed.write(Managed.ICEBERG).withConfig(icebergWriteConfig));
+ p.run();
+ }
+
+ public interface IcebergPipelineOptions extends GcpOptions {
+ @Description("Warehouse location where the table's data will be written
to.")
+ @Default.String("gs://apache-beam-samples/iceberg-examples")
+ String getWarehouse();
+
+ void setWarehouse(String warehouse);
+
+ @Description("Fully-qualified name of the catalog class to use.")
+ @Default.String("org.apache.iceberg.hadoop.HadoopCatalog")
+ String getCatalogImpl();
+
+ void setCatalogImpl(String catalogName);
+
+ @Validation.Required
+ @Default.String("example-catalog")
+ String getCatalogName();
+
+ void setCatalogName(String catalogName);
+ }
+}