

# 连接到 SAP OData
<a name="connecting-to-data-sap-odata"></a>

SAP OData 是一种标准 Web 协议，用于使用 ABAP（高级业务应用程序编程）查询和更新 SAP 中存在的数据，应用和构建 HTTP 等 Web 技术，以提供对来自各种外部应用程序、平台和设备的信息的访问权限。通过该产品，您可以访问所需的一切，以帮助您与 SAP 系统、应用程序或数据无缝集成。

**Topics**
+ [AWS Glue 对 SAP OData 的支持](sap-odata-support.md)
+ [创建 连接](sap-odata-creating-connections.md)
+ [创建 SAP OData 作业](sap-odata-creating-job.md)
+ [写入 SAP OData](sap-odata-writing.md)
+ [使用 SAP OData 状态管理脚本](sap-odata-state-management-script.md)
+ [非 ODP 实体的分区](sap-odata-non-odp-entities-partitioning.md)
+ [SAP OData 连接选项](sap-odata-connection-options.md)
+ [SAP OData 实体和字段详细信息](sap-odata-entity-field-details.md)

# AWS Glue 对 SAP OData 的支持
<a name="sap-odata-support"></a>

AWS Glue 对 SAP OData 的支持如下：

**是否支持作为来源？**  
是。您可以使用 AWS Glue ETL 作业查询 SAP OData 中的数据。

**是否支持作为目标？**  
是。您可以使用 AWS Glue ETL 作业将记录写入 SAP OData。

**支持的 SAP OData API 版本**  
支持以下 SAP OData API 版本：
+ 2.0

**支持的来源**  
支持以下来源：
+ ODP（操作数据供应）来源：
  + BW 提取器（数据源）
  + CDS 视图
  + SLT
+ 非 ODP 来源，例如：
  + CDS 视图服务
  + 基于 RFC 的服务
  + 自定义 ABAP 服务

**支持的 SAP 组件**  
以下是最低要求：
+ 您必须启用目录服务才能进行服务发现。
  + 在 SAP 系统的 SAP 网关中配置要提取的操作数据供应（ODP）数据来源。
  + **OData V2.0**：可以通过事务 `/IWFND/MAINT_SERVICE` 在 SAP 网关中启用 OData V2.0 目录服务。
  + 通过事务 `/IWFND/MAINT_SERVICE` 在 SAP 网关中启用 OData V2.0 服务。
  + 您的 SAP OData 服务必须支持客户端分页/查询选项，例如 `$top` 和 `$skip`。该服务还必须支持系统查询选项 `$count`。
  + 您必须为 SAP 中的用户提供所需的授权，才能使用 SAP OData 服务发现这些服务并提取数据。请参阅 SAP 提供的安全文档。
+ 如果要使用 OAuth 2.0 作为授权机制，则必须为 OData 服务启用 OAuth 2.0，并按照 SAP 文档注册 OAuth 客户端。
+ 要基于 ODP 数据来源生成 OData 服务，必须将 SAP Gateway Foundation 安装在本地的 ERP/BW 堆栈中或中心配置中。
  + 对于您的 ERP/BW 应用程序，SAP NetWeaver AS ABAP 堆栈必须为 7.50 SP02 或更高版本。
  + 对于中心系统（SAP 网关），中心系统的 SAP NetWeaver AS ABAP 必须为 7.50 SP01 或更高版本才能进行远程中心设置。
+ 对于非 ODP 来源，您的 SAP NetWeaver 堆栈版本必须为 7.40 SP02 或更高版本。

**支持的身份验证方法**  
支持以下身份验证方法：
+ 基本身份验证
+ OAuth 2.0

# 先决条件
<a name="sap-odata-prerequisites"></a>

在使用 SAP OData 连接启动 AWS Glue 作业从 SAP OData 提取数据之前，请完成以下先决条件：
+ 必须在 SAP 系统中激活相关的 SAP OData 服务，确保数据来源可供使用。如果未激活 OData 服务，则将无法访问 Glue 作业或从 SAP 提取数据。
+ 必须在 SAP 中配置适当的身份验证机制，例如基本（自定义）身份验证或 OAuth 2.0，以确保 AWS Glue 作业能够成功与 SAP OData 服务建立连接。
+ 配置 IAM 策略以授予 AWS Glue 作业相应的权限，使其能够访问 SAP、Secrets Manager 以及流程中涉及的其他 AWS 资源。
+ 如果 SAP 系统托管在私有网络中，则必须配置 VPC 连接，以确保 AWS Glue 作业可以安全地与 SAP 通信，而不会通过公共互联网暴露敏感数据。

AWS Secrets Manager 可用于安全存储 SAP 凭证等敏感信息，AWS Glue 作业可以在运行时动态检索这些信息。通过这种方法，无需对凭证进行硬编码，从而增强了安全性和灵活性。

以下先决条件提供了有关如何设置每个组件以实现 AWS Glue 与 SAP OData 之间顺利集成的分步指导。

