Skip to content

Commit f06772e

Browse files
authored
feat(yaml): Add Pub/Sub to Iceberg YAML template (#4020)
1 parent b3660ae commit f06772e

4 files changed

Lines changed: 804 additions & 0 deletions

File tree

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
2+
Pub/Sub to Iceberg (YAML) template
3+
---
4+
The Pub/Sub to Iceberg template is a streaming pipeline that ingests data from a
5+
Pub/Sub topic or subscription and writes the records to an Apache Iceberg table.
6+
7+
8+
9+
:bulb: This is a generated documentation based
10+
on [Metadata Annotations](https://github.com/GoogleCloudPlatform/DataflowTemplates/blob/main/contributor-docs/code-contributions.md#metadata-annotations)
11+
. Do not change this file directly.
12+
13+
## Parameters
14+
15+
### Required parameters
16+
17+
* **topic**: Pub/Sub topic to read the input from. For example, `projects/your-project-id/topics/your-topic-name`.
18+
* **format**: The message format. One of: AVRO, JSON, PROTO, RAW, or STRING.
19+
* **schema**: A schema is required if data format is JSON, AVRO or PROTO. For JSON, this is a JSON schema. For AVRO and PROTO, this is the full schema definition.
20+
* **table**: A fully-qualified table identifier, e.g., my_dataset.my_table. For example, `my_dataset.my_table`.
21+
* **catalogName**: The name of the Iceberg catalog that contains the table. For example, `my_hadoop_catalog`.
22+
* **catalogProperties**: A map of properties for setting up the Iceberg catalog. For example, `{"type": "hadoop", "warehouse": "gs://your-bucket/warehouse"}`.
23+
* **triggeringFrequencySeconds**: The frequency in seconds for producing snapshots in a streaming pipeline. For example, `60`.
24+
25+
### Optional parameters
26+
27+
* **attributes**: List of attribute keys whose values will be flattened into the output message as additional fields. For example, if the format is `raw` and attributes is `[a, b]` then this read will produce elements of the form `Row(payload=..., a=..., b=...)`.
28+
* **attributesMap**: Name of a field in which to store the full set of attributes associated with this message. For example, if the format is `raw` and `attribute_map` is set to `attrs` then this read will produce elements of the form `Row(payload=..., attrs=...)` where `attrs` is a Map type of string to string. If both `attributes` and `attribute_map` are set, the overlapping attribute values will be present in both the flattened structure and the attribute map.
29+
* **idAttribute**: The attribute on incoming Pub/Sub messages to use as a unique record identifier. When specified, the value of this attribute (which can be any string that uniquely identifies the record) will be used for deduplication of messages. If not provided, we cannot guarantee that no duplicate data will be delivered on the Pub/Sub stream. In this case, deduplication of the stream will be strictly best effort.
30+
* **timestampAttribute**: Message value to use as element timestamp. If None, uses message publishing time as the timestamp. Timestamp values should be in one of two formats: 1). A numerical value representing the number of milliseconds since the Unix epoch. 2). A string in RFC 3339 format, UTC timezone. Example: ``2015-10-29T23:41:41.123Z``. The sub-second component of the timestamp is optional, and digits beyond the first three (i.e., time units smaller than milliseconds) may be ignored.
31+
* **errorHandling**: This option specifies whether and where to output error rows.
32+
* **subscription**: Pub/Sub subscription to read the input from. For example, `projects/your-project-id/subscriptions/your-subscription-name`.
33+
* **configProperties**: A map of properties to pass to the Hadoop Configuration. For example, `{"fs.gs.impl": "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem"}`.
34+
* **drop**: A list of field names to drop. Mutually exclusive with 'keep' and 'only'. For example, `["field_to_drop_1", "field_to_drop_2"]`.
35+
* **filter**: A filter expression to apply to records from the Iceberg table. For example, `age > 18`.
36+
* **keep**: A list of field names to keep. Mutually exclusive with 'drop' and 'only'. For example, `["field_to_keep_1", "field_to_keep_2"]`.
37+
* **only**: The name of a single field to write. Mutually exclusive with 'keep' and 'drop'. For example, `my_record_field`.
38+
* **partitionFields**: A list of fields and transforms for partitioning, e.g., ['day(ts)', 'category']. For example, `["day(ts)", "bucket(id, 4)"]`.
39+
* **tableProperties**: A map of Iceberg table properties to set when the table is created. For example, `{"commit.retry.num-retries": "2"}`.
40+
* **sdfCheckpointAfterDuration**: Duration after which to checkpoint stateful DoFns. For example: 30s. Documentation: https://docs.cloud.google.com/dataflow/docs/reference/service-options For example, `30s`. Defaults to: 30s.
41+
* **sdfCheckpointAfterOutputBytes**: Output bytes after which to checkpoint stateful DoFns. For example: 536870912. Documentation: https://docs.cloud.google.com/dataflow/docs/reference/service-options For example, `536870912`. Defaults to: 536870912.
42+
43+
44+
45+
## Getting Started
46+
47+
### Requirements
48+
49+
* Java 17
50+
* Maven
51+
* [gcloud CLI](https://cloud.google.com/sdk/gcloud), and execution of the
52+
following commands:
53+
* `gcloud auth login`
54+
* `gcloud auth application-default login`
55+
56+
:star2: Those dependencies are pre-installed if you use Google Cloud Shell!
57+
58+
[![Open in Cloud Shell](http://gstatic.com/cloudssh/images/open-btn.svg)](https://console.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2FGoogleCloudPlatform%2FDataflowTemplates.git&cloudshell_open_in_editor=yaml/src/main/java/com/google/cloud/teleport/templates/yaml/PubsubToIcebergYaml.java)
59+
60+
### Templates Plugin
61+
62+
This README provides instructions using
63+
the [Templates Plugin](https://github.com/GoogleCloudPlatform/DataflowTemplates/blob/main/contributor-docs/code-contributions.md#templates-plugin).
64+
65+
#### Validating the Template
66+
67+
This template has a validation command that is used to check code quality.
68+
69+
```shell
70+
mvn clean install -PtemplatesValidate \
71+
-DskipTests -am \
72+
-pl yaml
73+
```
74+
75+
### Building Template
76+
77+
This template is a Flex Template, meaning that the pipeline code will be
78+
containerized and the container will be executed on Dataflow. Please
79+
check [Use Flex Templates](https://cloud.google.com/dataflow/docs/guides/templates/using-flex-templates)
80+
and [Configure Flex Templates](https://cloud.google.com/dataflow/docs/guides/templates/configuring-flex-templates)
81+
for more information.
82+
83+
#### Staging the Template
84+
85+
If the plan is to just stage the template (i.e., make it available to use) by
86+
the `gcloud` command or Dataflow "Create job from template" UI,
87+
the `-PtemplatesStage` profile should be used:
88+
89+
```shell
90+
export PROJECT=<my-project>
91+
export BUCKET_NAME=<bucket-name>
92+
export ARTIFACT_REGISTRY_REPO=<region>-docker.pkg.dev/$PROJECT/<repo>
93+
94+
mvn clean package -PtemplatesStage \
95+
-DskipTests \
96+
-DprojectId="$PROJECT" \
97+
-DbucketName="$BUCKET_NAME" \
98+
-DartifactRegistry="$ARTIFACT_REGISTRY_REPO" \
99+
-DstagePrefix="templates" \
100+
-DtemplateName="Pubsub_To_Iceberg_Yaml" \
101+
-f yaml
102+
```
103+
104+
The `-DartifactRegistry` parameter can be specified to set the artifact registry repository of the Flex Templates image.
105+
If not provided, it defaults to `gcr.io/<project>`.
106+
107+
The command should build and save the template to Google Cloud, and then print
108+
the complete location on Cloud Storage:
109+
110+
```
111+
Flex Template was staged! gs://<bucket-name>/templates/flex/Pubsub_To_Iceberg_Yaml
112+
```
113+
114+
The specific path should be copied as it will be used in the following steps.
115+
116+
#### Running the Template
117+
118+
**Using the staged template**:
119+
120+
You can use the path above run the template (or share with others for execution).
121+
122+
To start a job with the template at any time using `gcloud`, you are going to
123+
need valid resources for the required parameters.
124+
125+
Provided that, the following command line can be used:
126+
127+
```shell
128+
export PROJECT=<my-project>
129+
export BUCKET_NAME=<bucket-name>
130+
export REGION=us-central1
131+
export TEMPLATE_SPEC_GCSPATH="gs://$BUCKET_NAME/templates/flex/Pubsub_To_Iceberg_Yaml"
132+
133+
### Required
134+
export TOPIC=<topic>
135+
export FORMAT=<format>
136+
export SCHEMA=<schema>
137+
export TABLE=<table>
138+
export CATALOG_NAME=<catalogName>
139+
export CATALOG_PROPERTIES=<catalogProperties>
140+
export TRIGGERING_FREQUENCY_SECONDS=<triggeringFrequencySeconds>
141+
142+
### Optional
143+
export ATTRIBUTES=<attributes>
144+
export ATTRIBUTES_MAP=<attributesMap>
145+
export ID_ATTRIBUTE=<idAttribute>
146+
export TIMESTAMP_ATTRIBUTE=<timestampAttribute>
147+
export ERROR_HANDLING=<errorHandling>
148+
export SUBSCRIPTION=<subscription>
149+
export CONFIG_PROPERTIES=<configProperties>
150+
export DROP=<drop>
151+
export FILTER=<filter>
152+
export KEEP=<keep>
153+
export ONLY=<only>
154+
export PARTITION_FIELDS=<partitionFields>
155+
export TABLE_PROPERTIES=<tableProperties>
156+
export SDF_CHECKPOINT_AFTER_DURATION=30s
157+
export SDF_CHECKPOINT_AFTER_OUTPUT_BYTES=536870912
158+
159+
gcloud dataflow flex-template run "pubsub-to-iceberg-yaml-job" \
160+
--project "$PROJECT" \
161+
--region "$REGION" \
162+
--template-file-gcs-location "$TEMPLATE_SPEC_GCSPATH" \
163+
--parameters "topic=$TOPIC" \
164+
--parameters "format=$FORMAT" \
165+
--parameters "schema=$SCHEMA" \
166+
--parameters "attributes=$ATTRIBUTES" \
167+
--parameters "attributesMap=$ATTRIBUTES_MAP" \
168+
--parameters "idAttribute=$ID_ATTRIBUTE" \
169+
--parameters "timestampAttribute=$TIMESTAMP_ATTRIBUTE" \
170+
--parameters "errorHandling=$ERROR_HANDLING" \
171+
--parameters "subscription=$SUBSCRIPTION" \
172+
--parameters "table=$TABLE" \
173+
--parameters "catalogName=$CATALOG_NAME" \
174+
--parameters "catalogProperties=$CATALOG_PROPERTIES" \
175+
--parameters "configProperties=$CONFIG_PROPERTIES" \
176+
--parameters "drop=$DROP" \
177+
--parameters "filter=$FILTER" \
178+
--parameters "keep=$KEEP" \
179+
--parameters "only=$ONLY" \
180+
--parameters "partitionFields=$PARTITION_FIELDS" \
181+
--parameters "tableProperties=$TABLE_PROPERTIES" \
182+
--parameters "triggeringFrequencySeconds=$TRIGGERING_FREQUENCY_SECONDS" \
183+
--parameters "sdfCheckpointAfterDuration=$SDF_CHECKPOINT_AFTER_DURATION" \
184+
--parameters "sdfCheckpointAfterOutputBytes=$SDF_CHECKPOINT_AFTER_OUTPUT_BYTES"
185+
```
186+
187+
For more information about the command, please check:
188+
https://cloud.google.com/sdk/gcloud/reference/dataflow/flex-template/run
189+
190+
191+
**Using the plugin**:
192+
193+
Instead of just generating the template in the folder, it is possible to stage
194+
and run the template in a single command. This may be useful for testing when
195+
changing the templates.
196+
197+
```shell
198+
export PROJECT=<my-project>
199+
export BUCKET_NAME=<bucket-name>
200+
export REGION=us-central1
201+
202+
### Required
203+
export TOPIC=<topic>
204+
export FORMAT=<format>
205+
export SCHEMA=<schema>
206+
export TABLE=<table>
207+
export CATALOG_NAME=<catalogName>
208+
export CATALOG_PROPERTIES=<catalogProperties>
209+
export TRIGGERING_FREQUENCY_SECONDS=<triggeringFrequencySeconds>
210+
211+
### Optional
212+
export ATTRIBUTES=<attributes>
213+
export ATTRIBUTES_MAP=<attributesMap>
214+
export ID_ATTRIBUTE=<idAttribute>
215+
export TIMESTAMP_ATTRIBUTE=<timestampAttribute>
216+
export ERROR_HANDLING=<errorHandling>
217+
export SUBSCRIPTION=<subscription>
218+
export CONFIG_PROPERTIES=<configProperties>
219+
export DROP=<drop>
220+
export FILTER=<filter>
221+
export KEEP=<keep>
222+
export ONLY=<only>
223+
export PARTITION_FIELDS=<partitionFields>
224+
export TABLE_PROPERTIES=<tableProperties>
225+
export SDF_CHECKPOINT_AFTER_DURATION=30s
226+
export SDF_CHECKPOINT_AFTER_OUTPUT_BYTES=536870912
227+
228+
mvn clean package -PtemplatesRun \
229+
-DskipTests \
230+
-DprojectId="$PROJECT" \
231+
-DbucketName="$BUCKET_NAME" \
232+
-Dregion="$REGION" \
233+
-DjobName="pubsub-to-iceberg-yaml-job" \
234+
-DtemplateName="Pubsub_To_Iceberg_Yaml" \
235+
-Dparameters="topic=$TOPIC,format=$FORMAT,schema=$SCHEMA,attributes=$ATTRIBUTES,attributesMap=$ATTRIBUTES_MAP,idAttribute=$ID_ATTRIBUTE,timestampAttribute=$TIMESTAMP_ATTRIBUTE,errorHandling=$ERROR_HANDLING,subscription=$SUBSCRIPTION,table=$TABLE,catalogName=$CATALOG_NAME,catalogProperties=$CATALOG_PROPERTIES,configProperties=$CONFIG_PROPERTIES,drop=$DROP,filter=$FILTER,keep=$KEEP,only=$ONLY,partitionFields=$PARTITION_FIELDS,tableProperties=$TABLE_PROPERTIES,triggeringFrequencySeconds=$TRIGGERING_FREQUENCY_SECONDS,sdfCheckpointAfterDuration=$SDF_CHECKPOINT_AFTER_DURATION,sdfCheckpointAfterOutputBytes=$SDF_CHECKPOINT_AFTER_OUTPUT_BYTES" \
236+
-f yaml
237+
```
238+
239+
## Terraform
240+
241+
Dataflow supports the utilization of Terraform to manage template jobs,
242+
see [dataflow_flex_template_job](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dataflow_flex_template_job).
243+
244+
Terraform modules have been generated for most templates in this repository. This includes the relevant parameters
245+
specific to the template. If available, they may be used instead of
246+
[dataflow_flex_template_job](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dataflow_flex_template_job)
247+
directly.
248+
249+
To use the autogenerated module, execute the standard
250+
[terraform workflow](https://developer.hashicorp.com/terraform/intro/core-workflow):
251+
252+
```shell
253+
cd yaml/terraform/Pubsub_To_Iceberg_Yaml
254+
terraform init
255+
terraform apply
256+
```
257+
258+
To use
259+
[dataflow_flex_template_job](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/dataflow_flex_template_job)
260+
directly:
261+
262+
```terraform
263+
provider "google-beta" {
264+
project = var.project
265+
}
266+
variable "project" {
267+
default = "<my-project>"
268+
}
269+
variable "region" {
270+
default = "us-central1"
271+
}
272+
273+
resource "google_dataflow_flex_template_job" "pubsub_to_iceberg_yaml" {
274+
275+
provider = google-beta
276+
container_spec_gcs_path = "gs://dataflow-templates-${var.region}/latest/flex/Pubsub_To_Iceberg_Yaml"
277+
name = "pubsub-to-iceberg-yaml"
278+
region = var.region
279+
parameters = {
280+
topic = "<topic>"
281+
format = "<format>"
282+
schema = "<schema>"
283+
table = "<table>"
284+
catalogName = "<catalogName>"
285+
catalogProperties = "<catalogProperties>"
286+
triggeringFrequencySeconds = "<triggeringFrequencySeconds>"
287+
# attributes = "<attributes>"
288+
# attributesMap = "<attributesMap>"
289+
# idAttribute = "<idAttribute>"
290+
# timestampAttribute = "<timestampAttribute>"
291+
# errorHandling = "<errorHandling>"
292+
# subscription = "<subscription>"
293+
# configProperties = "<configProperties>"
294+
# drop = "<drop>"
295+
# filter = "<filter>"
296+
# keep = "<keep>"
297+
# only = "<only>"
298+
# partitionFields = "<partitionFields>"
299+
# tableProperties = "<tableProperties>"
300+
# sdfCheckpointAfterDuration = "30s"
301+
# sdfCheckpointAfterOutputBytes = "536870912"
302+
}
303+
}
304+
```

0 commit comments

Comments
 (0)