

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Hudi
<a name="emr-hudi"></a>

[Apache Hudi](https://hudi.apache.org/) 是一個開放原始碼資料管理架構，提供記錄層級的插入、更新、upsert 和刪除功能，可用於簡化增量資料處理和資料管道開發。*Upsert* 是指將記錄插入現有資料集 (如果記錄不存在)，或者更新記錄 (如果記錄已存在) 的能力。透過有效地管理資料在 Amazon S3 中的配置方式，Hudi 可讓資料以近乎即時的方式被擷取和更新。Hudi 仔細維護在資料集上執行的動作的中繼資料，以協助確保動作是不可部分完成且一致的。

Hudi 與 [Apache Spark](https://aws.amazon.com/emr/features/spark/)、[Apache Hive](https://hive.apache.org/) 和 [Presto](https://prestodb.github.io) 整合。在 Amazon EMR 發行版本 6.1.0 及更新版本中，Hudi 也與 [Trino (PrestoSQL)](https://trino.io/) 整合。

使用 Amazon EMR 發行版本 5.28.0 及更新版本時，如果已安裝 Spark、Hive、Presto 或 Flink，依預設，EMR 會安裝 Hudi 元件。您可以使用 Spark 或 Hudi DeltaStreamer 公用程式來建立或更新 Hudi 資料集。您可以使用 Hive、Spark、Presto 或 Flink 以互動的方式查詢 Hudi 資料集，或使用*增量提取*建置資料處理管道。增量提取是指僅提取在兩個動作之間變更的資料的能力。

這些功能使 Hudi 適用於下列使用案例：
+ 處理來自感應器和其他物聯網 (IoT) 裝置的串流資料，這些資料需要特定的資料插入和更新事件。
+ 在應用程式中遵守資料隱私權法規，使用者可能會選擇忘記或修改其對於資料使用方式的同意。
+ 實作[變更資料擷取 (CDC) 系統](https://en.wikipedia.org/wiki/Change_data_capture)，可讓您在一段時間內將變更套用至資料集。

以下表格列出了 Amazon EMR 7.x 系列最新版本中包含的 Hudi 版本，以及 Amazon EMR 隨 Hudi 一起安裝的元件。

如需此版本中與 Hudi 一起安裝的元件版本，請參閱[發行版本 7.12.0 元件版本。](emr-7120-release.md)


**emr-7.12.0 的 Hudi 版本資訊**  

| Amazon EMR 發行標籤 | Hudi 版本 | 與 Hudi 一起搭配安裝的元件 | 
| --- | --- | --- | 
| emr-7.12.0 | Hudi 1.0.2-amzn-1 | Not available. | 

下表列出 Amazon EMR 6.x 系列最新版本中包含的 Hudi 版本，以及 Amazon EMR 隨 Hudi 一起安裝的元件。

如需此版本中與 Hudi 一起搭配安裝的元件版本，請參閱[發行版本 6.15.0 元件版本](emr-6150-release.md)。


**emr-6.15.0 的 Hudi 版本資訊**  

| Amazon EMR 發行標籤 | Hudi 版本 | 與 Hudi 一起搭配安裝的元件 | 
| --- | --- | --- | 
| emr-6.15.0 | Hudi 0.14.0-amzn-0 | Not available. | 

**注意**  
Amazon EMR 6.8.0 版隨附 [Apache Hudi](https://hudi.apache.org/) 0.11.1；但是，Amazon EMR 6.8.0 叢集也與 Hudi 0.12.0 中的開放原始碼 `hudi-spark3.3-bundle_2.12` 相容。

下表列出 Amazon EMR 5.x 系列最新版本中包含的 Hudi 版本，以及 Amazon EMR 隨 Hudi 一起安裝的元件。

如需此版本中與 Hudi 一起安裝的元件版本，請參閱[發行版本 5.36.2 元件版本。](emr-5362-release.md)


**emr-5.36.2 的 Hudi 版本資訊**  

| Amazon EMR 發行標籤 | Hudi 版本 | 與 Hudi 一起搭配安裝的元件 | 
| --- | --- | --- | 
| emr-5.36.2 | Hudi 0.10.1-amzn-1 | Not available. | 

**Topics**
+ [Hudi 的運作方式](emr-hudi-how-it-works.md)
+ [在 Amazon EMR 上使用 Hudi 的考量與限制](emr-hudi-considerations.md)
+ [建立已安裝 Hudi 的叢集](emr-hudi-installation-and-configuration.md)
+ [使用 Hudi 資料集](emr-hudi-work-with-dataset.md)
+ [使用 Hudi CLI](emr-hudi-cli.md)
+ [Hudi 版本歷史記錄](Hudi-release-history.md)

# Hudi 的運作方式
<a name="emr-hudi-how-it-works"></a>

將 Hudi 與 Amazon EMR 搭配使用時，您可以使用 Spark Data Source API 或 Hudi DeltaStreamer 公用程式將資料寫入資料集。Hudi 將資料集組織到 `basepath` 下類似於傳統 Hive 資料表的分割目錄結構。有關資料如何配置為這些目錄中的檔案，具體情況取決於您選擇的資料集類型。您可以選擇「寫入時複製」(CoW) 或「讀取時合併」(MoR)。

無論資料集類型為何，資料集中的每個分割區都藉由其相對於 `basepath` 的 `partitionpath` 來唯一標識。在每個分割區中，記錄會分散到多個資料檔案中。如需詳細資訊，請參閱 Apache Hudi 文件中的[檔案管理](https://hudi.apache.org/docs/concepts.html#file-management)。

Hudi 中的每個動作都有一個相應的遞交，透過名為 *Instant* 的單調增加時間戳記加以識別。Hudi 會將一系列在資料集上執行的所有動作保留為時間軸。Hudi 倚賴此時間軸提供讀取器和寫入器之間的快照隔離，並可復原至前一個時間點。如需有關 Hudi 記錄的動作和動作狀態的詳細資訊，請參閱 Apache Hudi 文件中的[時間軸](https://hudi.apache.org/docs/concepts.html#timeline)。

## 了解資料集儲存類型：寫入時複製與讀取時合併
<a name="emr-hudi-data-files"></a>

當您建立 Hudi 資料集時，可以指定資料集在寫入時複製或在讀取時合併。
+ **寫入時複製 (CoW)** – 資料會以單欄式格式 (Parquet) 存放，每次更新都會在寫入期間建立新版本的檔案。CoW 是預設儲存類型。
+ **讀取時合併 (MoR)** – 資料的存放是使用單欄式 (Parquet) 和以資料行為基礎 (Avro) 格式的組合。更新會記錄到以資料列為基礎的 *delta* 檔案，並視需要壓縮以建立新版本的直欄式檔案。

使用 CoW 資料集，每次有記錄進行更新時，包含記錄的檔案就會以更新的值重寫。若使用 MoR 資料集，每次有更新時，Hudi 只會寫入已變更之記錄的資料行。MoR 更適合較少讀取，而寫入或變更較繁重的工作負載。CoW 更適合資料變更較不頻繁，而讀取作業較為繁重的工作負載。

Hudi 提供了用於存取資料的三個邏輯檢視：
+ **讀取優化檢視** – 提供來自 CoW 資料表的最新遞交資料集，以及來自 MoR 資料表的最新壓縮資料集。
+ **增量檢視** – 提供 CoW 資料集中的兩個動作之間的變更資料流，以饋送下游作業和擷取、轉換、載入 (ETL) 作業流程。
+ **即時檢視** – 透過合併直欄式和以列為基礎的檔案內嵌，提供來自 MoR 資料表的最新遞交資料。

當您查詢讀取最佳化檢視時，查詢會傳回所有壓縮的資料，但不包含最新的 delta 遞交。查詢此資料可提供良好的讀取效能，但會省略最新的資料。當您查詢即時檢視時，Hudi 會合併壓縮的資料與讀取時的 delta 遞交。最新的資料可用於查詢，但合併的運算作業負擔會使查詢效能降低。查詢壓縮資料或即時資料的能力，可讓您在查詢時選擇效能或彈性。

如需有關在儲存類型之間取捨的詳細資訊，請參閱 Apache Hudi 文件中的[儲存類型和檢視](https://hudi.apache.org/docs/concepts.html#storage-types--views)。

Hudi 會在 MoR 的 Hive 中繼存放區中建立兩個資料表：具有您指定名稱的資料表 (讀取優化檢視)，以及附加 `_rt` 的相同名稱資料表 (即時檢視)。您可以查詢這兩個資料表。

## 向您的中繼存放區註冊 Hudi 資料集
<a name="emr-hudi-hive-metastore"></a>

當您向 Hive 中繼存放區註冊 Hudi 資料表時，可以使用 Hive、Spark SQL 或 Presto 查詢 Hudi 資料表，如同您查詢其他任何資料表。此外，您可以透過設定 Hive AWS 和 Spark 使用 AWS Glue Data Catalog 作為中繼存放區，將 Hudi 與 Glue 整合。對於 MoR 資料表，Hudi 會將資料集註冊為中繼存放區中的兩個資料表：具有您指定名稱的資料表 (讀取優化檢視)，以及附加 `_rt` 的相同名稱資料表 (即時檢視)。

當您將 `HIVE_SYNC_ENABLED_OPT_KEY` 選項設定為 `"true"` 並提供其他所需的屬性以使用 Spark 建立 Hudi 資料集時，您將會向 Hive 中繼存放區註冊 Hudi 資料表。如需詳細資訊，請參閱[使用 Hudi 資料集](emr-hudi-work-with-dataset.md)。此外，您可以使用 hive\$1sync\$1tool 命令列公用程式，分別將 Hudi 資料集註冊為中繼儲存區中的資料表。

# 在 Amazon EMR 上使用 Hudi 的考量與限制
<a name="emr-hudi-considerations"></a>
+ **記錄索引鍵欄位不能為 null 或空白** – 您指定的記錄索引鍵欄位不能有 `null` 或空白值。
+ **結構描述預設在 upsert 和插入時更新** – 提供了一個介面，`HoodieRecordPayload` 確定輸入 DataFrame 和現有 Hudi 資料集如何合併以產生一個新的、更新的資料集。Hudi 提供此類的預設實作 `OverwriteWithLatestAvroPayload`，它會覆寫現有記錄，並更新輸入 DataFrame 中指定的結構描述。若要自訂此邏輯以實作合併和部分更新，您可以使用 `DataSourceWriteOptions.PAYLOAD_CLASS_OPT_KEY` 參數提供 `HoodieRecordPayload` 界面的實作。
+ **刪除需要結構描述** – 刪除時，您必須指定記錄索引鍵、分割區索引鍵，以及預先組合索引鍵欄位。其他欄位可以為 `null` 或空白，但需要完整的結構描述。
+ **MoR 資料表限制** – MoR 資料表不支援儲存點。您可以使用 Spark SQL、Presto 或 Hive 中的讀取優化檢視或即時檢視 (`tableName_rt`) 查詢 MoR 資料表。使用讀取優化的檢視僅公開基本檔案資料，而不公開基本資料和日誌資料的合併檢視。
+ **Hive**
  + 對於 Hive 中繼存放區中的註冊資料表，Hudi 會預期 Hive Thrift 伺服器執行於預設連接埠 `10000`。如果您以自訂連接埠覆寫此連接埠，請傳遞下列範例所示的 `HIVE_URL_OPT_KEY` 選項。

    ```
    .option(DataSourceWriteOptions.HIVE_URL_OPT_KEY, "jdbc:hive2://localhost:override-port-number
    ```
  + Spark 中的 `timestamp` 資料類型被註冊為 Hive 中的 `long` 資料類型，而非 Hive 的 `timestamp` 類型。
+ **Presto**
  + Presto 不支援在 0.6.0 以下的 Hudi 版本中讀取 MoR 即時資料表。
  + Presto 僅支援快照查詢。
  + 若要讓 Presto 正確解譯 Hudi 資料集欄位，請將 `hive.parquet_use_column_names` 值設定為 `true`。
    + 若要設定工作階段的值，請在 Presto Shell 中執行下列命令：

      ```
      set session hive.parquet_use_column_names=true
      ```
    + 若要在叢集層級設定值，請使用 `presto-connector-hive` 組態分類將 `hive.parquet.use_column_names` 設定為 `true`，如下列範例所示。如需詳細資訊，請參閱[設定應用程式](emr-configure-apps.md)。

      ```
      [
        {
          "Classification": "presto-connector-hive",
          "Properties": {
            "hive.parquet.use-column-names": "true"
          }
        }
      ]
      ```
+ **HBase 索引**
  + 用於*建置* Hudi 的 HBase 版本可能與 EMR 版本指南中列出的版本不同。若要提取 Spark 工作階段的正確依存項目，請執行下列命令。

    ```
    spark-shell \
    --jars /usr/lib/spark/external/lib/spark-avro.jar,/usr/lib/hudi/cli/lib/*.jar \
    --conf "spark.serializer=org.apache.spark.serializer.KryoSerializer" \
    --conf "spark.sql.hive.convertMetastoreParquet=false"
    ```
+ **最佳效能的設定** – 對於 EMR 7.3\$1/Hudi 0.15\$1，建議客戶設定此組態以減少 Kryo 序列化額外負荷：

  ```
  --conf 'spark.kryo.registrator=org.apache.spark.HoodieKryoRegistrar'
  ```
**注意**  
如果您在 EMR Serverless 上使用精細存取控制 (FGAC)，則不需要此組態，因為使用者必須使用 JavaSerializer 而非 KryoSerializer。

# 建立已安裝 Hudi 的叢集
<a name="emr-hudi-installation-and-configuration"></a>

使用 Amazon EMR 發行版本 5.28.0 及更新版本時，如果已安裝 Spark、Hive 或 Presto，依預設，Amazon EMR 會安裝 Hudi 元件。若要在 Amazon EMR 上使用 Hudi，請建立已安裝下列一或多個應用程式的叢集：
+ Hadoop
+ Hive
+ Spark
+ Presto
+ Flink

您可以使用 AWS 管理主控台、 AWS CLI或 Amazon EMR API 建立叢集。

## 使用 建立具有 Hudi 的叢集 AWS 管理主控台
<a name="emr-hudi-create-cluster-console"></a>

1. 導覽至新的 Amazon EMR 主控台，然後從側邊導覽選取**切換至舊主控台**。如需有關切換至舊主控台時預期情況的詳細資訊，請參閱[使用舊主控台](https://docs.aws.amazon.com/emr/latest/ManagementGuide/whats-new-in-console.html#console-opt-in)。

1. 選擇 **Create cluster (建立叢集)**，然後選擇 **Go to advanced options (前往進階選項)**。

1. 在「軟體組態」下，對於**發行版本**，選擇 **emr-5.28.0** 或更新版本，然後選擇 **Hadoop**、**Hive**、**Spark**、**Presto** 和 **Tez** 以及叢集需要的其他應用程式。

1. 視您的應用程式需要設定其他選項，然後選擇 **Next (下一步)**。

1. 視需要設定 **Hardware (硬體)** 和 **General cluster settings (一般叢集設定)** 選項。

1. 對於 **Security Options (安全性選項)**，我們建議您選取 **EC2 key pair (EC2 金鑰對)**，以便使用 SSH 連線到主節點命令列。這可讓您執行本指南中描述的 Spark Shell 命令、Hive CLI 命令和 Hudi CLI 命令。

1. 視需要設定其他安全選項，然後選擇 **Create cluster (建立叢集)**。

# 使用 Hudi 資料集
<a name="emr-hudi-work-with-dataset"></a>

Hudi 支援透過 Spark 插入、更新和刪除 Hudi 資料集中的資料。如需詳細資訊，請參閱 Apache Hudi 文件中的[寫入 Hudi 資料表](https://hudi.apache.org/docs/writing_data.html)。

下列範例示範如何啟動互動式 Spark Shell、使用 Spark 提交，或透過 Amazon EMR Notebooks 在 Amazon EMR 上使用 Hudi。您也可以使用 Hudi DeltaStreamer 公用程式或其他工具來寫入資料集。本節中的範例示範使用 Spark shell 來處理資料集，同時以預設的 `hadoop` 使用者身分使用 SSH 連接到主節點。

## 使用 Amazon EMR 6.7 及更新版本啟動 Spark Shell
<a name="hudi-datasets-67"></a>

在使用 Amazon EMR 6.7.0 或更早版本執行 `spark-shell`、`spark-submit` 或 `spark-sql` 時，請傳遞下列命令。

**注意**  
Amazon EMR 6.7.0 使用 [Apache Hudi](https://hudi.apache.org/) 0.11.0-amzn-0，相比之前的 Hudi 版本有顯著改進。如需詳細資訊，請參閱 [Apache Hudi 0.11.0 遷移指南](https://hudi.apache.org/releases/release-0.11.0/#migration-guide)。此標籤上的範例反映了這些變更。

**在主節點上開啟 Spark Shell**

1. 使用 SSH 連接至主節點。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[使用 SSH 連接至主節點](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)。

1. 輸入以下命令啟動 Spark shell。若要使用 PySpark Shell，請將 *spark-shell* 取代為 *pyspark*。

   ```
   spark-shell --jars /usr/lib/hudi/hudi-spark-bundle.jar \
   --conf "spark.serializer=org.apache.spark.serializer.KryoSerializer" \    
   --conf "spark.sql.catalog.spark_catalog=org.apache.spark.sql.hudi.catalog.HoodieCatalog"  \
   --conf "spark.sql.extensions=org.apache.spark.sql.hudi.HoodieSparkSessionExtension"
   ```

## 使用 Amazon EMR 6.6 及更早版本啟動 Spark Shell
<a name="hudi-datasets-67"></a>

在使用 Amazon EMR 6.6.x 或更早版本執行 `spark-shell`、`spark-submit` 或 `spark-sql` 時，請傳遞下列命令。

**注意**  
Amazon EMR 6.2 和 5.31 及更新版本 (Hudi 0.6.x 及更新版本) 可以從組態中省略 `spark-avro.jar`。
Amazon EMR 6.5 和 5.35 及更新版本 (Hudi 0.9.x 及更新版本) 可以從組態中省略 `spark.sql.hive.convertMetastoreParquet=false`。
Amazon EMR 6.6 和 5.36 及更新版本 (Hudi 0.10.x 及更新版本) 必須包含 `HoodieSparkSessionExtension` 組態，如[版本：0.10.0 Spark 指南](https://hudi.apache.org/docs/0.10.0/quick-start-guide/)中所述：  

  ```
  --conf  "spark.sql.extensions=org.apache.spark.sql.hudi.HoodieSparkSessionExtension" \
  ```

**在主節點上開啟 Spark Shell**

1. 使用 SSH 連接至主節點。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[使用 SSH 連接至主節點](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)。

1. 輸入以下命令啟動 Spark shell。若要使用 PySpark Shell，請將 *spark-shell* 取代為 *pyspark*。

   ```
   spark-shell \
   --conf "spark.serializer=org.apache.spark.serializer.KryoSerializer" \
   --conf "spark.sql.hive.convertMetastoreParquet=false" \
   --jars /usr/lib/hudi/hudi-spark-bundle.jar,/usr/lib/spark/external/lib/spark-avro.jar
   ```

## 將 Hudi 與使用 Amazon EMR 6.7 及更新版本的 Amazon EMR Notebooks 搭配使用
<a name="hudi-datasets-notebooks"></a>

若要將 Hudi 與 Amazon EMR Notebooks 搭配使用，您必須先將 Hudi jar 檔案從本機檔案系統複製到筆記本叢集主節點上的 HDFS。然後，使用筆記本編輯器來設定 EMR 筆記本以使用 Hudi。

**將 Hudi 與 Amazon EMR Notebooks 搭配使用**

1. 為 Amazon EMR Notebooks 建立和啟動叢集。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[為筆記本建立 Amazon EMR 叢集](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-managed-notebooks-cluster.html)。

1. 使用 SSH 連接到叢集的主節點，然後將 jar 檔案從本機檔案系統複製到 HDFS，如以下範例所示。在此範例中，我們在 HDFS 中建立目錄以便清楚管理檔案。如有需要，您可以在 HDFS 中選擇自己的目的地。

   ```
   hdfs dfs -mkdir -p /apps/hudi/lib
   ```

   ```
   hdfs dfs -copyFromLocal /usr/lib/hudi/hudi-spark-bundle.jar /apps/hudi/lib/hudi-spark-bundle.jar
   ```

1. 開啟筆記本編輯器，輸入下列範例中的程式碼，然後執行程式碼。

   ```
   %%configure
   { "conf": {
               "spark.jars":"hdfs:///apps/hudi/lib/hudi-spark-bundle.jar",
               "spark.serializer":"org.apache.spark.serializer.KryoSerializer",
               "spark.sql.catalog.spark_catalog": "org.apache.spark.sql.hudi.catalog.HoodieCatalog",
               "spark.sql.extensions":"org.apache.spark.sql.hudi.HoodieSparkSessionExtension"
             }}
   ```

## 將 Hudi 與使用 Amazon EMR 6.6 及更早版本的 Amazon EMR Notebooks 搭配使用
<a name="hudi-datasets-notebooks-66"></a>

若要將 Hudi 與 Amazon EMR Notebooks 搭配使用，您必須先將 Hudi jar 檔案從本機檔案系統複製到筆記本叢集主節點上的 HDFS。然後，使用筆記本編輯器來設定 EMR 筆記本以使用 Hudi。

**將 Hudi 與 Amazon EMR Notebooks 搭配使用**

1. 為 Amazon EMR Notebooks 建立和啟動叢集。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[為筆記本建立 Amazon EMR 叢集](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-managed-notebooks-cluster.html)。

1. 使用 SSH 連接到叢集的主節點，然後將 jar 檔案從本機檔案系統複製到 HDFS，如以下範例所示。在此範例中，我們在 HDFS 中建立目錄以便清楚管理檔案。如有需要，您可以在 HDFS 中選擇自己的目的地。

   ```
   hdfs dfs -mkdir -p /apps/hudi/lib
   ```

   ```
   hdfs dfs -copyFromLocal /usr/lib/hudi/hudi-spark-bundle.jar /apps/hudi/lib/hudi-spark-bundle.jar
   ```

   ```
   hdfs dfs -copyFromLocal /usr/lib/spark/external/lib/spark-avro.jar /apps/hudi/lib/spark-avro.jar
   ```

1. 開啟筆記本編輯器，輸入下列範例中的程式碼，然後執行程式碼。

   ```
   { "conf": {
               "spark.jars":"hdfs:///apps/hudi/lib/hudi-spark-bundle.jar,hdfs:///apps/hudi/lib/spark-avro.jar",
               "spark.serializer":"org.apache.spark.serializer.KryoSerializer",
               "spark.sql.hive.convertMetastoreParquet":"false"
             }}
   ```

## 初始化 Hudi 的 Spark 工作階段
<a name="emr-hudi-initialize-session"></a>

使用 Scala 時，您必須在 Spark 工作階段中匯入下列類別。這需要在每個 Spark 工作階段都各自完成一次。

```
import org.apache.spark.sql.SaveMode
import org.apache.spark.sql.functions._
import org.apache.hudi.DataSourceWriteOptions
import org.apache.hudi.DataSourceReadOptions
import org.apache.hudi.config.HoodieWriteConfig
import org.apache.hudi.hive.MultiPartKeysValueExtractor
import org.apache.hudi.hive.HiveSyncConfig
import org.apache.hudi.sync.common.HoodieSyncConfig
```

## 寫入 Hudi 資料集
<a name="emr-hudi-dataframe"></a>

下列範例顯示如何建立 DataFrame 並將其寫入為 Hudi 資料集。

**注意**  
若要將程式碼範例貼到 Spark shell 中，請在提示字元中輸入 **:paste**、貼上範例，然後按 **CTRL** \$1 **D**。

每次將 DataFrame 寫入至 Hudi 資料集時，都必須指定 `DataSourceWriteOptions`。這些選項有許多在各個寫入操作之間可能是相同的。以下範例會使用 `hudiOptions` 變數指定常用選項，後續範例會使用這些變數。

### 將 Scala 與 Amazon EMR 6.7 及更新版本搭配使用進行寫入
<a name="scala-examples-67"></a>

**注意**  
Amazon EMR 6.7.0 使用 [Apache Hudi](https://hudi.apache.org/) 0.11.0-amzn-0，相比之前的 Hudi 版本有顯著改進。如需詳細資訊，請參閱 [Apache Hudi 0.11.0 遷移指南](https://hudi.apache.org/releases/release-0.11.0/#migration-guide)。此標籤上的範例反映了這些變更。

```
// Create a DataFrame
val inputDF = Seq(
 ("100", "2015-01-01", "2015-01-01T13:51:39.340396Z"),
 ("101", "2015-01-01", "2015-01-01T12:14:58.597216Z"),
 ("102", "2015-01-01", "2015-01-01T13:51:40.417052Z"),
 ("103", "2015-01-01", "2015-01-01T13:51:40.519832Z"),
 ("104", "2015-01-02", "2015-01-01T12:15:00.512679Z"),
 ("105", "2015-01-02", "2015-01-01T13:51:42.248818Z")
 ).toDF("id", "creation_date", "last_update_time")

//Specify common DataSourceWriteOptions in the single hudiOptions variable 
val hudiOptions = Map[String,String](
  HoodieWriteConfig.TBL_NAME.key -> "tableName",
  DataSourceWriteOptions.TABLE_TYPE.key -> "COPY_ON_WRITE", 
  DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY -> "id",
  DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY -> "creation_date",
  DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY -> "last_update_time",
  DataSourceWriteOptions.HIVE_SYNC_ENABLED_OPT_KEY -> "true",
  DataSourceWriteOptions.HIVE_TABLE_OPT_KEY -> "tableName",
  DataSourceWriteOptions.HIVE_PARTITION_FIELDS_OPT_KEY -> "creation_date",
  HoodieSyncConfig.META_SYNC_PARTITION_EXTRACTOR_CLASS.key -> "org.apache.hudi.hive.MultiPartKeysValueExtractor",
  HoodieSyncConfig.META_SYNC_ENABLED.key -> "true",
  HiveSyncConfig.HIVE_SYNC_MODE.key -> "hms",
  HoodieSyncConfig.META_SYNC_TABLE_NAME.key -> "tableName",
  HoodieSyncConfig.META_SYNC_PARTITION_FIELDS.key -> "creation_date"
)

// Write the DataFrame as a Hudi dataset
(inputDF.write
    .format("hudi")
    .options(hudiOptions)
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY,"insert")
    .mode(SaveMode.Overwrite)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 將 Scala 與 Amazon EMR 6.6 及更早版本搭配使用進行寫入
<a name="scala-examples-66"></a>

```
// Create a DataFrame
val inputDF = Seq(
 ("100", "2015-01-01", "2015-01-01T13:51:39.340396Z"),
 ("101", "2015-01-01", "2015-01-01T12:14:58.597216Z"),
 ("102", "2015-01-01", "2015-01-01T13:51:40.417052Z"),
 ("103", "2015-01-01", "2015-01-01T13:51:40.519832Z"),
 ("104", "2015-01-02", "2015-01-01T12:15:00.512679Z"),
 ("105", "2015-01-02", "2015-01-01T13:51:42.248818Z")
 ).toDF("id", "creation_date", "last_update_time")

//Specify common DataSourceWriteOptions in the single hudiOptions variable 
val hudiOptions = Map[String,String](
  HoodieWriteConfig.TABLE_NAME -> "tableName",
  DataSourceWriteOptions.TABLE_TYPE_OPT_KEY -> "COPY_ON_WRITE", 
  DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY -> "id",
  DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY -> "creation_date",
  DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY -> "last_update_time",
  DataSourceWriteOptions.HIVE_SYNC_ENABLED_OPT_KEY -> "true",
  DataSourceWriteOptions.HIVE_TABLE_OPT_KEY -> "tableName",
  DataSourceWriteOptions.HIVE_PARTITION_FIELDS_OPT_KEY -> "creation_date",
  DataSourceWriteOptions.HIVE_PARTITION_EXTRACTOR_CLASS_OPT_KEY -> classOf[MultiPartKeysValueExtractor].getName
)

// Write the DataFrame as a Hudi dataset
(inputDF.write
    .format("org.apache.hudi")
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY, DataSourceWriteOptions.INSERT_OPERATION_OPT_VAL)
    .options(hudiOptions)
    .mode(SaveMode.Overwrite)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 使用 PySpark 進行寫入
<a name="pyspark-examples"></a>

```
# Create a DataFrame
inputDF = spark.createDataFrame(
    [
        ("100", "2015-01-01", "2015-01-01T13:51:39.340396Z"),
        ("101", "2015-01-01", "2015-01-01T12:14:58.597216Z"),
        ("102", "2015-01-01", "2015-01-01T13:51:40.417052Z"),
        ("103", "2015-01-01", "2015-01-01T13:51:40.519832Z"),
        ("104", "2015-01-02", "2015-01-01T12:15:00.512679Z"),
        ("105", "2015-01-02", "2015-01-01T13:51:42.248818Z"),
    ],
    ["id", "creation_date", "last_update_time"]
)

# Specify common DataSourceWriteOptions in the single hudiOptions variable
hudiOptions = {
'hoodie.table.name': 'tableName',
'hoodie.datasource.write.recordkey.field': 'id',
'hoodie.datasource.write.partitionpath.field': 'creation_date',
'hoodie.datasource.write.precombine.field': 'last_update_time',
'hoodie.datasource.hive_sync.enable': 'true',
'hoodie.datasource.hive_sync.table': 'tableName',
'hoodie.datasource.hive_sync.partition_fields': 'creation_date',
'hoodie.datasource.hive_sync.partition_extractor_class': 'org.apache.hudi.hive.MultiPartKeysValueExtractor'
}

# Write a DataFrame as a Hudi dataset
inputDF.write \
.format('org.apache.hudi') \
.option('hoodie.datasource.write.operation', 'insert') \
.options(**hudiOptions) \
.mode('overwrite') \
.save('s3://amzn-s3-demo-bucket/myhudidataset/')
```

**注意**  
您可能會在程式碼範例和通知中看到 "hoodie" 而不是 Hudi。Hudi 程式碼庫廣泛使用舊的 "hoodie" 拼寫。


**Hudi 的 DataSourceWriteOptions 參考**  

| 選項 | Description | 
| --- | --- | 
|  TABLE\$1NAME  |  在其下註冊資料集的表名。  | 
|  TABLE\$1TYPE\$1OPT\$1KEY  |  選用。指定要將資料集建立為 `"COPY_ON_WRITE"` 或 `"MERGE_ON_READ"`。預設值為 `"COPY_ON_WRITE"`。  | 
|  RECORDKEY\$1FIELD\$1OPT\$1KEY  |  記錄金鑰欄位，其值將用作 `HoodieKey` 的 `recordKey` 元件。實際值將藉由叫用欄位值的 `.toString()` 來取得。您可以使用點符號來指定巢狀欄位，例如 `a.b.c`。  | 
|  PARTITIONPATH\$1FIELD\$1OPT\$1KEY  |  分割區路徑欄位，其值將用作 `HoodieKey` 的 `partitionPath` 元件。實際值將藉由叫用欄位值的 `.toString()` 來取得。  | 
|  PRECOMBINE\$1FIELD\$1OPT\$1KEY  |  在實際寫入之前，會在預先結合中使用此欄位。當兩個記錄具有相同的金鑰值時，Hudi 選取 (由 `Object.compareTo(..)` 決定之) 預先組合欄位中值最大的記錄。  | 

只有在您的中繼存放區中註冊 Hudi 資料集資料表時才需要下列選項。如果您未將 Hudi 資料集註冊為 Hive 中繼存放區中的資料表，則不需要這些選項。


**Hive 的 DataSourceWriteOptions 參考**  

| 選項 | Description | 
| --- | --- | 
|  HIVE\$1DATABASE\$1OPT\$1KEY  |  要同步的 Hive 資料庫。預設值為 `"default"`。  | 
|  HIVE\$1PARTITION\$1EXTRACTOR\$1CLASS\$1OPT\$1KEY  |  用於將分割區欄位值擷取至 Hive 分割區欄的類別。  | 
|  HIVE\$1PARTITION\$1FIELDS\$1OPT\$1KEY  |  資料集中用於判斷 Hive 分割區欄的欄位。  | 
|  HIVE\$1SYNC\$1ENABLED\$1OPT\$1KEY  |  當設定為 `"true"` 時，將資料集註冊至 Apache Hive 中繼存放區。預設值為 `"false"`。  | 
|  HIVE\$1TABLE\$1OPT\$1KEY  |  必要. Hive 中要同步的資料表的名稱。例如 `"my_hudi_table_cow"`。  | 
|  HIVE\$1USER\$1OPT\$1KEY  |  選用。同步時要使用的 Hive 使用者名稱。例如 `"hadoop"`。  | 
|  HIVE\$1PASS\$1OPT\$1KEY  |  選用。由 `HIVE_USER_OPT_KEY` 指定之使用者的 Hive 密碼。  | 
|  HIVE\$1URL\$1OPT\$1KEY  |  Hive 中繼存放區 URL。  | 

## Upsert 資料
<a name="emr-hudi-upsert-to-datasets"></a>

下列範例示範如何撰寫 DataFrame 來進行 upsert 資料。與先前插入範例不同，`OPERATION_OPT_KEY` 值設定為 `UPSERT_OPERATION_OPT_VAL`。此外，指定 `.mode(SaveMode.Append)` 以指示應附加記錄。

### 將 Scala 與 Amazon EMR 6.7 及更新版本搭配使用進行 upsert
<a name="scala-upsert-67"></a>

**注意**  
Amazon EMR 6.7.0 使用 [Apache Hudi](https://hudi.apache.org/) 0.11.0-amzn-0，相比之前的 Hudi 版本有顯著改進。如需詳細資訊，請參閱 [Apache Hudi 0.11.0 遷移指南](https://hudi.apache.org/releases/release-0.11.0/#migration-guide)。此標籤上的範例反映了這些變更。

```
// Create a new DataFrame from the first row of inputDF with a different creation_date value
val updateDF = inputDF.limit(1).withColumn("creation_date", lit("new_value"))

(updateDF.write
    .format("hudi")
    .options(hudiOptions)
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY, "upsert")
    .mode(SaveMode.Append)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 將 Scala 與 Amazon EMR 6.6 及更早版本搭配使用進行 upsert
<a name="scala-upsert-66"></a>

```
// Create a new DataFrame from the first row of inputDF with a different creation_date value
val updateDF = inputDF.limit(1).withColumn("creation_date", lit("new_value"))

(updateDF.write
    .format("org.apache.hudi")
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY, DataSourceWriteOptions.UPSERT_OPERATION_OPT_VAL)
    .options(hudiOptions)
    .mode(SaveMode.Append)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 使用 PySpark 進行 upsert
<a name="pyspark-upsert"></a>

```
from pyspark.sql.functions import lit

# Create a new DataFrame from the first row of inputDF with a different creation_date value
updateDF = inputDF.limit(1).withColumn('creation_date', lit('new_value'))

updateDF.write \
    .format('org.apache.hudi') \
    .option('hoodie.datasource.write.operation', 'upsert') \
    .options(**hudiOptions) \
    .mode('append') \
    .save('s3://amzn-s3-demo-bucket/myhudidataset/')
```

## 刪除記錄
<a name="emr-hudi-delete-from-datasets"></a>

若要硬刪除記錄，您可以 upsert 空的承載。在此情況下，`PAYLOAD_CLASS_OPT_KEY` 選項會指定 `EmptyHoodieRecordPayload` 類別。此範例利用在 upsert 範例中使用的相同 DataFrame `updateDF`，來指定相同的記錄。

### 將 Scala 與 Amazon EMR 6.7 及更新版本搭配使用進行刪除
<a name="scala-delete-67"></a>

**注意**  
Amazon EMR 6.7.0 使用 [Apache Hudi](https://hudi.apache.org/) 0.11.0-amzn-0，相比之前的 Hudi 版本有顯著改進。如需詳細資訊，請參閱 [Apache Hudi 0.11.0 遷移指南](https://hudi.apache.org/releases/release-0.11.0/#migration-guide)。此標籤上的範例反映了這些變更。

```
(updateDF.write
    .format("hudi")
    .options(hudiOptions)
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY, "delete")
    .mode(SaveMode.Append)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 將 Scala 與 Amazon EMR 6.6 及更早版本搭配使用進行刪除
<a name="scala-delete-66"></a>

```
(updateDF.write
    .format("org.apache.hudi")
    .option(DataSourceWriteOptions.OPERATION_OPT_KEY, DataSourceWriteOptions.UPSERT_OPERATION_OPT_VAL)
    .option(DataSourceWriteOptions.PAYLOAD_CLASS_OPT_KEY, "org.apache.hudi.common.model.EmptyHoodieRecordPayload")
    .mode(SaveMode.Append)
    .save("s3://amzn-s3-demo-bucket/myhudidataset/"))
```

### 使用 PySpark 進行刪除
<a name="pyspark-delete"></a>

```
updateDF.write \
    .format('org.apache.hudi') \
    .option('hoodie.datasource.write.operation', 'upsert') \
    .option('hoodie.datasource.write.payload.class', 'org.apache.hudi.common.model.EmptyHoodieRecordPayload') \
    .options(**hudiOptions) \
    .mode('append') \
    .save('s3://amzn-s3-demo-bucket/myhudidataset/')
```

您還可以透過以下方式硬刪除資料：將 `OPERATION_OPT_KEY ` 設定為 `DELETE_OPERATION_OPT_VAL`，來刪除您提交的資料集中的所有記錄。如需有關執行軟刪除的指示，以及有關刪除儲存在 Hudi 資料表中的資料的詳細資訊，請參閱 Apache Hudi 文件中的 [Deletes](https://hudi.apache.org/docs/writing_data.html#deletes)。

## 從 Hudi 資料集讀取
<a name="emr-hudi-read-dataset"></a>

為在目前時間點擷取資料，Hudi 依預設執行快照查詢。以下是查詢在 [寫入 Hudi 資料集](#emr-hudi-dataframe) 中寫入至 S3 的資料集的範例。將 *s3：//amzn-s3-demo-bucket/myhudidataset* 取代為您的資料表路徑，並為每個分割區層級新增萬用字元星號，*加上一個額外的星號*。在此範例中，有一個分割區層級，因此我們新增了兩個萬用字符號。

### 將 Scala 與 Amazon EMR 6.7 及更新版本搭配使用進行讀取
<a name="scala-read-67"></a>

**注意**  
Amazon EMR 6.7.0 使用 [Apache Hudi](https://hudi.apache.org/) 0.11.0-amzn-0，相比之前的 Hudi 版本有顯著改進。如需詳細資訊，請參閱 [Apache Hudi 0.11.0 遷移指南](https://hudi.apache.org/releases/release-0.11.0/#migration-guide)。此標籤上的範例反映了這些變更。

```
val snapshotQueryDF = spark.read
    .format("hudi")
    .load("s3://amzn-s3-demo-bucket/myhudidataset") 
    .show()
```

### 將 Scala 與 Amazon EMR 6.6 及更早版本搭配使用進行讀取
<a name="scala-read-66"></a>

```
(val snapshotQueryDF = spark.read
    .format("org.apache.hudi")
    .load("s3://amzn-s3-demo-bucket/myhudidataset" + "/*/*"))

snapshotQueryDF.show()
```

### 使用 PySpark 進行讀取
<a name="pyspark-read"></a>

```
snapshotQueryDF = spark.read \
    .format('org.apache.hudi') \
    .load('s3://amzn-s3-demo-bucket/myhudidataset' + '/*/*')
    
snapshotQueryDF.show()
```

### 增量查詢
<a name="emr-hudi-incremental-query"></a>

您還可以使用 Hudi 執行增量查詢，以取得自提供遞交時間戳記以來已變更的記錄串流。若要這麼做，請將 `QUERY_TYPE_OPT_KEY` 欄位設定為 `QUERY_TYPE_INCREMENTAL_OPT_VAL`。然後，為 `BEGIN_INSTANTTIME_OPT_KEY` 新增一個值，以取得自指定時間以來寫入的所有記錄。增量查詢的效率通常是批次處理查詢的十倍，因為它們僅處理變更的記錄。

在執行增量查詢時，請使用根 (基本) 資料表路徑，而不需要用於快照查詢的萬用字元星號。

**注意**  
Presto 不支援增量查詢。

#### 使用 Scala 進行增量查詢
<a name="scala-incremental-queries"></a>

```
val incQueryDF = spark.read
    .format("org.apache.hudi")
    .option(DataSourceReadOptions.QUERY_TYPE_OPT_KEY, DataSourceReadOptions.QUERY_TYPE_INCREMENTAL_OPT_VAL)
    .option(DataSourceReadOptions.BEGIN_INSTANTTIME_OPT_KEY, <beginInstantTime>)
    .load("s3://amzn-s3-demo-bucket/myhudidataset")
     
incQueryDF.show()
```

#### 使用 PySpark 進行增量查詢
<a name="pyspark-incremental-queries"></a>

```
readOptions = {
  'hoodie.datasource.query.type': 'incremental',
  'hoodie.datasource.read.begin.instanttime': <beginInstantTime>,
}

incQueryDF = spark.read \
    .format('org.apache.hudi') \
    .options(**readOptions) \
    .load('s3://amzn-s3-demo-bucket/myhudidataset')
    
incQueryDF.show()
```

如需有關從 Hudi 資料集讀取的詳細資訊，請參閱 Apache Hudi 文件中的[查詢 Hudi 資料表](https://hudi.apache.org/docs/querying_data.html)。

# 使用 Hudi CLI
<a name="emr-hudi-cli"></a>

您可以使用 Hudi CLI 來管理 Hudi 資料集，以檢視有關遞交、檔案系統、統計資料等資訊。您也可以使用 CLI 手動執行壓縮、排程壓縮或取消排程壓縮。如需詳細資訊，請參閱 Apache Hudi 文件中的[透過 CLI 互動](https://hudi.apache.org/docs/cli/)。

**啟動 Hudi CLI 並連接至資料集**

1. 使用 SSH 連接至主節點。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[使用 SSH 連接至主節點](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)。

1. 在命令列輸入 `/usr/lib/hudi/cli/bin/hudi-cli.sh`。

   命令提示會變更為 `hudi->`。

1. 使用下列命令來連線至資料集。將 *s3：//amzn-s3-demo-bucket/myhudidataset* 取代為您要使用的資料集路徑。我們使用的值與先前範例中建立的值相同。

   ```
   connect --path s3://amzn-s3-demo-bucket/myhudidataset
   ```

   命令提示字元會變更為包含您連線的資料集，如下列範例所示。

   ```
   hudi:myhudidataset->
   ```

根據預設，Amazon EMR 7.3.0 到 7.8.0 版中的`hudi-cli.sh`指令碼會使用 。 `hudi-cli-bundle.jar`如果您遇到問題，您可以使用下列命令切換回傳統 Hudi CLI：

```
/usr/lib/hudi/cli/bin/hudi-cli.sh --cliBundle false
```

此命令會執行`hudi-cli.sh`指令碼、設定 `--cliBundle`旗標，並指示 CLI 使用個別 JAR 檔案，而非綁定的 JAR。根據預設， `--cliBundle`設定為 true，這表示 CLI 會改用綁定的 JAR。

## 使用 Amazon EMR 7.9.0 和更新版本
<a name="emr-hudi-cli-start"></a>

**注意**  
 **hudi-cli.sh** 指令碼已在 EMR 7.9.0 版及更高版本中棄用。Amazon EMR 7.9.0 版和更新版本使用 **hudi-cli-bundle.jar**。

**若要啟動 Hudi CLI 並連線至資料集：**

1. 使用 SSH 連接至主節點。如需詳細資訊，請參閱《Amazon EMR 管理指南》**中的[使用 SSH 連接至主節點](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node-ssh.html)。

1. 在命令列輸入 **/usr/lib/hudi/cli-bundle/bin/hudi-cli-with-bundle.sh**，或直接輸入 **hudi-cli-with-bundle** 或 **>hudi-cli**。

   命令提示字元會變更為 **hudi- >**。

1. 使用下列命令來連線至資料集。將 **s3：//amzn-s3-demo-bucket/myhudidataset** 取代為您要使用的資料集路徑。我們使用的值與先前範例中建立的值相同。

   ```
   connect --path s3://amzn-s3-demo-bucket/myhudidataset
   ```

1. 命令提示字元會變更為包含您連線的資料集，如下列範例所示。

   ```
   hudi:myhudidataset->
   ```

# Hudi 版本歷史記錄
<a name="Hudi-release-history"></a>

下表列出 Amazon EMR 的每個發行版本中包含的 Hudi 版本，以及與應用程式一起搭配安裝的元件。如需每個發行版本中的元件版本，請參閱 [Amazon EMR 7.x 發行版本](emr-release-7x.md)、[Amazon EMR 6.x 發行版本](emr-release-6x.md) 或 [Amazon EMR 5.x 發行版本](emr-release-5x.md) 中適用於您發行版本的「元件版本」一節。


**Hudi 版本資訊**  

| Amazon EMR 發行標籤 | Hudi 版本 | 與 Hudi 一起搭配安裝的元件 | 
| --- | --- | --- | 
| emr-7.12.0 | 1.0.2-amzn-1 | Not available. | 
| emr-7.11.0 | 1.0.2-amzn-0 | Not available. | 
| emr-7.10.0 | 0.15.0-amzn-7 | Not available. | 
| emr-7.9.0 | 0.15.0-amzn-6 | Not available. | 
| emr-7.8.0 | 0.15.0-amzn-5 | Not available. | 
| emr-7.7.0 | 0.15.0-amzn-4 | Not available. | 
| emr-7.6.0 | 0.15.0-amzn-3 | Not available. | 
| emr-7.5.0 | 0.15.0-amzn-2 | Not available. | 
| emr-7.4.0 | 0.15.0-amzn-1 | Not available. | 
| emr-7.3.0 | 0.15.0-amzn-0 | Not available. | 
| emr-7.2.0 | 0.14.1-amzn-1 | Not available. | 
| emr-5.36.2 | 0.10.1-amzn-1 | Not available. | 
| emr-7.1.0 | 0.14.1-amzn-0 | Not available. | 
| emr-7.0.0 | 0.14.0-amzn-1 | Not available. | 
| emr-6.15.0 | 0.14.0-amzn-0 | Not available. | 
| emr-6.14.0 | 0.13.1-amzn-2 | Not available. | 
| emr-6.13.0 | 0.13.1-amzn-1 | Not available. | 
| emr-6.12.0 | 0.13.1-amzn-0 | Not available. | 
| emr-6.11.1 | 0.13.0-amzn-0 | Not available. | 
| emr-6.11.0 | 0.13.0-amzn-0 | Not available. | 
| emr-6.10.1 | 0.12.2-amzn-0 | Not available. | 
| emr-6.10.0 | 0.12.2-amzn-0 | Not available. | 
| emr-6.9.1 | 0.12.1-amzn-0 | Not available. | 
| emr-6.9.0 | 0.12.1-amzn-0 | Not available. | 
| emr-6.8.1 | 0.11.1-amzn-0 | Not available. | 
| emr-6.8.0 | 0.11.1-amzn-0 | Not available. | 
| emr-6.7.0 | 0.11.0-amzn-0 | Not available. | 
| emr-5.36.1 | 0.10.1-amzn-1 | Not available. | 
| emr-5.36.0 | 0.10.1-amzn-1 | Not available. | 
| emr-6.6.0 | 0.10.1-amzn-0 | Not available. | 
| emr-5.35.0 | 0.9.0-amzn-2 | Not available. | 
| emr-6.5.0 | 0.9.0-amzn-1 | Not available. | 
| emr-6.4.0 | 0.8.0-amzn-0 | Not available. | 
| emr-6.3.1 | 0.7.0-amzn-0 | Not available. | 
| emr-6.3.0 | 0.7.0-amzn-0 | Not available. | 
| emr-6.2.1 | 0.6.0-amzn-1 | Not available. | 
| emr-6.2.0 | 0.6.0-amzn-1 | Not available. | 
| emr-6.1.1 | 0.5.2-incubating-amzn-2 | Not available. | 
| emr-6.1.0 | 0.5.2-incubating-amzn-2 | Not available. | 
| emr-6.0.1 | 0.5.0-incubating-amzn-1 | Not available. | 
| emr-6.0.0 | 0.5.0-incubating-amzn-1 | Not available. | 
| emr-5.34.0 | 0.9.0-amzn-0 | Not available. | 
| emr-5.33.1 | 0.7.0-amzn-1 | Not available. | 
| emr-5.33.0 | 0.7.0-amzn-1 | Not available. | 
| emr-5.32.1 | 0.6.0-amzn-0 | Not available. | 
| emr-5.32.0 | 0.6.0-amzn-0 | Not available. | 
| emr-5.31.1 | 0.6.0-amzn-0 | Not available. | 
| emr-5.31.0 | 0.6.0-amzn-0 | Not available. | 
| emr-5.30.2 | 0.5.2-incubating | Not available. | 
| emr-5.30.1 | 0.5.2-incubating | Not available. | 
| emr-5.30.0 | 0.5.2-incubating | Not available. | 
| emr-5.29.0 | 0.5.0-incubating | Not available. | 
| emr-5.28.1 | 0.5.0-incubating | Not available. | 
| emr-5.28.0 | 0.5.0-incubating | Not available. | 