

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

# 搭配 Glue AWS 使用具體化視觀表
<a name="materialized-views"></a>

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

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

**Topics**
+ [具體化視觀表如何與 Glue AWS 搭配使用](#materialized-views-how-they-work)
+ [先決條件](#materialized-views-prerequisites)
+ [設定 Spark 以使用具體化視觀表](#materialized-views-configuring-spark)
+ [建立具體化視觀表](#materialized-views-creating)
+ [查詢具體化視觀表](#materialized-views-querying)
+ [重新整理具體化視觀表](#materialized-views-refreshing)
+ [管理具體化視觀表](#materialized-views-managing)
+ [具體化視觀表的許可](#materialized-views-permissions)
+ [監控具體化視觀表操作](#materialized-views-monitoring)
+ [範例：完成工作流程](#materialized-views-complete-workflow)
+ [考量和限制](#materialized-views-considerations-limitations)

## 具體化視觀表如何與 Glue AWS 搭配使用
<a name="materialized-views-how-they-work"></a>

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

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

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

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

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

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

若要在 Glue AWS 中建立和管理具體化視觀表，請使用所需的 Iceberg 延伸模組和目錄設定來設定 Spark 工作階段。組態方法取決於您使用的是 AWS Glue 任務或 Glue Studio AWS 筆記本。

### 設定 AWS Glue 任務
<a name="materialized-views-configuring-glue-jobs"></a>

建立或更新 AWS Glue 任務時，請將下列組態參數新增為任務參數：

#### 對於 S3 Tables 儲存貯體
<a name="materialized-views-s3-tables-buckets"></a>

```
job = glue.create_job(
    Name='materialized-view-job',
    Role='arn:aws:iam::111122223333:role/GlueServiceRole',
    Command={
        'Name': 'glueetl',
        'ScriptLocation': 's3://amzn-s3-demo-bucket/scripts/mv-script.py',
        'PythonVersion': '3'
    },
    DefaultArguments={
        '--enable-glue-datacatalog': 'true',
        '--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 '
                  '--conf spark.sql.optimizer.answerQueriesWithMVs.enabled=true '
                  '--conf spark.sql.materializedViews.metadataCache.enabled=true'
    },
    GlueVersion='5.1'
)
```

#### 對於 S3 一般用途儲存貯體
<a name="materialized-views-s3-general-purpose-buckets"></a>

```
job = glue.create_job(
    Name='materialized-view-job',
    Role='arn:aws:iam::111122223333:role/GlueServiceRole',
    Command={
        'Name': 'glueetl',
        'ScriptLocation': 's3://amzn-s3-demo-bucket/scripts/mv-script.py',
        'PythonVersion': '3'
    },
    DefaultArguments={
        '--enable-glue-datacatalog': 'true',
        '--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 '
                  '--conf spark.sql.materializedViews.metadataCache.enabled=true'
    },
    GlueVersion='5.1'
)
```

### 設定 AWS Glue Studio 筆記本
<a name="materialized-views-configuring-glue-studio-notebooks"></a>

在 AWS Glue Studio 筆記本中，使用筆記本開頭的 %%configure 魔術命令來設定 Spark 工作階段：

```
%%configure
{
    "conf": {
        "spark.sql.extensions": "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions",
        "spark.sql.catalog.glue_catalog": "org.apache.iceberg.spark.SparkCatalog",
        "spark.sql.catalog.glue_catalog.type": "glue",
        "spark.sql.catalog.glue_catalog.warehouse": "s3://amzn-s3-demo-bucket/warehouse",
        "spark.sql.catalog.glue_catalog.glue.region": "us-east-1",
        "spark.sql.catalog.glue_catalog.glue.id": "111122223333",
        "spark.sql.catalog.glue_catalog.glue.account-id": "111122223333",
        "spark.sql.catalog.glue_catalog.glue.lakeformation-enabled": "true",
        "spark.sql.defaultCatalog": "glue_catalog",
        "spark.sql.optimizer.answerQueriesWithMVs.enabled": "true",
        "spark.sql.materializedViews.metadataCache.enabled": "true"
    }
}
```

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

若要啟用增量重新整理最佳化，請將下列組態屬性新增至您的任務參數或筆記本組態：

```
--conf spark.sql.optimizer.incrementalMVRefresh.enabled=true
--conf spark.sql.optimizer.incrementalMVRefresh.deltaThresholdCheckEnabled=false
```

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

下列組態參數控制具體化視觀表行為：
+ `spark.sql.extensions` – 啟用具體化視觀表支援所需的 Iceberg Spark 工作階段延伸。
+ `spark.sql.optimizer.answerQueriesWithMVs.enabled` – 啟用自動查詢重寫以使用具體化視觀表。設定為 true 以啟用此最佳化。
+ `spark.sql.materializedViews.metadataCache.enabled` – 啟用具體化檢視中繼資料的快取，以進行查詢最佳化。設為 true 可改善查詢重寫效能。
+ `spark.sql.optimizer.incrementalMVRefresh.enabled` – 啟用增量重新整理最佳化。設為 true 以在重新整理操作期間僅處理已變更的資料。
+ `spark.sql.optimizer.answerQueriesWithMVs.decimalAggregateCheckEnabled` – 控制查詢重寫中小數彙總操作的驗證。設定為 false 以停用特定小數溢位檢查。

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

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

### 在 Glue AWS 任務中建立基本具體化視觀表
<a name="materialized-views-creating-basic-glue-jobs"></a>

下列範例示範在 Glue AWS 任務指令碼中建立具體化檢視，在檢視定義中使用具有三個部分命名慣例的完整資料表名稱：

```
from awsglue.context import GlueContext
from pyspark.context import SparkContext

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session

# Create materialized view
spark.sql("""
    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="materialized-views-creating-automatic-refresh"></a>

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

```
spark.sql("""
    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="materialized-views-creating-cross-catalog"></a>

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

```
spark.sql("""
    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
""")
```

### 在 Glue Studio AWS 筆記本中建立具體化視觀表
<a name="materialized-views-creating-glue-studio-notebooks"></a>

在 AWS Glue Studio 筆記本中，您可以使用 %%sql 魔術命令，在檢視定義中使用具有三個部分命名慣例的完整資料表名稱來建立具體化檢視：

```
%%sql
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="materialized-views-querying"></a>

建立具體化檢視後，您可以使用 Glue 任務或筆記本中的標準 SQL SELECT AWS 陳述式，像任何其他資料表一樣進行查詢。

### 在 Glue AWS 任務中查詢
<a name="materialized-views-querying-glue-jobs"></a>

```
from awsglue.context import GlueContext
from pyspark.context import SparkContext

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session

# Query materialized view
result = spark.sql("SELECT * FROM customer_orders")
result.show()
```

### 在 AWS Glue Studio 筆記本中查詢
<a name="materialized-views-querying-glue-studio-notebooks"></a>

```
%%sql
SELECT * FROM customer_orders
```

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

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

```
result = spark.sql("""
    SELECT 
        customer_name, 
        COUNT(*) as order_count, 
        SUM(amount) as total_amount 
    FROM orders
    GROUP BY customer_name
""")
```

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

### 驗證自動查詢重寫
<a name="materialized-views-verifying-automatic-query-rewrite"></a>

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

```
spark.sql("""
    EXPLAIN EXTENDED
    SELECT customer_name, COUNT(*) as order_count, SUM(amount) as total_amount 
    FROM orders
    GROUP BY customer_name
""").show(truncate=False)
```

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

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

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

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

### Glue AWS 任務中的手動完整重新整理
<a name="materialized-views-manual-full-refresh-glue-jobs"></a>

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

```
spark.sql("REFRESH MATERIALIZED VIEW customer_orders FULL")

# Verify updated results
result = spark.sql("SELECT * FROM customer_orders")
result.show()
```

### Glue AWS 任務中的手動增量重新整理
<a name="materialized-views-manual-incremental-refresh-glue-jobs"></a>

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

```
spark.sql("REFRESH MATERIALIZED VIEW customer_orders")

# Verify updated results
result = spark.sql("SELECT * FROM customer_orders")
result.show()
```

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

### 在 AWS Glue Studio 筆記本中重新整理
<a name="materialized-views-refreshing-glue-studio-notebooks"></a>

在筆記本中，使用 %%sql 魔術命令：

```
%%sql
REFRESH MATERIALIZED VIEW customer_orders FULL
```

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

若要確認已成功執行增量重新整理，請在 AWS Glue 任務中啟用偵錯記錄：

```
from awsglue.context import GlueContext
from pyspark.context import SparkContext
import logging

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session

# Enable debug logging
logger = logging.getLogger('org.apache.spark.sql')
logger.setLevel(logging.DEBUG)

# Execute refresh
spark.sql("REFRESH MATERIALIZED VIEW customer_orders")
```

在 Glue AWS 任務日誌中搜尋下列訊息：

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

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

AWS Glue 提供 SQL 命令，用於管理任務和筆記本中具體化視觀表的生命週期。

### 描述具體化視觀表
<a name="materialized-views-describing"></a>

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

```
spark.sql("DESCRIBE EXTENDED customer_orders").show(truncate=False)
```

### 變更具體化視觀表
<a name="materialized-views-altering"></a>

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

```
spark.sql("""
    ALTER MATERIALIZED VIEW customer_orders 
    ADD SCHEDULE REFRESH EVERY 2 HOURS
""")
```

若要移除自動重新整理：

```
spark.sql("""
    ALTER MATERIALIZED VIEW customer_orders 
    DROP SCHEDULE
""")
```

### 捨棄具體化視觀表
<a name="materialized-views-dropping"></a>

若要刪除具體化檢視：

```
spark.sql("DROP MATERIALIZED VIEW customer_orders")
```

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

### 列出具體化視觀表
<a name="materialized-views-listing"></a>

若要列出資料庫中的所有具體化視觀表：

```
spark.sql("SHOW VIEWS FROM analytics").show()
```

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

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

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

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

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

### Glue 任務的 IAM AWS 許可
<a name="materialized-views-iam-permissions-glue-jobs"></a>

Glue AWS 任務的 IAM 角色需要下列許可：

```
{
    "Version": "2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "glue:GetCatalog",
                "glue:GetCatalogs",
                "glue:GetTable",
                "glue:GetTables",
                "glue:CreateTable",
                "glue:UpdateTable",
                "glue:DeleteTable",
                "glue:GetDatabase",
                "glue:GetDatabases",
                "cloudwatch:PutMetricData"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::amzn-s3-demo-bucket"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:*:*:*:/aws-glue/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "lakeformation:GetDataAccess"
            ],
            "Resource": "*"
        }
    ]
}
```

您用於具體化檢視自動重新整理的角色必須具有角色的 iam：PassRole 許可。

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:PassRole"
      ],
      "Resource": [
        "arn:aws:iam::111122223333:role/materialized-view-role-name"
      ]
    }
  ]
}
```

若要讓 Glue 為您自動重新整理具體化視觀表，該角色也必須具有下列信任政策，讓服務能夠擔任該角色。

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "iam:PassRole"
      ],
      "Resource": [
        "arn:aws:iam::111122223333:role/materialized-view-role-name"
      ]
    }
  ]
}
```

如果具體化檢視存放在 S3 資料表儲存貯體中，您也需要將下列許可新增至角色。

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3tables:PutTableMaintenanceConfiguration"
      ],
      "Resource": "arn:aws:s3tables:*:123456789012:*"
    }
  ]
}
```

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

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

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

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

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

### 檢視任務日誌
<a name="materialized-views-viewing-job-logs"></a>

若要檢視建立或重新整理具體化檢視之 AWS Glue 任務的日誌：

1. 開啟 AWS Glue 主控台。

1. 從導覽窗格中選擇任務。

1. 選取您的任務，然後選擇執行。

1. 選取特定的執行，然後選擇日誌以檢視 CloudWatch 日誌。

### 設定警示
<a name="materialized-views-setting-up-alarms"></a>

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

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

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

### 範例 AWS Glue 任務指令碼
<a name="materialized-views-example-glue-job-script"></a>

```
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

args = getResolvedOptions(sys.argv, ['JOB_NAME'])
sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# Create database and base table
spark.sql("CREATE DATABASE IF NOT EXISTS sales")
spark.sql("USE sales")

spark.sql("""
    CREATE TABLE IF NOT EXISTS orders (
        id INT,
        customer_name STRING,
        amount DECIMAL(10,2),
        order_date DATE
    )
""")

# Insert sample data
spark.sql("""
    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'))
""")

# Create materialized view
spark.sql("""
    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
""")

# Query the materialized view
print("Initial materialized view data:")
spark.sql("SELECT * FROM customer_summary").show()

# Insert additional data
spark.sql("""
    INSERT INTO orders VALUES 
        (4, 'Jane Smith', 350.00, DATE('2024-01-18')),
        (5, 'Bob Johnson', 100.25, DATE('2024-01-19'))
""")

# Refresh the materialized view
spark.sql("REFRESH MATERIALIZED VIEW customer_summary FULL")

# Query updated results
print("Updated materialized view data:")
spark.sql("SELECT * FROM customer_summary").show()

job.commit()
```

### 範例 AWS Glue Studio 筆記本
<a name="materialized-views-example-glue-studio-notebook"></a>

```
%%configure
{
    "conf": {
        "spark.sql.extensions": "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions",
        "spark.sql.catalog.glue_catalog": "org.apache.iceberg.spark.SparkCatalog",
        "spark.sql.catalog.glue_catalog.type": "glue",
        "spark.sql.catalog.glue_catalog.warehouse": "s3://amzn-s3-demo-bucket/warehouse",
        "spark.sql.catalog.glue_catalog.glue.region": "us-east-1",
        "spark.sql.catalog.glue_catalog.glue.id": "111122223333",
        "spark.sql.catalog.glue_catalog.glue.account-id": "111122223333",
        "spark.sql.catalog.glue_catalog.glue.lakeformation-enabled": "true",
        "spark.sql.defaultCatalog": "glue_catalog",
        "spark.sql.optimizer.answerQueriesWithMVs.enabled": "true",
        "spark.sql.materializedViews.metadataCache.enabled": "true"
    }
}
```

```
%%sql
CREATE DATABASE IF NOT EXISTS sales
```

```
%%sql
USE sales
```

```
%%sql
CREATE TABLE IF NOT EXISTS orders (
    id INT,
    customer_name STRING,
    amount DECIMAL(10,2),
    order_date DATE
)
```

```
%%sql
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'))
```

```
%%sql
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
```

```
%%sql
SELECT * FROM customer_summary
```

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

```
%%sql
REFRESH MATERIALIZED VIEW customer_summary FULL
```

```
%%sql
SELECT * FROM customer_summary
```

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

搭配 Glue AWS 使用具體化視觀表時，請考慮下列事項：
+ 具體化視觀表需要 AWS Glue 5.1 版或更新版本。
+ 來源資料表必須是在 Glue Data Catalog 中註冊的 Apache Iceberg AWS 資料表。啟動時不支援 Apache Hive、Apache Hudi 和 Linux Foundation Delta Lake 資料表。
+ 來源資料表必須位於與具體化視觀表相同的區域和帳戶中。
+ 所有來源資料表都必須由 管理 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 查詢不支援包含英數字元和底線以外的特殊字元的識別符。這適用於所有識別符類型，包括catalog/namespace/table名稱、資料欄和結構欄位名稱、CTEs 和別名。
+ 以 \$1\$1ivm 字首開頭的具體化檢視資料欄會保留供系統使用。Amazon 保留在未來版本中修改或移除這些資料欄的權利。
+ 具體化視觀表定義不支援 SORT BY、LIMIT、OFFSET、CLUSTER BY 和 ORDER BY 子句。
+ 不支援跨區域和跨帳戶來源資料表。
+ 檢視查詢中參考的資料表必須使用三部分命名慣例 （例如 glue\$1catalog.my\$1db.my\$1table)，因為自動重新整理不會使用預設目錄和資料庫設定。
+ 完整重新整理操作會覆寫整個資料表，並使先前的快照無法使用。
+ 具體化視觀表定義不支援非確定性函數，例如 rand() 或 current\$1timestamp()。