**Topics**
+ [SAP OData 激活](sap-odata-activation.md)
+ [IAM 策略](sap-odata-configuring-iam-permissions.md)
+ [连接/VPC 连接](sap-odata-connectivity-vpc-connection.md)
+ [SAP 身份验证](sap-odata-authentication.md)
+ [用于存储身份验证密钥的 AWS Secrets Manager](sap-odata-aws-secret-manager-auth-secret.md)

# SAP OData 激活
<a name="sap-odata-activation"></a>

完成 SAP OData 连接的以下步骤：

## ODP 源
<a name="sap-odata-odp-sources"></a>

必须满足以下要求，然后才能从 ODP 提供程序传输数据：
+ 您有一个 SAP NetWeaver AS ABAP 实例。
+ 您的 SAP NetWeaver 实例包含一个要从其传输数据的 ODP 提供程序。ODP 提供程序包括：
  + SAP 数据源（事务代码 RSO2）
  + SAP 核心数据服务 ABAP CDS 视图
  + SAP BW 或 SAP BW/4HANA 系统（InfoObject、DataStore 对象）
  + 通过 SAP Landscape Replication Server（SAP SLT）从 SAP 源系统实时复制表和数据库视图
  + 基于 SAP ABAP 的来源中的 SAP HANA 信息视图
+ 您的 SAP NetWeaver 实例有 SAP Gateway Foundation 组件。
+ 您已创建从 ODP 提供程序提取数据的 OData 服务。要创建 OData 服务，请使用 SAP Gateway Service Builder。要访问您的 ODP 数据，Amazon AppFlow 将使用 OData API 调用此服务。有关更多信息，请参阅 SAP BW/4HANA 文档中的 [Generating a Service for Extracting ODP Data via OData](https://help.sap.com/docs/SAP_BPC_VERSION_BW4HANA/dd104a87ab9249968e6279e61378ff66/69b481859ef34bab9cc7d449e6fff7b6.html?version=11.0)。
+ 要基于 ODP 数据来源生成 OData 服务，必须将 SAP Gateway Foundation 安装在本地的 ERP/BW 堆栈中或中心配置中。
  + 对于您的 ERP/BW 应用程序，SAP NetWeaver AS ABAP 堆栈必须为 7.50 SP02 或更高版本。
  + 对于中心系统（SAP 网关），中心系统的 SAP NetWeaver AS ABAP 必须为 7.50 SP01 或更高版本才能进行远程中心设置。

## 非 ODP 源
<a name="sap-odata-non-odp-sources"></a>
+ 您的 SAP NetWeaver 堆栈版本必须为 7.40 SP02 或更高版本。
+ 您必须启用目录服务才能进行服务发现。
  + **OData V2.0**：可以通过事务 `/IWFND/MAINT_SERVICE` 在 SAP 网关中启用 OData V2.0 目录服务
+ 您的 SAP OData 服务必须支持客户端分页/查询选项，例如 `$top` 和 `$skip`。该服务还必须支持系统查询选项 `$count`。
+ 对于 OAuth 2.0，您必须为 OData 服务启用 OAuth 2.0 并根据 SAP 文档注册 OAuth 客户端，并设置授权重定向 URL，如下所示：
  + `https://<region>.console.aws.amazon.com/gluestudio/oauth`，`<region>` 替换为 AWS Glue 正在运行的区域，例如：us-east-1。
  + 必须启用安全设置才能通过 HTTPS 进行连接。
+ 您必须为 SAP 中的用户提供所需的授权，才能使用 SAP OData 服务发现这些服务并提取数据。请参阅 SAP 提供的安全文档。

# IAM 策略
<a name="sap-odata-configuring-iam-permissions"></a>

## 包含创建和使用连接的 API 操作的策略
<a name="sap-odata-policies-api-operations"></a>

以下示例策略描述了创建和使用连接所需的 AWS IAM 权限。如果您要创建新角色，请创建包含以下内容的策略：

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "glue:ListConnectionTypes",
        "glue:DescribeConnectionType",
        "glue:RefreshOAuth2Tokens",
        "glue:ListEntities",
        "glue:DescribeEntity"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:DescribeSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:PutSecretValue"
      ],
      "Resource": "*"
    }
  ]
}
```

------

该角色必须授予作业所用所有资源的访问权限，例如 Amazon S3。如果您不想使用上述方法，也可以使用以下托管 IAM 策略。
+ [AWSGlueServiceRole](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole) – 授予对各种 AWS Glue 进程代表您运行所需的资源的访问权限。这些资源包括 AWS Glue、Amazon S3、IAM、CloudWatch Logs 和 Amazon EC2。如果您遵循此策略中指定的资源的命名约定，则 AWS Glue 进程具有所需的权限。此策略通常附加到在定义爬网程序、作业和开发终端节点时指定的角色。
+ [AWSGlueConsoleFullAccess](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/AWSGlueConsoleFullAccess)：当策略所附加到的身份使用 AWS 管理控制台时，授予对 AWS Glue 资源的完全访问权限。如果遵循此策略中指定的资源的命名约定，则用户具有完全控制台功能。此策略通常附加到 AWS Glue 控制台的用户。
+ [SecretsManagerReadWrite](https://console.aws.amazon.com/iam/home#policies/arn:aws:iam::aws:policy/SecretsManagerReadWrite)：提供通过 AWS 管理控制台访问 AWS Secrets Manager 的读/写访问权限。注意：此项不包括 IAM 操作，因此如果需要轮换配置，请与 `IAMFullAccess` 结合使用。

**配置 VPC 所需的 IAM 策略/权限**

使用 VPC 连接创建 AWS Glue 连接时需要以下 IAM 权限。有关更多详细信息，请参阅[为 AWS Glue 创建 IAM 策略](https://docs.aws.amazon.com/glue/latest/dg/create-service-policy.html)。

------
#### [ JSON ]

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateNetworkInterface",
        "ec2:DeleteNetworkInterface",
        "ec2:DescribeNetworkInterfaces"
      ],
      "Resource": [
        "*"
      ]
    }
  ]
}
```

