

# 通过 AWS Glue 使用实体化视图
<a name="materialized-views"></a>

AWS Glue 版本 5.1 及更高版本支持在 AWS Glue Data Catalog 中创建和管理 Apache Iceberg 实体化视图。实体化视图是一种托管表，该表以 Apache Iceberg 格式存储 SQL 查询预先计算的结果，并随着基础源表的更改而增量更新。可以使用实体化视图来简化数据转换管道并提高复杂分析工作负载的查询性能。

使用 AWS Glue 中的 Spark 创建实体化视图时，视图定义和元数据存储在 AWS Glue Data Catalog 中。预先计算的结果以 Apache Iceberg 表的形式，存储在您的账户中的 Amazon S3 表类数据存储服务存储桶或 Amazon S3 通用存储桶中。AWS Glue Data Catalog 使用托管的计算基础设施自动监控源表并刷新实体化视图。

**Topics**
+ [实体化视图如何与 AWS Glue 配合使用](#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)

## 实体化视图如何与 AWS Glue 配合使用
<a name="materialized-views-how-they-work"></a>

通过 Apache Spark 在 AWS Glue 作业和 AWS Glue Studio 笔记本中对 Iceberg 的支持，实体化视图与 AWS Glue 集成。将 Spark 会话配置为使用 AWS Glue Data Catalog 时，可以使用标准 SQL 语法创建实体化视图。当实体化视图提供更好的性能时，Spark 优化器可以自动重写查询进而使用这些视图，从而无需手动修改应用程序代码。

AWS Glue Data Catalog 处理实体化视图维护的所有操作方面，包括：
+ 使用 Apache Iceberg 的元数据层检测源表中的更改
+ 使用托管的 Spark 计算计划和执行刷新操作
+ 根据数据更改确定是执行完全刷新还是增量刷新
+ 以 Apache Iceberg 格式存储预先计算的结果，便于多引擎访问

可以使用与普通表相同的 Spark SQL 接口从 AWS Glue 中查询实体化视图。也可以从其他服务访问预先计算的数据，包括 Amazon Athena 和 Amazon Redshift。

## 先决条件
<a name="materialized-views-prerequisites"></a>

要在 AWS Glue 中使用实体化视图，需要：
+  账户
+ AWS Glue 版本 5.1 或更高版本
+ 在 AWS Glue Data Catalog 中注册的 Apache Iceberg 格式的源表
+ 为源表和目标数据库配置的 AWS Lake Formation 权限
+ 通过 AWS Lake Formation 注册的 S3 表类数据存储服务存储桶或 S3 通用存储桶，用于存储实体化视图数据
+ 有权访问 AWS Glue Data Catalog 和 Amazon S3 的 IAM 角色

## 将 Spark 配置为使用实体化视图
<a name="materialized-views-configuring-spark"></a>

要在 AWS Glue 中创建和管理实体化视图，请使用所需的 Iceberg 扩展和目录设置来配置 Spark 会话。根据使用的是 AWS Glue 作业还是 AWS Glue Studio 笔记本，配置方法会有所不同。

### 配置 AWS Glue 作业
<a name="materialized-views-configuring-glue-jobs"></a>

创建或更新 AWS Glue 作业时，添加以下配置参数作为作业参数：

#### 对于 S3 表类数据存储服务存储桶
<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 magic 命令配置 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>

可以在 AWS Glue 作业或笔记本中使用 CREATE MATERIALIZED VIEW SQL 语句创建实体化视图。视图定义将转换逻辑指定为引用一个或多个源表的 SQL 查询。

### 在 AWS Glue 作业中创建基本实体化视图
<a name="materialized-views-creating-basic-glue-jobs"></a>

以下示例演示如何在 AWS Glue 作业脚本中创建实体化视图，在视图定义中使用具有三部分命名约定的完全限定表名：

```
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
""")
```

### 在 AWS Glue Studio 笔记本中创建实体化视图
<a name="materialized-views-creating-glue-studio-notebooks"></a>

在 AWS Glue Studio 笔记本中，可以使用 %%sql magic 命令来创建实体化视图，在视图定义中使用具有三部分命名约定的完全限定表名：

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

创建实体化视图后，可以像在 AWS Glue 作业或笔记本中使用标准 SQL SELECT 语句一样查询该视图。

### 在 AWS Glue 作业中查询
<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>

可以使用两种方法刷新实体化视图：完全刷新或增量刷新。完全刷新会根据所有基表数据重新计算整个实体化视图，而增量刷新仅处理自上次刷新以来发生更改的数据。

### 在 AWS Glue 作业中手动进行完全刷新
<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()
```

### 在 AWS Glue 作业中手动进行增量刷新
<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 magic 命令：

```
%%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")
```

在 AWS Glue 作业日志中搜索以下消息：

```
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")
```

此命令从 AWS Glue Data Catalog 中移除实体化视图定义，并从 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 在执行自动刷新操作时担任此角色。如果定义者角色失去对源表的访问权限，则在恢复权限之前，刷新操作将失败。

### AWS Glue 作业的 IAM 权限
<a name="materialized-views-iam-permissions-glue-jobs"></a>

AWS Glue 作业的 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>

以下示例演示了在 AWS Glue 中创建和使用实体化视图的完整工作流程。

### 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>

在使用 AWS Glue 实体化视图时，请注意以下事项：
+ 实体化视图需要 AWS Glue 版本 5.1 或更高版本。
+ 源表必须是在 AWS Glue Data Catalog 中注册的 Apache Iceberg 表。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 查询中不支持包含除字母数字字符和下划线之外的特殊字符的标识符。这适用于所有标识符类型，包括目录/命名空间/表名、列和结构字段名、CTE 和别名。
+ 以 \$1\$1ivm 前缀开头的实体化视图列保留供系统使用。Amazon 保留在未来版本中修改或移除这些列的权利。
+ 实体化视图定义中不支持 SORT BY、LIMIT、OFFSET、CLUSTER BY 和 ORDER BY 子句。
+ 不支持跨区域和跨账户源表。
+ 视图查询中引用的表必须使用三部分命名约定（例如，glue\$1catalog.my\$1db.my\$1table），因为自动刷新不使用默认的目录和数据库设置。
+ 完全刷新操作会覆盖整个表，并使以前的快照不可用。
+ 实体化视图定义中不支持诸如 as rand() 或 current\$1timestamp() 之类的非确定性函数。