hudi-agent commented on code in PR #19272: URL: https://github.com/apache/hudi/pull/19272#discussion_r3729276815
########## website/blog/2026-08-05-migrating-from-apache-iceberg-to-hudi.md: ########## @@ -0,0 +1,139 @@ +--- +title: "Migrating from Apache Iceberg to Apache Hudi" +excerpt: "A practical guide to adopting Apache Hudi on existing Iceberg tables — via XTable metadata translation or a one-time rewrite — while keeping every Iceberg-based reader working through reverse sync." +description: "How to migrate Iceberg tables to Apache Hudi with XTable metadata conversion or a Spark rewrite, keeping Snowflake, BigQuery and Trino Iceberg readers working." +authors: [sivabalan] +category: how-to +image: /assets/images/blog/2025-07-02-Lakehouse-Architecture-apache-hudi-and-apache-iceberg.png +tags: +- migration +- apache xtable +- apache iceberg +- guide +--- + +You can adopt Apache Hudi on an existing Apache Iceberg table either by translating its metadata with [Apache XTable](https://xtable.apache.org) — no data rewrite, since both formats store data as Parquet files — or via a one-time rewrite; and because XTable also works in the reverse direction, projecting a Hudi table back out as Iceberg, your existing Iceberg readers can keep working after the switch. That second point changes the shape of the whole exercise. "Migrating from Iceberg to Hudi" does not have to mean a hard cutover of every writer, reader, catalog entry and dashboard on the same weekend. It can mean moving just the *write path* to Hudi — to get record-level indexes, streaming upserts and built-in table services — while every Snowflake, BigQuery or Trino consumer that speaks Iceberg continues reading the same table, unaware anything changed underneath. + +This guide walks through both migration options with working configuration and code, the cutover sequence that de-risks the switch, an honest look at which Iceberg features do not map one-to-one, and a validation checklist with a rollback story. It is the Iceberg-side companion to our guides on [using Hudi with Apache Iceberg via XTable](/blog/2026/07/28/using-hudi-with-apache-iceberg-via-xtable) and [migrating from Delta Lake to Hudi](/blog/2026/08/04/migrating-from-delta-lake-to-hudi). + +## Why Teams Move from Iceberg to Hudi + +The migrations we see are almost always driven by the write side. Apache Iceberg has broad catalog and engine support, and for append-mostly batch analytics it serves many teams fine. The friction shows up when workloads become mutation-heavy or latency-sensitive: + +- **Record-level indexes for fast upserts.** Hudi maintains a [multi-modal indexing subsystem](/docs/indexes) — record-level index, bloom filters, expression and secondary indexes — that maps record keys to file groups. An upsert locates exactly the files it must touch instead of planning a join or scan against the target to find matching rows. For CDC pipelines applying millions of scattered updates, this is routinely the difference between minutes and hours. +- **Merge-on-Read designed for streaming ingest.** Hudi's MOR tables absorb updates as compact log files merged on read, so writers sustain high-frequency commits — minute-level or faster from Kafka, Flink or Spark Structured Streaming — without churning out rewritten Parquet on every batch. +- **Built-in table services.** Compaction, clustering, cleaning and file sizing are part of the Hudi runtime and run inline or asynchronously without external orchestration. With Iceberg, that maintenance is left to engines, scheduled Spark procedures or a vendor service — someone has to own it. +- **CDC-grade change streams.** Hudi tables serve [incremental queries](/docs/sql_queries#incremental-query): give me exactly the records that changed between two points on the timeline, including before/after images in CDC mode. Downstream pipelines chain off tables directly instead of re-reading snapshots and diffing. + +The gap is measurable. In benchmarks run with the open-source [LakeLoader](https://github.com/onehouseinc/lake-loader) framework — Spark 3.5, Hudi 1.1.1, Iceberg 1.10.0, on S3 — we observed roughly 4× lower incremental write latency for Hudi on a 10 TB partitioned fact table with skewed updates, and about 8× lower steady-state latency on Merge-on-Read tables taking sparse, column-level updates, with Hudi's record-level index sidestepping the full-table-scan merge joins that dominate the alternative write path. The workload definitions are format-agnostic and repeatable, so you can rerun the comparison on your own update patterns before deciding. + +The point is not that Iceberg cannot handle these workloads — it is that Hudi's write path, indexing and self-managing services are built for mutable, streaming-oriented workloads. If that describes the tables you are running, here is how to move them. + +## Migrate the Writer, Keep the Readers + +The biggest source of migration risk is rarely the table itself — it is the long tail of consumers. A warehouse reading through an Iceberg catalog, BI dashboards, other teams' Spark jobs. A migration plan that requires all of them to change on cutover day is fragile enough that most teams never start. + +The two-way XTable pattern removes that requirement: + +1. **Writers move to Hudi.** Your ingestion pipeline gains Hudi's upsert indexes, MOR streaming writes and table services. +2. **XTable continuously projects the Hudi table back out as Iceberg.** After each Hudi commit (or on a schedule), XTable translates the Hudi timeline into Iceberg metadata over the *same* Parquet data files, and its catalog sync can keep Hive Metastore or AWS Glue entries current. +3. **Readers keep reading Iceberg.** Snowflake, BigQuery, Trino Iceberg catalogs, anything else that only speaks Iceberg — all keep working. They can each move to native Hudi reads later, on their own schedule, or never. + +Because the data files are shared and only lightweight metadata is generated, the reverse projection is cheap and stays fresh. The migration decision decomposes: the writer cutover is one contained change, and every reader migration becomes optional and independent. We cover the reader-side mechanics in depth in the [Hudi + Iceberg interoperability guide](/blog/2026/07/28/using-hudi-with-apache-iceberg-via-xtable); the rest of this post focuses on getting the table and the writer onto Hudi. + +## Option A: Convert Iceberg Metadata to Hudi with Apache XTable + +XTable (incubating) translates table metadata between Hudi, Iceberg and Delta Lake in any direction. Pointed at an Iceberg table, it reads the Iceberg snapshot and writes Hudi metadata — a `.hoodie` timeline with schema, commit history, partition and column statistics — referencing the existing Parquet files in place. Nothing is copied or rewritten. + +Grab the XTable bundled jar (build from [source](https://github.com/apache/incubator-xtable) or download from GitHub packages) and create a config: + +```yaml md title="iceberg_to_hudi.yaml" +sourceFormat: ICEBERG +targetFormats: + - HUDI +datasets: + - + tableBasePath: s3://warehouse/orders + tableDataPath: s3://warehouse/orders/data + tableName: orders + partitionSpec: order_date:VALUE Review Comment: 🤖 Is `partitionSpec` needed for an Iceberg source? In XTable, partition information for Delta and Iceberg sources is generally derived from the source table's own metadata, and `partitionSpec` is documented as required mainly for Hudi source tables — the in-repo `syncing_xtable.md` example only shows it under a `sourceFormat: HUDI` config. Including it here for `sourceFormat: ICEBERG` may be unnecessary and could confuse readers who copy the config verbatim. It might help to verify against the XTable docs and either drop it or add a note that it's optional for Iceberg sources. <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.</i></sub> ########## website/blog/2026-08-04-migrating-from-delta-lake-to-hudi.md: ########## @@ -0,0 +1,148 @@ +--- +title: "Migrating from Delta Lake to Apache Hudi" +excerpt: "A practical guide to moving Delta Lake tables to Apache Hudi — metadata-only conversion with Apache XTable, a one-time Spark rewrite, validation, and rollback." +description: "How to migrate Delta Lake tables to Apache Hudi: XTable metadata translation with no data rewrite, or a one-time Spark bulk insert — plus validation and rollback." +authors: [sivabalan] +category: how-to +image: /assets/images/blog/2023-08-09-Lakehouse-Trifecta-Delta-Lake-Apache-Iceberg-and-Apache-Hudi.png +tags: +- migration +- apache xtable +- delta lake +- guide +--- + +You can migrate a Delta Lake table to Apache Hudi either by translating its metadata with [Apache XTable](https://xtable.apache.org) — no data rewrite required, since both formats store data as Apache Parquet — or by rewriting the table once with a Spark `bulk_insert`; many teams start by running both formats side by side via XTable and cut writers over only after validating the Hudi side. + +That single sentence is the whole decision in miniature, but a production migration deserves more care than a summary. This guide walks through why teams make this move, the three migration strategies and when each fits, the exact XTable and Spark commands involved, the Delta-specific features that need per-table attention, and how to validate and — if necessary — roll back. Throughout, the framing to keep in mind is that both Delta Lake and Hudi are [open table formats](/blog/2026/07/14/what-is-an-open-table-format): metadata layers over Parquet files. That shared foundation is precisely what makes a metadata-level migration possible. + +## Why Teams Move from Delta Lake to Hudi + +Delta Lake takes a deliberately simple approach on disk and is closely integrated with Spark. Teams that migrate to Hudi are usually not fleeing Delta so much as reaching for write-side machinery that Hudi builds in: + +- **Record-level indexing.** Hudi maintains a [multi-modal indexing subsystem](/docs/indexes) — record-level indexes, bloom filters, column statistics, expression indexes — inside an internal metadata table. For update-heavy workloads such as CDC ingestion, an index that maps record keys to file groups means the writer can locate the files affected by an update without scanning or joining against the whole table. +- **Streaming-first Merge-on-Read design.** Hudi's MOR table type absorbs updates into compact log files that are compacted asynchronously, decoupling write latency from file rewrite cost. Workloads that need minute-level freshness under continuous upserts tend to be the strongest motivation for the move. +- **Built-in table services.** Compaction, clustering, cleaning, and indexing ship with the project and run inline or asynchronously, without a separate orchestration layer or a commercial service to keep tables healthy. +- **Built-in ingestion tooling.** Hudi Streamer provides a self-contained ingestion utility with sources for Kafka, DFS, and JDBC, checkpoint management, transformations, and catalog syncing. + +These differences are measurable, not just architectural. In benchmarks run with the open-source [LakeLoader](https://github.com/onehouseinc/lake-loader) framework — Spark 3.5, Hudi 1.1.1, Delta Lake 3.3.2, on S3 — we observed roughly 6× lower incremental write latency for Hudi on a 10 TB partitioned fact table with skewed updates, and about 5× lower steady-state latency on Merge-on-Read tables taking sparse, column-level updates. The workload definitions are format-agnostic and repeatable, so you can rerun the comparison against your own update patterns before committing to a migration. + +None of this is a knock on Delta — if your workload is mostly appends with occasional merges, run entirely on Spark, and you are happy with your current operational model, you may not need to migrate at all. The rest of this guide assumes you have concluded the write-side capabilities matter for your workload. + +## Understand the Three Migration Options + +| | A. XTable metadata translation | B. Full rewrite (Spark bulk insert) | C. Incremental dual-write cutover | +|---|---|---|---| +| **Data movement** | None — metadata only | Full copy of the table | Full copy, spread over time | +| **Downtime for writers** | None during sync; brief pause at cutover | Pause writes during the rewrite (or reconcile a delta) | None — new writer runs in parallel | +| **Resulting table** | Hudi metadata over existing Parquet files | Native Hudi table, freshly laid out | Native Hudi table | +| **Lets you re-key / re-partition / resize files** | No — inherits Delta's layout | Yes | Yes | +| **Reversible** | Trivially — source metadata untouched | Source table left intact until decommission | Source table left intact until decommission | +| **Best for** | Large tables, fast side-by-side evaluation, low-risk cutover | Small-to-medium tables, or when you want a clean re-layout | Very large, hot tables that cannot pause and need a new layout | + +A few rules of thumb. If the table is large and its current Parquet layout is acceptable, start with **Option A** — it costs almost nothing to try and keeps both formats readable while you evaluate. If the table is small enough that a rewrite finishes in an acceptable window, or you want to change record keys, partitioning, or file sizes as part of the move, **Option B** is simpler to reason about. **Option C** — standing up a parallel Hudi pipeline fed from the same upstream source, backfilling history, then switching consumers — is really Option B with a longer runway, and is worth the extra coordination only for tables that can neither pause nor tolerate an inherited layout. Hudi's [migration guide](/docs/migration_guide) covers additional bootstrapping modes (such as metadata-only bootstrap) that occupy a middle ground for plain Parquet sources. + +## Option A: Convert with Apache XTable + +[Apache XTable](https://xtable.apache.org) (incubating) is an open source project that translates table metadata between Delta Lake, Hudi, and Iceberg in any direction, without copying or rewriting data files. For this migration, Delta is the source and Hudi is the target. XTable reads the Delta transaction log and writes out the equivalent Hudi metadata — schema, commit history, partition information, and column statistics — alongside the existing Parquet files. (The same tool also works in the other directions; see the companion post on [using Hudi with Apache Iceberg via XTable](/blog/2026/07/28/using-hudi-with-apache-iceberg-via-xtable) for the interop angle.) + +Create a config file describing the source and target: + +```yaml +# my_config.yaml +sourceFormat: DELTA +targetFormats: + - HUDI +datasets: + - tableBasePath: s3://bucket/warehouse/orders + tableName: orders +``` + +Then run the sync with the bundled XTable jar (built from [source](https://github.com/apache/incubator-xtable) or downloaded from the project's GitHub packages): + +```shell +java -jar path/to/xtable-utilities-bundled.jar --datasetConfig my_config.yaml +``` + +When the sync completes, the table's base path contains a `.hoodie` directory with Hudi's timeline and metadata, side by side with Delta's `_delta_log`. No Parquet file was read or written — the job's runtime scales with the amount of metadata (number of files and commits), not with data volume. The same directory is now readable as a Delta table *and* as a Hudi table. + +Two operational notes, faithful to the [XTable documentation](https://xtable.apache.org/docs/how-to): + +- **Syncs are repeatable and incremental.** XTable supports incremental sync (translating only new commits since the last run) with a fallback to full sync, so you can run it on a schedule — or after each Delta commit — to keep the Hudi metadata current while the Delta writer keeps running. +- **Catalog registration is a separate step.** XTable produces metadata in storage; to query the table as Hudi from your engines, register it in your catalog (Hive Metastore, AWS Glue) using Hudi's catalog sync tools or XTable's own catalog sync support. Hudi's [XTable page](/docs/syncing_xtable) shows the reverse direction and the Hudi Streamer integration. + +## The Catch: Converted vs Native Tables + +Here is the honest fine print. A converted table is *readable* as a Hudi table — snapshot queries, engine integrations, and catalog syncing all work. But most of the reasons you are migrating live on the **write path**: record-level indexes are built and maintained by Hudi writers; streaming upserts, MOR log files, and table services all require Hudi to be the one committing to the table. XTable gives you a Hudi-readable table; it does not retroactively give your Delta writer Hudi's write-side machinery. + +So a metadata conversion is the first half of the migration, not the whole thing. The second half is the writer cutover, which follows a simple sequence: + +1. **Stop the Delta writer.** Pause the job or pipeline committing to the Delta table. In-flight data can queue upstream (e.g., in Kafka) during the brief window. +2. **Run a final XTable sync.** Translate the last Delta commits so the Hudi metadata reflects the table's final Delta-written state. +3. **Start the Hudi writer.** Point your pipeline — Spark structured streaming, Hudi Streamer, or batch jobs following the [quick start guide](/docs/quick-start-guide) — at the same base path, configured with the record key, ordering field, and table type you validated beforehand. From this commit forward, Hudi owns the table and begins building its indexes and running table services on new data. Review Comment: 🤖 This step could clarify what actually happens when a Hudi writer starts on top of XTable-converted metadata. The pre-existing Parquet files were written by Delta and don't carry Hudi's record-metadata columns (`_hoodie_record_key`, `_hoodie_commit_time`, …), and those historical records aren't present in Hudi's record index. So an upsert whose key already exists in the converted data can be treated as an insert (creating a duplicate) rather than being merged. The Iceberg companion post handles exactly this by recommending Hudi's bootstrap mechanism or a full rewrite instead of "writing directly on top of converted metadata" — it would help to carry the same caveat here. @yihua could you confirm the supported cutover path (bootstrap vs. writing directly onto converted metadata) for making historical records upsertable without duplicates? <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.</i></sub> ########## website/blog/2026-08-04-migrating-from-delta-lake-to-hudi.md: ########## @@ -0,0 +1,148 @@ +--- +title: "Migrating from Delta Lake to Apache Hudi" +excerpt: "A practical guide to moving Delta Lake tables to Apache Hudi — metadata-only conversion with Apache XTable, a one-time Spark rewrite, validation, and rollback." +description: "How to migrate Delta Lake tables to Apache Hudi: XTable metadata translation with no data rewrite, or a one-time Spark bulk insert — plus validation and rollback." +authors: [sivabalan] +category: how-to +image: /assets/images/blog/2023-08-09-Lakehouse-Trifecta-Delta-Lake-Apache-Iceberg-and-Apache-Hudi.png +tags: +- migration +- apache xtable +- delta lake +- guide +--- + +You can migrate a Delta Lake table to Apache Hudi either by translating its metadata with [Apache XTable](https://xtable.apache.org) — no data rewrite required, since both formats store data as Apache Parquet — or by rewriting the table once with a Spark `bulk_insert`; many teams start by running both formats side by side via XTable and cut writers over only after validating the Hudi side. + +That single sentence is the whole decision in miniature, but a production migration deserves more care than a summary. This guide walks through why teams make this move, the three migration strategies and when each fits, the exact XTable and Spark commands involved, the Delta-specific features that need per-table attention, and how to validate and — if necessary — roll back. Throughout, the framing to keep in mind is that both Delta Lake and Hudi are [open table formats](/blog/2026/07/14/what-is-an-open-table-format): metadata layers over Parquet files. That shared foundation is precisely what makes a metadata-level migration possible. + +## Why Teams Move from Delta Lake to Hudi + +Delta Lake takes a deliberately simple approach on disk and is closely integrated with Spark. Teams that migrate to Hudi are usually not fleeing Delta so much as reaching for write-side machinery that Hudi builds in: + +- **Record-level indexing.** Hudi maintains a [multi-modal indexing subsystem](/docs/indexes) — record-level indexes, bloom filters, column statistics, expression indexes — inside an internal metadata table. For update-heavy workloads such as CDC ingestion, an index that maps record keys to file groups means the writer can locate the files affected by an update without scanning or joining against the whole table. +- **Streaming-first Merge-on-Read design.** Hudi's MOR table type absorbs updates into compact log files that are compacted asynchronously, decoupling write latency from file rewrite cost. Workloads that need minute-level freshness under continuous upserts tend to be the strongest motivation for the move. +- **Built-in table services.** Compaction, clustering, cleaning, and indexing ship with the project and run inline or asynchronously, without a separate orchestration layer or a commercial service to keep tables healthy. +- **Built-in ingestion tooling.** Hudi Streamer provides a self-contained ingestion utility with sources for Kafka, DFS, and JDBC, checkpoint management, transformations, and catalog syncing. + +These differences are measurable, not just architectural. In benchmarks run with the open-source [LakeLoader](https://github.com/onehouseinc/lake-loader) framework — Spark 3.5, Hudi 1.1.1, Delta Lake 3.3.2, on S3 — we observed roughly 6× lower incremental write latency for Hudi on a 10 TB partitioned fact table with skewed updates, and about 5× lower steady-state latency on Merge-on-Read tables taking sparse, column-level updates. The workload definitions are format-agnostic and repeatable, so you can rerun the comparison against your own update patterns before committing to a migration. + +None of this is a knock on Delta — if your workload is mostly appends with occasional merges, run entirely on Spark, and you are happy with your current operational model, you may not need to migrate at all. The rest of this guide assumes you have concluded the write-side capabilities matter for your workload. + +## Understand the Three Migration Options + +| | A. XTable metadata translation | B. Full rewrite (Spark bulk insert) | C. Incremental dual-write cutover | +|---|---|---|---| +| **Data movement** | None — metadata only | Full copy of the table | Full copy, spread over time | +| **Downtime for writers** | None during sync; brief pause at cutover | Pause writes during the rewrite (or reconcile a delta) | None — new writer runs in parallel | +| **Resulting table** | Hudi metadata over existing Parquet files | Native Hudi table, freshly laid out | Native Hudi table | +| **Lets you re-key / re-partition / resize files** | No — inherits Delta's layout | Yes | Yes | +| **Reversible** | Trivially — source metadata untouched | Source table left intact until decommission | Source table left intact until decommission | +| **Best for** | Large tables, fast side-by-side evaluation, low-risk cutover | Small-to-medium tables, or when you want a clean re-layout | Very large, hot tables that cannot pause and need a new layout | + +A few rules of thumb. If the table is large and its current Parquet layout is acceptable, start with **Option A** — it costs almost nothing to try and keeps both formats readable while you evaluate. If the table is small enough that a rewrite finishes in an acceptable window, or you want to change record keys, partitioning, or file sizes as part of the move, **Option B** is simpler to reason about. **Option C** — standing up a parallel Hudi pipeline fed from the same upstream source, backfilling history, then switching consumers — is really Option B with a longer runway, and is worth the extra coordination only for tables that can neither pause nor tolerate an inherited layout. Hudi's [migration guide](/docs/migration_guide) covers additional bootstrapping modes (such as metadata-only bootstrap) that occupy a middle ground for plain Parquet sources. + +## Option A: Convert with Apache XTable + +[Apache XTable](https://xtable.apache.org) (incubating) is an open source project that translates table metadata between Delta Lake, Hudi, and Iceberg in any direction, without copying or rewriting data files. For this migration, Delta is the source and Hudi is the target. XTable reads the Delta transaction log and writes out the equivalent Hudi metadata — schema, commit history, partition information, and column statistics — alongside the existing Parquet files. (The same tool also works in the other directions; see the companion post on [using Hudi with Apache Iceberg via XTable](/blog/2026/07/28/using-hudi-with-apache-iceberg-via-xtable) for the interop angle.) + +Create a config file describing the source and target: + +```yaml +# my_config.yaml +sourceFormat: DELTA +targetFormats: + - HUDI +datasets: + - tableBasePath: s3://bucket/warehouse/orders + tableName: orders +``` + +Then run the sync with the bundled XTable jar (built from [source](https://github.com/apache/incubator-xtable) or downloaded from the project's GitHub packages): + +```shell +java -jar path/to/xtable-utilities-bundled.jar --datasetConfig my_config.yaml +``` + +When the sync completes, the table's base path contains a `.hoodie` directory with Hudi's timeline and metadata, side by side with Delta's `_delta_log`. No Parquet file was read or written — the job's runtime scales with the amount of metadata (number of files and commits), not with data volume. The same directory is now readable as a Delta table *and* as a Hudi table. + +Two operational notes, faithful to the [XTable documentation](https://xtable.apache.org/docs/how-to): + +- **Syncs are repeatable and incremental.** XTable supports incremental sync (translating only new commits since the last run) with a fallback to full sync, so you can run it on a schedule — or after each Delta commit — to keep the Hudi metadata current while the Delta writer keeps running. +- **Catalog registration is a separate step.** XTable produces metadata in storage; to query the table as Hudi from your engines, register it in your catalog (Hive Metastore, AWS Glue) using Hudi's catalog sync tools or XTable's own catalog sync support. Hudi's [XTable page](/docs/syncing_xtable) shows the reverse direction and the Hudi Streamer integration. + +## The Catch: Converted vs Native Tables + +Here is the honest fine print. A converted table is *readable* as a Hudi table — snapshot queries, engine integrations, and catalog syncing all work. But most of the reasons you are migrating live on the **write path**: record-level indexes are built and maintained by Hudi writers; streaming upserts, MOR log files, and table services all require Hudi to be the one committing to the table. XTable gives you a Hudi-readable table; it does not retroactively give your Delta writer Hudi's write-side machinery. + +So a metadata conversion is the first half of the migration, not the whole thing. The second half is the writer cutover, which follows a simple sequence: + +1. **Stop the Delta writer.** Pause the job or pipeline committing to the Delta table. In-flight data can queue upstream (e.g., in Kafka) during the brief window. +2. **Run a final XTable sync.** Translate the last Delta commits so the Hudi metadata reflects the table's final Delta-written state. +3. **Start the Hudi writer.** Point your pipeline — Spark structured streaming, Hudi Streamer, or batch jobs following the [quick start guide](/docs/quick-start-guide) — at the same base path, configured with the record key, ordering field, and table type you validated beforehand. From this commit forward, Hudi owns the table and begins building its indexes and running table services on new data. + +Until step 1, you can run the two formats side by side indefinitely: Delta writers keep writing, XTable keeps both metadata layers in sync, and your Hudi-native engines and pipelines read the converted table. That side-by-side period is where the de-risking happens — you validate reads, permissions, catalog integration, and downstream jobs against real data before any writer changes. + +## Option B: Full Rewrite with Spark + +If the table is modest in size, or you want to change its physical layout — different partitioning, tuned file sizes, a proper record key for upserts — a one-time rewrite is the simplest path. Read the Delta table with Spark, write it back as Hudi using `bulk_insert`, the write operation designed for exactly this initial-load case: + +```scala +// spark-shell with both Delta and Hudi bundles on the classpath +val df = spark.read.format("delta").load("s3://bucket/warehouse/orders") + +df.write.format("hudi"). Review Comment: 🤖 Since the guide leads with Merge-on-Read's streaming-upsert benefits, it might help to note that this `bulk_insert` example produces a Copy-on-Write table by default (`hoodie.datasource.write.table.type` is unset). Readers who followed the MOR motivation above and want that behavior would need to add `option("hoodie.datasource.write.table.type", "MERGE_ON_READ")`, and table type is fixed at creation. The Iceberg companion's Option B example (line 91) has the same omission. <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag quality.</i></sub> -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
