

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

# 搭配 Amazon EMR 使用具體化視觀表
<a name="emr-spark-materialized-views"></a>

Amazon EMR 7.12.0 版及更新版本支援在 Glue Data Catalog 中建立和管理 Apache Iceberg AWS 具體化視觀表。具體化檢視是受管資料表，以 Apache Iceberg 格式存放 SQL 查詢的預先計算結果，並隨著基礎來源資料表的變更逐步更新。您可以使用具體化視觀表來簡化資料轉換管道，並加速複雜分析工作負載的查詢效能。

當您在 Amazon EMR 上使用 Spark 建立具體化檢視時，檢視定義和中繼資料會存放在 AWS Glue Data Catalog 中。預先計算的結果會以 Apache Iceberg 資料表的形式儲存在 Amazon S3 Tables 儲存貯體中，或存放在您 AWS 帳戶中的 Amazon S3 一般用途儲存貯體中。Glue Data Catalog AWS 會自動監控來源資料表，並使用受管運算基礎設施重新整理具體化視觀表。

**Topics**
+ [具體化視觀表如何與 Amazon EMR 搭配使用](#emr-spark-materialized-views-how-it-works)
+ [先決條件](#emr-spark-materialized-views-prerequisites)
+ [設定 Spark 以使用具體化視觀表](#emr-spark-materialized-views-configure)
+ [建立具體化視觀表](#emr-spark-materialized-views-create)
+ [查詢具體化視觀表](#emr-spark-materialized-views-query)
+ [重新整理具體化視觀表](#emr-spark-materialized-views-refresh)
+ [管理具體化視觀表](#emr-spark-materialized-views-manage)
+ [具體化視觀表的許可](#emr-spark-materialized-views-permissions)
+ [監控具體化視觀表操作](#emr-spark-materialized-views-monitoring)
+ [範例：完成工作流程](#emr-spark-materialized-views-example)
+ [考量和限制](#emr-spark-materialized-views-limitations)

## 具體化視觀表如何與 Amazon EMR 搭配使用
<a name="emr-spark-materialized-views-how-it-works"></a>

具體化視觀表透過 Apache Spark 的 Iceberg 支援與 Amazon EMR 整合。當您將 Spark 工作階段設定為使用 AWS Glue Data Catalog 時，您可以使用標準 SQL 語法建立具體化檢視。Spark 最佳化工具可以在提供更好的效能時自動重寫查詢，以使用具體化視觀表，無需手動修改應用程式程式碼。

Glue Data Catalog AWS 會處理具體化視觀表維護的所有操作層面，包括：
+ 使用 Apache Iceberg 的中繼資料層偵測來源資料表中的變更
+ 使用受管 Spark 運算排程和執行重新整理操作
+ 根據資料變更決定是否執行完整或增量重新整理
+ 將預先計算的結果儲存為 Apache Iceberg 格式以進行多引擎存取

您可以使用用於一般資料表的相同 Spark SQL 介面，從 Amazon EMR 查詢具體化視觀表。預先計算的資料也可以從其他 服務存取，包括 Amazon Athena 和 Amazon Redshift。

## 先決條件
<a name="emr-spark-materialized-views-prerequisites"></a>

若要搭配 Amazon EMR 使用具體化視觀表，您需要：
+  AWS 帳戶
+ 執行 7.12.0 或更新版本的 Amazon EMR 叢集
+ 在 Glue Data Catalog AWS 中註冊的 Apache Iceberg 格式來源資料表
+ AWS 針對來源資料表和目標資料庫設定的 Lake Formation 許可
+ 向 Lake Formation 註冊的 AWS S3 Tables 儲存貯體或 S3 一般用途儲存貯體，用於存放具體化視觀表資料

## 設定 Spark 以使用具體化視觀表
<a name="emr-spark-materialized-views-configure"></a>

若要建立和管理具體化視觀表，請使用所需的 Iceberg 延伸模組和目錄設定來設定 Spark 工作階段。組態會根據來源資料表和具體化視觀表是否使用 S3 Tables 儲存貯體或 S3 一般用途儲存貯體而有所不同。

### 設定 S3 資料表
<a name="emr-spark-materialized-views-configure-s3-tables"></a>

將 S3 Tables 儲存貯體用於具體化視觀表時，請為來源資料表和具體化視觀表設定個別的目錄參考：

```
spark-sql \
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
  --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.glue_catalog.type=glue \
  --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
  --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
  --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
  --conf spark.sql.catalog.glue_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.glue_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.catalog.s3t_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.s3t_catalog.type=glue \
  --conf spark.sql.catalog.s3t_catalog.glue.id=111122223333:s3tablescatalog/my-table-bucket \
  --conf spark.sql.catalog.s3t_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.catalog.s3t_catalog.warehouse=s3://amzn-s3-demo-bucket/mv-warehouse \
  --conf spark.sql.catalog.s3t_catalog.glue.region=us-east-1 \
  --conf spark.sql.defaultCatalog=s3t_catalog \
  // turn on automatic query rewrite (optional)
  --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true
```

### 針對 S3 一般用途儲存貯體設定
<a name="emr-spark-materialized-views-configure-s3-general"></a>

使用 S3 一般用途儲存貯體時，請設定單一目錄參考：

```
spark-sql \
  --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
  --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
  --conf spark.sql.catalog.glue_catalog.type=glue \
  --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
  --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
  --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.account-id=111122223333 \
  --conf spark.sql.catalog.s3t_catalog.glue.lakeformation-enabled=true \
  --conf spark.sql.defaultCatalog=glue_catalog \
  // turn on automatic query rewrite (optional)
  --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true
```

### 啟用增量重新整理
<a name="emr-spark-materialized-views-configure-incremental"></a>

若要啟用增量重新整理最佳化，請將下列組態屬性新增至 Spark 工作階段：

```
spark-sql \
  --conf spark.sql.optimizer.incrementalMVRefresh.enabled=true \
```

### 組態參數
<a name="emr-spark-materialized-views-configure-parameters"></a>

下列組態參數控制具體化視觀表行為：
+ `spark.sql.extensions` – 啟用具體化視觀表支援所需的 Iceberg Spark 工作階段延伸。
+ `spark.sql.optimizer.answerQueriesWithMVs.enabled` – 啟用自動查詢重寫以使用具體化視觀表。設為 true 以啟用此最佳化。
+ `spark.sql.optimizer.incrementalMVRefresh.enabled` – 啟用增量重新整理最佳化。設為 true 以在重新整理操作期間僅處理已變更的資料。

## 建立具體化視觀表
<a name="emr-spark-materialized-views-create"></a>

您可以使用 CREATE MATERIALIZED VIEW SQL 陳述式建立具體化視觀表。檢視定義會將轉換邏輯指定為參考一或多個來源資料表的 SQL 查詢。

### DLLs
<a name="emr-spark-materialized-views-create-dlls"></a>

**建立檢視**

```
{ CREATE OR REPLACE MATERIALIZED VIEW | CREATE MATERIALIZED VIEW [ IF NOT EXISTS ] }
   view_identifier
  [ view_clauses ]
  [ schedule_clauses ]
  AS [ select_statement ]

view_clauses =
  { [ LOCATION location ] |
    [ PARTITIONED BY (col [, ...]) ] |
    [ COMMENT view_comment ] |
    [ SCHEDULE [ REFRESH ] schedule_clause ] }

schedule_clause =
  { EVERY number { HOUR | HOURS | DAY | DAYS | WEEK | WEEKS } }
```

**注意**  
view\$1clauses 必須出現在 select\$1statement 之前。

### 建立基本具體化視觀表
<a name="emr-spark-materialized-views-create-basic"></a>

下列範例會建立具體化檢視，依客戶彙總訂單資料，在檢視定義中使用具有三個部分命名慣例的完整資料表名稱：

```
CREATE MATERIALIZED VIEW customer_orders
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

### 使用自動重新整理建立具體化檢視
<a name="emr-spark-materialized-views-create-auto-refresh"></a>

若要設定自動重新整理，請在檢視定義中使用具有三個部分命名慣例的完整資料表名稱建立檢視時指定重新整理排程：

```
CREATE MATERIALIZED VIEW customer_orders
SCHEDULE REFRESH EVERY 1 HOUR
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

### 使用跨目錄參考建立具體化視觀表
<a name="emr-spark-materialized-views-create-cross-catalog"></a>

當您的來源資料表與具體化檢視位於不同的目錄中時，請在檢視名稱和檢視定義中使用具有三部分命名慣例的完整資料表名稱：

```
CREATE MATERIALIZED VIEW s3t_catalog.analytics.customer_summary
AS 
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM glue_catalog.sales.orders
GROUP BY customer_name;
```

## 查詢具體化視觀表
<a name="emr-spark-materialized-views-query"></a>

建立具體化檢視後，您可以使用標準 SQL SELECT 陳述式，像任何其他資料表一樣進行查詢：

```
SELECT * FROM customer_orders;
```

### 自動查詢重寫
<a name="emr-spark-materialized-views-query-rewrite"></a>

啟用自動查詢重寫時，Spark 最佳化工具會分析您的查詢，並在可以改善效能時自動使用具體化視觀表。例如，如果您執行下列查詢：

```
SELECT 
    customer_name, 
    COUNT(*) as order_count, 
    SUM(amount) as total_amount 
FROM orders
GROUP BY customer_name;
```

Spark 最佳化工具會自動重寫此查詢，以使用 customer\$1orders 具體化檢視，而不是處理基礎訂單資料表，前提是具體化檢視是最新的。

### 驗證自動查詢重寫
<a name="emr-spark-materialized-views-query-verify"></a>

若要驗證查詢是否使用自動查詢重寫，請使用 EXPLAIN EXTENDED 命令：

```
EXPLAIN EXTENDED
SELECT customer_name, COUNT(*) as order_count, SUM(amount) as total_amount 
FROM orders
GROUP BY customer_name;
```

在執行計畫中，尋找 BatchScan 操作中的具體化檢視名稱。如果計劃顯示 BatchScan glue\$1catalog.analytics.customer\$1orders，而不是 BatchScan glue\$1catalog.sales.orders，則查詢會自動重新寫入，以使用具體化視觀表。

**注意**  
自動查詢重寫需要時間，Spark 中繼資料快取才能在建立具體化檢視之後填入。此程序通常會在 30 秒內完成。

## 重新整理具體化視觀表
<a name="emr-spark-materialized-views-refresh"></a>

您可以使用兩種方法重新整理具體化視觀表：完全重新整理或增量重新整理。完整重新整理會從所有基礎資料表資料重新計算整個具體化檢視，而增量重新整理只會處理自上次重新整理以來變更的資料。

### 手動完整重新整理
<a name="emr-spark-materialized-views-refresh-full"></a>

若要完整重新整理具體化視觀表：

```
REFRESH MATERIALIZED VIEW customer_orders FULL;
```

執行此命令後，請查詢具體化檢視以驗證更新的結果：

```
SELECT * FROM customer_orders;
```

### 手動增量重新整理
<a name="emr-spark-materialized-views-refresh-incremental"></a>

若要執行增量重新整理，請確定已在 Spark 工作階段組態中啟用增量重新整理，然後執行：

```
REFRESH MATERIALIZED VIEW customer_orders;
```

 AWS Glue Data Catalog 會根據檢視定義和變更的資料量，自動判斷增量重新整理是否適用。如果無法進行增量重新整理，操作會回到完全重新整理。

### 驗證增量重新整理執行
<a name="emr-spark-materialized-views-refresh-verify"></a>

若要確認已成功執行增量重新整理，您可以執行下列命令來檢查`lastRefreshType`資料表屬性：

```
SHOW TBLPROPERTIES <mvName>("lastRefreshType")
```

此外，您也可以透過修改 Spark 日誌組態來啟用偵錯記錄來達成此目的：

1. 開啟 Spark log4j 組態檔案：

   ```
   sudo vim /usr/lib/spark/conf/log4j2.properties
   ```

1. 新增下列記錄器組態：

   ```
   logger.spark.name = org.apache.spark.sql
   logger.spark.level = debug
   
   logger.inmemcache.name = org.apache.spark.sql.InMemMvMetadataCache
   logger.inmemcache.level = off
   ```

1. 執行重新整理操作後，請在 Spark 輸出中搜尋下列訊息：

   ```
   DEBUG RefreshMaterializedViewExec: Executed Incremental Refresh
   ```

## 管理具體化視觀表
<a name="emr-spark-materialized-views-manage"></a>

Amazon EMR 提供 SQL 命令來管理具體化視觀表的生命週期。

### 描述具體化視觀表
<a name="emr-spark-materialized-views-manage-describe"></a>

若要檢視具體化檢視的中繼資料，包括其定義、重新整理狀態和上次重新整理時間戳記：

```
DESCRIBE EXTENDED customer_orders;
```

### 變更具體化視觀表
<a name="emr-spark-materialized-views-manage-alter"></a>

若要修改現有具體化檢視的重新整理排程：

```
ALTER MATERIALIZED VIEW customer_orders 
ADD SCHEDULE REFRESH EVERY 2 HOURS;
```

若要移除自動重新整理：

```
ALTER MATERIALIZED VIEW customer_orders 
DROP SCHEDULE;
```

### 捨棄具體化視觀表
<a name="emr-spark-materialized-views-manage-drop"></a>

若要刪除具體化視觀表：

```
DROP MATERIALIZED VIEW customer_orders;
```

此命令會從 Glue Data Catalog AWS 中移除具體化檢視定義，並從 S3 儲存貯體中刪除基礎 Iceberg 資料表資料。

## 具體化視觀表的許可
<a name="emr-spark-materialized-views-permissions"></a>

若要建立和管理具體化視觀表，您必須設定 AWS Lake Formation 許可。建立具體化檢視的 IAM 角色 （定義者角色） 需要來源資料表和目標資料庫的特定許可。

### 定義者角色的必要許可
<a name="emr-spark-materialized-views-permissions-definer"></a>

定義者角色必須具有下列 Lake Formation 許可：
+ 在來源資料表上 – 沒有資料列、資料欄或儲存格篩選條件的 SELECT 或 ALL 許可
+ 在目標資料庫上 – CREATE\$1TABLE 許可
+ 在 AWS Glue Data Catalog 上 – GetTable 和 CreateTable API 許可

當您建立具體化檢視時，定義者角色的 ARN 會存放在檢視定義中。執行自動重新整理操作時， AWS Glue Data Catalog 會擔任此角色。如果定義者角色無法存取來源資料表，重新整理操作將會失敗，直到許可還原為止。

### 授予具體化視觀表的存取權
<a name="emr-spark-materialized-views-permissions-access"></a>

若要授予其他使用者查詢具體化視觀表的存取權，請使用 AWS Lake Formation 授予具體化視觀表的 SELECT 許可。使用者可以查詢具體化視觀表，而不需要直接存取基礎來源資料表。

如需設定 Lake Formation 許可的詳細資訊，請參閱 AWS Lake Formation 開發人員指南中的授予和撤銷 Data Catalog 資源的許可。

## 監控具體化視觀表操作
<a name="emr-spark-materialized-views-monitoring"></a>

 AWS Glue Data Catalog 會將具體化檢視重新整理操作的指標和日誌發佈至 Amazon CloudWatch。您可以監控透過 CloudWatch 指標處理的重新整理狀態、持續時間和資料磁碟區。

### 檢視重新整理指標
<a name="emr-spark-materialized-views-monitoring-metrics"></a>

若要檢視具體化檢視重新整理指標：

1. 開啟 CloudWatch 主控台。

1. 從導覽窗格中選擇指標。

1. 選取 Glue (Glue) 命名空間。

1. 依具體化檢視名稱篩選指標。

### 設定警示
<a name="emr-spark-materialized-views-monitoring-alarms"></a>

若要在重新整理操作失敗或超過預期持續時間時接收通知，請在具體化檢視指標上建立 CloudWatch 警示。您也可以設定 Amazon EventBridge 規則來觸發重新整理事件的自動回應。

## 範例：完成工作流程
<a name="emr-spark-materialized-views-example"></a>

下列範例示範在 Amazon EMR 上建立和使用具體化檢視的完整工作流程。

1. 使用 SSH 連線至 EMR 叢集主節點。

1. 使用範例資料建立基礎資料表：

   ```
   spark-sql \
     --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
     --conf spark.sql.catalog.glue_catalog=org.apache.iceberg.spark.SparkCatalog \
     --conf spark.sql.catalog.glue_catalog.type=glue \
     --conf spark.sql.catalog.glue_catalog.warehouse=s3://amzn-s3-demo-bucket/warehouse \
     --conf spark.sql.catalog.glue_catalog.glue.region=us-east-1 \
     --conf spark.sql.catalog.glue_catalog.glue.id=111122223333 \
     --conf spark.sql.catalog.glue_catalog.glue.account-id=111122223333 \
     --conf spark.sql.catalog.glue_catalog.glue.lakeformation-enabled=true \
     --conf spark.sql.defaultCatalog=glue_catalog \
     --conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true 
   
   
   CREATE DATABASE IF NOT EXISTS sales;
   
   USE sales;
   
   CREATE TABLE orders (
       id INT,
       customer_name STRING,
       amount DECIMAL(10,2),
       order_date DATE
   );
   
   INSERT INTO orders VALUES 
       (1, 'John Doe', 150.00, DATE('2024-01-15')),
       (2, 'Jane Smith', 200.50, DATE('2024-01-16')),
       (3, 'Bob Johnson', 75.25, DATE('2024-01-17'));
   ```

1. 建立具體化視觀表：

   ```
   CREATE MATERIALIZED VIEW customer_summary
   AS 
   SELECT 
       customer_name, 
       COUNT(*) as order_count, 
       SUM(amount) as total_amount 
   FROM glue_catalog.sales.orders
   GROUP BY customer_name;
   ```

1. 查詢具體化視觀表：

   ```
   SELECT * FROM customer_summary;
   ```

1. 將其他資料插入基底資料表：

   ```
   INSERT INTO orders VALUES 
       (4, 'Jane Smith', 350.00, DATE('2024-01-18')),
       (5, 'Bob Johnson', 100.25, DATE('2024-01-19'));
   ```

1. 重新整理具體化視觀表：

   ```
   REFRESH MATERIALIZED VIEW customer_summary FULL;
   ```

1. 驗證更新的結果：

   ```
   SELECT * FROM customer_summary;
   ```

## 考量和限制
<a name="emr-spark-materialized-views-limitations"></a>

搭配 Amazon EMR 使用具體化視觀表時，請考慮下列事項：
+ 具體化視觀表需要 Amazon EMR 7.12.0 或更新版本。
+ 來源資料表必須是在 Glue Data Catalog 中註冊的 Apache Iceberg AWS 資料表。啟動時不支援 Apache Hive、Apache Hudi 和 Linux Foundation Delta Lake 資料表。
+ 來源資料表必須位於與具體化視觀表相同的 AWS 區域和 AWS 帳戶中。
+ 所有來源資料表都必須受 AWS Lake Formation 管理。不支援僅限 IAM 的許可和混合存取。
+ 具體化視觀表無法參考 AWS Glue Data Catalog 檢視、多方視觀表或其他具體化視觀表作為來源資料表。
+ 檢視定義者角色必須在未套用資料列、資料欄或儲存格篩選條件的所有來源資料表上具有完整讀取存取權 (SELECT 或 ALL 許可）。
+ 具體化視觀表最終與來源資料表一致。在重新整理時段期間，查詢可能會傳回過時的資料。執行手動重新整理以立即保持一致。
+ 最短自動重新整理間隔為一小時。
+ 增量重新整理支援 SQL 操作的限制子集。檢視定義必須是單一 SELECT-FROM-WHERE-GROUP BY-HAVING 區塊，而且不能包含設定操作、子查詢、SELECT 或彙總函數中的 DISTINCT 關鍵字、視窗函數或 INNER JOIN 以外的聯結。
+ 增量重新整理不支援使用者定義的函數或特定內建函數。僅支援 Spark SQL 內建函數的子集。
+ 查詢自動重寫只會考慮具體化視觀表，其定義屬於與增量重新整理限制類似的受限 SQL 子集。
+ 完整重新整理操作會覆寫整個資料表，並使先前的快照無法使用。
+ CREATE MATERIALIZED VIEW 查詢不支援包含英數字元和底線以外的特殊字元的識別符。
+ 以 \$1\$1ivm 字首開頭的具體化檢視資料欄會保留給系統使用。 AWS 保留在未來版本中修改或移除這些資料欄的權利。
+ 具體化視觀表定義中不支援 SORT BY、LIMIT、OFFSET、CLUSTER BY 和 ORDER BY 子句。
+ 不支援跨區域和跨帳戶來源資料表。
+ 具體化視觀表定義不支援非確定性函數，例如 rand() 或 current\$1timestamp()。