------

# 连接/VPC 连接
<a name="sap-odata-connectivity-vpc-connection"></a>

VPC 连接的步骤：

1. 使用现有 VPC 连接或按照 [Amazon VPC 文档](https://docs.aws.amazon.com/vpc/latest/userguide/create-vpc.html)创建新连接。

1. 确保您拥有将流量路由到互联网的 NAT 网关。

1. 选择 VPC 端点作为 Amazon S3 网关以创建连接。

1. 启用 DNS 解析和 DNS 主机名以使用 AWS 提供的 DNS 服务。

1. 前往已创建的 VPC，为 STS、AWS Glue、Secret Manager 等不同的服务添加必要的端点。

   1. 选择 Create Endpoint（创建端点）。

   1. 对于“服务类别”，选择 AWS 服务。

   1. 对于“服务名称”，选择要连接到的服务。

   1. 选择 VPC 并启用 DNS 名称。

   1. VPC 连接所需的 VCP 端点：

      1. [STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sts_vpc_endpoint_create.html)

      1. [AWS Glue](https://docs.aws.amazon.com/glue/latest/dg/vpc-interface-endpoints.html)

      1. [Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/vpc-endpoint-overview.html)

## 安全组配置
<a name="sap-odata-security-group-configuration"></a>

安全组必须允许来自 AWS Glue VPC 的流量进入其侦听端口，以使 AWS Glue 能与其连接。最好尽可能限制源 IP 地址的范围。

AWS Glue 需要特殊的安全组以允许来自自身的所有入站流量。您可以创建自引用规则，允许来自安全组的所有流量。您可以修改现有安全组并将该安全组指定为源。

开放来自 URL 端点（NLB 或 SAP 实例）HTTPS 端口的通信。

## 连接选项
<a name="sap-odata-connectivity-options"></a>
+ 与内部和外部 NLB 的 HTTPS 连接，来自证书颁发机构（CA）的 SSL 证书，非自签名 SSL 证书
+ 与 SAP 实例的 HTTPS 连接，来自证书颁发机构（CA）的 SSL 证书，非自签名 SSL 证书

# SAP 身份验证
<a name="sap-odata-authentication"></a>

SAP 连接器支持自定义（这是 SAP 基本身份验证）和 OAUTH 身份验证方法。

## 自定义身份验证
<a name="sap-odata-custom-authentication"></a>

AWS Glue 支持自定义（基本身份验证）作为与 SAP 系统建立连接的方法，允许使用用户名和密码进行安全访问。此身份验证类型非常适合自动化场景，因为它允许预先使用用户名和密码以及 SAP OData 实例中特定用户的权限。AWS Glue 能够使用用户名和密码对 SAP OData API 进行身份验证。在 AWS Glue 中，基本授权是作为自定义授权实现的。

有关基本身份验证流程的 SAP OData 公开文档，请参阅 [HTTP Basic Authentication](https://help.sap.com/docs/SAP_SUCCESSFACTORS_PLATFORM/d599f15995d348a1b45ba5603e2aba9b/5c8bca0af1654b05a83193b2922dcee2.html)。

## OAuth 2.0 身份验证
<a name="sap-odata-oauth-2.0-authentication"></a>

AWS Glue 还支持 OAuth 2.0 作为与 SAP 系统建立连接的安全身份验证机制。这可以实现无缝集成，同时确保符合现代身份验证标准并提高数据访问的安全性。

## AUTHORIZATION\$1CODE 授权类型
<a name="sap-odata-authentication-code-grant-type"></a>

授权类型决定了 AWS Glue 如何与 SAP OData 通信以请求访问您的数据。SAP OData 仅支持 `AUTHORIZATION_CODE` 授权类型。此授权类型被视为“三足型”OAuth，因为它依赖于将用户重定向到第三方授权服务器来对用户进行身份验证。它用于通过 AWS Glue 控制台创建连接。

用户仍然可以选择在 SAP OData 中创建自己的关联应用程序，并在通过 AWS Glue 控制台创建连接时提供自己的客户端 ID 和客户端密钥。在这种情况下，他们仍会重定向到 SAP OData，以便登录并授权 AWS Glue 访问其资源。

此授权类型会生成刷新令牌和访问令牌。访问令牌的有效期很短，可以通过刷新令牌在不需要用户干预的情况下自动刷新。

有关为授权码 OAuth 流创建关联应用程序的公共 SAP OData 文档，请参阅 [Authentication Using OAuth 2.0](https://help.sap.com/docs/ABAP_PLATFORM_NEW/e815bb97839a4d83be6c4fca48ee5777/2e5104fd87ff452b9acb247bd02b9f9e.html)。

# 用于存储身份验证密钥的 AWS Secrets Manager
<a name="sap-odata-aws-secret-manager-auth-secret"></a>

您需要将 SAP OData 连接密钥存储在 AWS Secrets Manager 中，按照 [IAM 策略](sap-odata-configuring-iam-permissions.md)一节中的规定配置必要的检索权限，并在创建连接时使用该权限。

使用 AWS Secrets Manager 的 AWS 管理控制台为您的 SAP 源创建密钥。有关更多信息，请参阅 [Create an AWS Secrets Manager secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html)。AWS Secrets Manager 中的详细信息应包含以下代码中的元素。

## 自定义身份验证密钥
<a name="sap-odata-custom-auth-secret"></a>

您需要输入您的 SAP 系统用户名来代替 *<your SAP username>*，输入其密码来代替 *<your SAP username password>*，以及输入 True 或 False。在这种情况下，将 `basicAuthDisableSSO` 设置为 `true` 会禁用基本身份验证请求的单点登录（SSO），要求每个请求都提供显式用户凭证。相反，将其设置为 `false` 将允许使用现有的 SSO 会话（如果有）。

```
{
   "basicAuthUsername": "<your SAP username>",
   "basicAuthPassword": "<your SAP username password>",
   "basicAuthDisableSSO": "<True/False>",
   "customAuthenticationType": "CustomBasicAuth"
}
```

## OAuth 2.0 密钥
<a name="sap-odata-oauth-2.0-secret"></a>

如果使用 OAuth 2.0 作为身份验证机制，则 AWS Secrets Manager 中的密钥应具有以下格式的**用户托管客户端应用程序 ClientId**。您需要输入 SAP 客户端密钥来代替 <your client secret>。

```
{"USER_MANAGED_CLIENT_APPLICATION_CLIENT_SECRET": "<your client secret>"
}
```

# 创建 连接
<a name="sap-odata-creating-connections"></a>

配置 SAP OData 连接：

1. 登录 AWS 管理控制台，打开 [AWS Glue 控制台](https://console.aws.amazon.com/glue)。在 AWS Glue Studio 中，按照以下步骤创建连接：

   1. 在左侧面板上单击“数据连接”。

   1. 单击“创建连接”。

   1. 在**选择数据来源**中选择 **SAP OData**

   1. 提供您要连接的 SAP OData 实例的**应用程序主机 URL**。对于非 VPC 连接，必须能够通过公共互联网访问此应用程序主机 url。

   1. 提供您要连接的 SAP OData 实例的**应用程序服务路径**。这与目录服务路径相同。例如：`/sap/opu/odata/iwfnd/catalogservice;v=2`。AWS Glue 不接受特定的对象路径。

   1. 提供您要连接的 SAP OData 实例的**客户端编号**。可接受的值为 [001-999]。示例：010

   1. 提供您要连接的 SAP OData 实例的**端口号**。示例：443

   1. 提供您要连接的 SAP OData 实例的**登录语言**。示例：EN

   1. 选择 AWS Glue 可以代入并拥有如 [IAM 策略](sap-odata-configuring-iam-permissions.md)一节所述权限的 AWS IAM 角色。

   1. 从下拉列表中选择想要在 AWS Glue 中用于此连接的**身份验证类型**：OAUTH2 或自定义

      1. 自定义：选择您按照[用于存储身份验证密钥的 AWS Secrets Manager](sap-odata-aws-secret-manager-auth-secret.md) 一节中指定的方式创建的密钥。

      1. OAuth 2.0：仅在 OAuth 2.0 中输入以下内容：

         1. 在**用户托管客户端应用程序 ClientId** 下，输入您的客户端 ID。

         1. 您在[用于存储身份验证密钥的 AWS Secrets Manager](sap-odata-aws-secret-manager-auth-secret.md) 一节中创建的 AWS Secrets Manager 中的 `USER_MANAGED_CLIENT_APPLICATION_CLIENT_SECRET`（您的客户端密钥）。

         1. 在**授权码 URL** 下，输入您的授权码 URL。

         1. 在**授权令牌 URL** 下，输入您的授权令牌 URL。

         1. 在 **OAuth 范围**下，输入用空格分隔的 OAuth 范围。示例：`/IWFND/SG_MED_CATALOG_0002 ZAPI_SALES_ORDER_SRV_0001`

   1. 如果要使用网络，请选择网络选项。有关更多详细信息，请参阅 [连接/VPC 连接](sap-odata-connectivity-vpc-connection.md)。

1. 向与您的 AWS Glue 作业关联的 IAM 角色授予读取 `secretName` 的权限。有关详细信息，请参阅[IAM 策略](sap-odata-configuring-iam-permissions.md)。

1. 选择**测试连接**并测试您的连接。如果连接测试通过，则请单击“下一步”，输入您的连接名称并保存连接。如果您选择了网络选项（VPC），则测试连接功能不可用。

# 创建 SAP OData 作业
<a name="sap-odata-creating-job"></a>

请参阅[使用 AWS Glue Studio 构建可视化 ETL 作业](https://docs.aws.amazon.com/glue/latest/dg/author-job-glue.html)

# 操作数据供应（ODP）来源
<a name="sap-odata-operational-data-provisioning-sources"></a>

操作数据供应（ODP）提供了一个技术基础架构，可用于支持各种目标应用程序的数据提取和复制，并支持这些场景中的增量机制。对于增量过程，来自源（ODP 提供程序）的数据使用更新过程自动写入到增量队列（操作增量队列 – ODQ），或者使用提取器接口传递到增量队列。ODP 提供程序可以是数据源（提取器）、ABAP 核心数据服务视图（ABAP CDS 视图）、SAP BW 或 SAP BW/4HANA、SAP Landscape Transformation Replication Server（SLT）和 SAP HANA 信息视图（计算视图）。目标应用程序（称为 ODQ“订阅用户”或更普遍的“ODP 使用者”）从增量队列中检索数据并继续处理数据。

## 完全加载
<a name="sap-odata-full-load"></a>

在 SAP OData 和 ODP 实体环境中，**完全加载**是指通过一次操作从 ODP 实体提取所有可用数据的过程。此操作从源系统检索完整的数据集，确保目标系统拥有实体数据全面且最新的副本。完全加载通常用于不支持增量加载的源或需要刷新目标系统的情况。

**示例**

在创建 DynamicFrame 时，您可以将 `ENABLE_CDC` 标志显式设置为 false。注意：默认情况下 `ENABLE_CDC` 为 false；如果您不想初始化增量队列，则无需发送此标志或将其设置为 true。不将此标志设置为 true 将导致完全加载提取。

```
sapodata_df = glueContext.create_dynamic_frame.from_options(
    connection_type="SAPOData",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "ENABLE_CDC": "false"
    }, transformation_ctx=key)
```

## 增量加载
<a name="sap-odata-incremental-load"></a>

ODP（操作数据供应）实体环境中的**增量加载**涉及仅提取源系统中自上次数据提取以来新的或更改的数据（增量），从而避免对已经处理的记录进行预处理。这种方法显著提高了效率，减少了数据传输量，增强了性能，确保了系统之间的有效同步，并最大限度地缩短了处理时间，对于经常变化的大型数据集尤其如此。

# 基于增量令牌的增量传输
<a name="sap-odata-incremental-transfers"></a>

要使用更改数据捕获（CDC）为支持 ODP 的实体启用增量传输，请执行以下步骤：

1. 在脚本模式下创建增量传输作业。

1. 创建 DataFrame 或 Glue DynamicFrame 时，您需要传递选项 `"ENABLE_CDC": "True"`。此选项可确保您将收到来自 SAP 的增量令牌，该令牌可用于随后检索更改的数据。

增量令牌将在数据帧最后一行的 DELTA\$1TOKEN 列中显示。此令牌可用作后续调用中的连接器选项来逐步检索下一组数据。

**示例**
+ 创建 DynamicFrame 时，我们将 `ENABLE_CDC` 标志设置为 `true`。注意：默认情况下 `ENABLE_CDC` 为 `false`；如果您不想初始化增量队列，则无需发送此标志或将其设置为 true。不将此标志设置为 true 将导致完全加载提取。

  ```
  sapodata_df = glueContext.create_dynamic_frame.from_options(
      connection_type="SAPOData",
      connection_options={
          "connectionName": "connectionName",
          "ENTITY_NAME": "entityName",
          "ENABLE_CDC": "true"
      }, transformation_ctx=key)
  
  # Extract the delta token from the last row of the DELTA_TOKEN column
  delta_token_1 = your_logic_to_extract_delta_token(sapodata_df) # e.g., D20241029164449_000370000
  ```
+ 提取的增量令牌可作为检索新事件的选项传递。

  ```
  sapodata_df_2 = glueContext.create_dynamic_frame.from_options(
      connection_type="SAPOData",
      connection_options={
          "connectionName": "connectionName",
          "ENTITY_NAME": "entityName",
          // passing the delta token retrieved in the last run
          "DELTA_TOKEN": delta_token_1
      } , transformation_ctx=key)
  
  # Extract the new delta token for the next run
  delta_token_2 = your_logic_to_extract_delta_token(sapodata_df_2)
  ```

请注意，存在 `DELTA_TOKEN` 的最后一条记录不是来自源的事务记录，而仅用于传递增量令牌值。

除 `DELTA_TOKEN` 外，数据帧的每一行都会返回以下字段。
+ **GLUE\$1FETCH\$1SQ**：此项是一个序列字段，根据记录接收顺序从 EPOC 时间戳生成，并且每个记录都是唯一的。如果您需要了解或确定源系统中的更改顺序，则可以使用此项。此字段仅对启用 ODP 的实体显示。
+ **DML\$1STATUS**：对于从源新插入和更新的所有记录，此项将显示 `UPDATED`；对于从源删除的记录，此项将显示 `DELETED`。

有关如何通过示例管理状态和重用增量令牌来检索已更改记录的更多详细信息，请参阅[使用 SAP OData 状态管理脚本](sap-odata-state-management-script.md)一节。

## 增量令牌失效
<a name="sap-odata-invalidation"></a>

增量令牌与服务集合和用户相关联。如果为同一个服务集合和用户启动新的初始拉取且 `“ENABLE_CDC” : “true”`，则 SAP OData 服务将使因之前初始化发出的所有之前的增量令牌失效。使用过期的增量令牌调用连接器将导致异常：

`Could not open data access via extraction API RODPS_REPL_ODP_OPEN` 

# OData 服务（非 ODP 来源）
<a name="sap-odata-non-odp-services"></a>

## 完全加载
<a name="sap-odata-non-odp-full-load"></a>

对于非 ODP（操作数据供应）系统，**完全加载**包括从源系统提取整个数据集并将其加载到目标系统中。由于非 ODP 系统本质上不支持增量等高级数据提取机制，因此该过程很简单，但可能会占用大量资源，具体取决于数据的大小。

## 增量加载
<a name="sap-odata-non-odp-incremental-load"></a>

对于不支持 **ODP（操作数据供应）**的系统或实体，可以通过实施基于时间戳的机制来跟踪和提取更改，从而手动管理增量数据传输。

**基于时间戳的增量传输**

对于未启用 ODP 的实体（或启用 ODP 但未使用 ENABLE\$1CDC 标志的实体），我们可以在连接器中使用 `filteringExpression` 选项来指示我们要检索数据的 `datetime` 间隔。此方法依赖于数据中的时间戳字段，该字段表示每条记录的上次创建/修改时间。

**示例**

检索 2024-01-01T00:00:00.000 之后更改的记录

```
sapodata_df = glueContext.create_dynamic_frame.from_options(
    connection_type="SAPOData",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "filteringExpression": "LastChangeDateTime >= 2024-01-01T00:00:00.000"
    }, transformation_ctx=key)
```

注意：在此示例中，`LastChangeDateTime` 是表示每条记录上次修改时间的字段。实际字段名称可能会因具体的 SAP OData 实体而有所不同。

要在后续运行中获得新的数据子集，您需要使用新时间戳更新 `filteringExpression`。通常，此项将是先前检索到的数据的最大时间戳值。

**示例**

```
max_timestamp = get_max_timestamp(sapodata_df)  # Function to get the max timestamp from the previous run
next_filtering_expression = f"LastChangeDateTime > {max_timestamp}"

# Use this next_filtering_expression in your next run
```

在下一节中，我们将提供一种自动化的方法来管理这些基于时间戳的增量传输，从而无需在两次运行之间手动更新筛选表达式。

# 写入 SAP OData
<a name="sap-odata-writing"></a>

 本节说明如何使用 SAP OData 的 AWS Glue 连接器将数据写入您的 SAP OData 服务。

**先决条件**
+ 访问 SAP OData 服务
+ 您要写入的 SAP OData 实体集对象。您将需要对象名称。
+ 有效的 SAP OData 凭证和有效的连接
+ [IAM 策略](https://docs.aws.amazon.com/glue/latest/dg/sap-odata-configuring-iam-permissions.html)中描述的适当权限

SAP OData 连接器支持两种写入操作：
+ INSERT
+ UPDATE

在使用 UPDATE 写入操作时，必须提供 ID\$1FIELD\$1NAMES 参数以指定记录的外部 ID 字段。

**示例：**

```
sapodata_write = glueContext.write_dynamic_frame.from_options(
    frame=frameToWrite,
    connection_type="sapodata",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "WRITE_OPERATION": "INSERT"
    }
```

# 使用 SAP OData 状态管理脚本
<a name="sap-odata-state-management-script"></a>

要在 AWS Glue 作业中使用 SAP OData 状态管理脚本，请执行以下步骤：
+ 从公共 Amazon S3 存储桶下载状态管理脚本：`s3://aws-blogs-artifacts-public/artifacts/BDB-4789/sap_odata_state_management.zip `。
+ 将脚本上传到您的 AWS Glue 作业有权访问的 Amazon S3 存储桶。
+ 在 AWS Glue 作业中引用脚本：创建或更新 AWS Glue 作业时，传递引用 Amazon S3 存储桶中脚本路径的 `'--extra-py-files'` 选项。例如：`--extra-py-files s3://your-bucket/path/to/sap_odata_state_management.py`
+ 在 AWS Glue 作业脚本中导入和使用状态管理库。

## 基于增量令牌的增量传输示例
<a name="sap-odata-delta-token-incremental-transfer"></a>

以下是有关如何使用状态管理脚本进行基于增量令牌的增量传输的示例：

```
from sap_odata_state_management import StateManagerFactory, StateManagerType, StateType

# Initialize the state manager
state_manager = StateManagerFactory.create_manager(
    manager_type=StateManagerType.JOB_TAG,
    state_type=StateType.DELTA_TOKEN,
    options={
        "job_name": args['JOB_NAME'],
        "logger": logger
    }
)

# Get connector options (including delta token if available)
key = "SAPODataNode"
connector_options = state_manager.get_connector_options(key)

# Use the connector options in your Glue job
df = glueContext.create_dynamic_frame.from_options(
    connection_type="SAPOData",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "ENABLE_CDC": "true",
        **connector_options
    }
)

# Process your data here...

# Update the state after processing
state_manager.update_state(key, sapodata_df.toDF())
```

## 基于时间戳的增量传输示例
<a name="sap-odata-timestamp-incremental-transfer"></a>

以下是有关如何使用状态管理脚本进行基于增量令牌的增量传输的示例：

```
from sap_odata_state_management import StateManagerFactory, StateManagerType, StateType

# Initialize the state manager
state_manager = StateManagerFactory.create_manager(
    manager_type=StateManagerType.JOB_TAG,
    state_type=StateType.DELTA_TOKEN,
    options={
        "job_name": args['JOB_NAME'],
        "logger": logger
    }
)

# Get connector options (including delta token if available)
key = "SAPODataNode"
connector_options = state_manager.get_connector_options(key)

# Use the connector options in your Glue job
df = glueContext.create_dynamic_frame.from_options(
    connection_type="SAPOData",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "entityName",
        "ENABLE_CDC": "true",
        **connector_options
    }
)

# Process your data here...

# Update the state after processing
state_manager.update_state(key, sapodata_df.toDF())
```

在这两个示例中，状态管理脚本处理在两次作业运行之间存储状态（增量令牌或时间戳）的复杂性。它会在获取连接器选项时自动检索上次已知状态，并在处理后更新状态，从而确保每次运行的作业仅处理新的或更改的数据。

# 非 ODP 实体的分区
<a name="sap-odata-non-odp-entities-partitioning"></a>

在 Apache Spark 中，分区是指在集群中的 Worker 节点之间划分和分配数据以实现并行处理的方式。每个分区都是一个逻辑数据块，可以通过任务独立处理。分区是 Spark 中的一个基本概念，它直接影响性能、可扩展性和资源利用率。AWS Glue 作业使用 Spark 的分区机制将数据集划分为较小的块（分区），从而可以在集群的 Worker 节点上并行处理。请注意，分区不适用于 ODP 实体。

有关更多详细信息，请参阅 [AWS Glue Spark 和 PySpark 作业](https://docs.aws.amazon.com/glue/latest/dg/spark_and_pyspark.html)。

**先决条件**

您要从中读取内容的 SAP OData 对象。您将需要对象/实体集名称。例如：` /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder `。

**示例**

```
sapodata_read = glueContext.create_dynamic_frame.from_options(
    connection_type="SAPOData",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "/sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder"
    }, transformation_ctx=key)
```

## 对查询进行分区
<a name="sap-odata-partitioning-queries"></a>

### 基于字段的分区
<a name="sap-odata-field-based-partitioning"></a>

如果您想在 Spark 中利用并发，可以提供其他 Spark 选项：`PARTITION_FIELD`、`LOWER_BOUND`、`UPPER_BOUND` 和 `NUM_PARTITIONS`。使用这些参数，原始查询将被拆分为 `NUM_PARTITIONS` 个子查询，这些子查询可以由 Spark 任务同时执行。整数、日期和日期时间字段支持 SAP OData 连接器中基于字段的分区。
+ `PARTITION_FIELD`：用于对查询进行分区的字段的名称。
+ `LOWER_BOUND`：所选分区字段的包含下限值。

   对于任何数据类型为 DateTime 的字段，接受 Spark SQL 查询中使用的 Spark 时间戳格式。

  有效值示例：`"2000-01-01T00:00:00.000Z"`
+ `UPPER_BOUND`：所选分区字段的排除上限值。
+ `NUM_PARTITIONS`：分区的数量。
+ `PARTITION_BY`：要执行的类型分区；如果是基于字段的分区，则传递 `FIELD`。

**示例**

```
sapodata= glueContext.create_dynamic_frame.from_options(
    connection_type="sapodata",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "/sap/opu/odata/sap/SEPM_HCM_SCENARIO_SRV/EmployeeSet",
        "PARTITION_FIELD": "validStartDate"
        "LOWER_BOUND": "2000-01-01T00:00:00.000Z"
        "UPPER_BOUND": "2020-01-01T00:00:00.000Z"
        "NUM_PARTITIONS": "10",
        "PARTITION_BY": "FIELD"
    }, transformation_ctx=key)
```

### 基于记录的分区
<a name="sap-odata-record-based-partitioning"></a>

原始查询将被拆分为 `NUM_PARTITIONS` 个子查询，这些子查询可以由 Spark 任务同时执行。

只有非 ODP 实体支持基于记录的分区，因为 ODP 实体中的分页通过下一个令牌/跳过令牌支持。
+ `PARTITION_BY`：要执行的类型分区。如果是基于记录的分区，则传递 `COUNT`。

**示例**

```
sapodata= glueContext.create_dynamic_frame.from_options(
    connection_type="sapodata",
    connection_options={
        "connectionName": "connectionName",
        "ENTITY_NAME": "/sap/opu/odata/sap/SEPM_HCM_SCENARIO_SRV/EmployeeSet",
        "NUM_PARTITIONS": "10",
        "PARTITION_BY": "COUNT"
    }, transformation_ctx=key)
```

# 限制/标注
<a name="sap-odata-limitations"></a>
+ 由于分页使用跳过令牌/增量令牌处理，ODP 实体与基于记录的分区不兼容。因此，对于基于记录的分区，无论用户输入什么，maxConcurrency 的默认值都设置为“null”。
+ 当同时应用限制和分区时，限制优先于分区。

# SAP OData 连接选项
<a name="sap-odata-connection-options"></a>

以下是 SAP OData 的连接选项：
+ `ENTITY_NAME`（字符串）：（必填）用于读取。SAP OData 中对象的名称。

  例如：/sap/opu/odata/sap/API\$1SALES\$1ORDER\$1SRV/A\$1SalesOrder
+ `API_VERSION`（字符串）：（可选）用于读取。您想要使用的 SAP OData Rest API 版本。示例：2.0。
+ `SELECTED_FIELDS`（列表<字符串>）–默认：empty(SELECT \$1)。用于读取。您想要为对象选择的列。

  例如：SalesOrder
+ `FILTER_PREDICATE`（字符串）– 默认：空。用于读取。应采用 Spark SQL 格式。

  例如：`SalesOrder = "10"`
+ `QUERY`（字符串）– 默认：空。用于读取。完整的 Spark SQL 查询。

  例如：`SELECT * FROM /sap/opu/odata/sap/API_SALES_ORDER_SRV/A_SalesOrder`
+ `PARTITION_FIELD`（字符串）– 用于读取。用于分区查询的字段。

  例如：`ValidStartDate`
+ `LOWER_BOUND`（字符串）– 用于读取。所选分区字段的包含下限值。

  例如：`"2000-01-01T00:00:00.000Z"`
+ `UPPER_BOUND`（字符串）– 用于读取。所选分区字段的排除上限值。

  例如：`"2024-01-01T00:00:00.000Z"`
+ `NUM_PARTITIONS`（整数）– 默认：1。用于读取。要读取的分区数。
+ `INSTANCE_URL`（字符串）：SAP 实例应用程序主机 URL。

  例如：`https://example-externaldata.sierra.aws.dev`
+ `SERVICE_PATH`（字符串）：SAP 实例应用程序服务路径。

  例如：`/sap/opu/odata/iwfnd/catalogservice;v=2`
+ `CLIENT_NUMBER`（字符串）：SAP 实例应用程序客户端编号。

  例如：100
+ `PORT_NUMBER`（字符串）：默认值：SAP 实例应用程序端口号。

  例如：443
+ `LOGON_LANGUAGE`（字符串）：SAP 实例应用程序登录语言。

  例如：`EN`
+ `ENABLE_CDC`（字符串）：定义是否在启用 CDC（即跟踪更改）的情况下运行作业。

  例如：`True/False`
+ `DELTA_TOKEN`（字符串）：根据提供的有效增量令牌运行增量数据拉取。

  例如：`D20241107043437_000463000`
+ `PAGE_SIZE`（整数）：定义查询记录的页面大小。默认页面大小为 50000。指定页面大小后，SAP 在每次 API 调用时仅返回定义的记录数，而不是整个数据集。连接器仍将提供记录总数，并使用您指定的页面大小处理分页。如果您需要更大的页面大小，则可以选择不超过 500000（即允许的最大值）的任何值。任何超过 500000 的指定页面大小都将忽略。而系统将使用允许的最大页面大小。您可以通过添加带有所需值的连接选项 `PAGE_SIZE` 在 AWS Glue Studio UI 中指定页面大小。

  例如：`20000`

# SAP OData 实体和字段详细信息
<a name="sap-odata-entity-field-details"></a>

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/glue/latest/dg/sap-odata-entity-field-details.html)