|
| 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 | +[](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