Amazon Web Services ブログ

AWS GlueとJDBCを使用したSAP HANAからのデータ抽出

必要なデータを検索するためにSAP GUIを果てしなくクリックすることがありませんか?そして、必要な結果を得るための単純なクエリを実行するだけのために、表をスプレッドシートに出力しなければならないときがありませんか?

私にはあります。そのため、SAPデータに簡単にアクセスして、思い通りに利用できる場所に格納したいと思っていました。

この記事では、AWS Glueを使用してSAP HANAとの接続を構成し、 Amazon S3にデータを抽出します。このソリューションにより、SAPをさまざまな分析サービスや可視化サービスに公開し、必要な結果を得ることのできる、シームレスなメカニズムを実現します。

概要

SAPからデータを抽出するために利用できるツールはいろいろとあります。ただし、それらのほとんどすべては、実装、展開、およびライセンスの取得に数か月かかります。また、これらは「一方通行のドア」のアプローチです。意思決定を行った後に元の状態に戻るのが困難です。

AWSには、“双方向のドア”という哲学があります。AWS Glue、Amazon Athena、そしてAmazon QuickSightは、AWSが提供する従量課金制のクラウドネイティブなサービスです。

  • AWS Glue – この完全マネージドの抽出、変換、およびロード (ETL)を行うサービスにより、分析用のデータを簡単に準備、やり取りできます。実装または管理するインフラストラクチャはありません。AWS Glueは、完全マネージドのスケールアウトされるApache Spark環境で、ETLジョブを実行するために必要なリソースの展開、構成、スケーリングを処理します。
  • Athena – このインタラクティブなクエリサービスにより、標準SQLを使用してS3のデータを簡単に分析できます。Athenaはサーバーレスなため、管理するインフラストラクチャはなく、実行するクエリに対してのみ料金が発生します。S3にあるデータを指定し、スキーマを定義して、標準SQLを使用してクエリの実行を開始するだけです。
  • Amazon QuickSight – この完全マネージドで高速なクラウドベースのビジネスインテリジェンスサービスにより、組織内のすべての人に洞察を簡単に提供できます。Amazon QuickSightを使用すると、ML Insightsを含むインタラクティブなダッシュボードを簡単に作成、公開できます。

ウォークスルー

この記事では、上述のAWSリソースに加えてAWS Secrets Managerを使用して、SAP HANAとの接続を構成し、データを抽出します。

前提条件

接続を構成する前に、認証情報、接続詳細、およびJDBCドライバーを安全な場所に保存する必要があります。まず、この演習用にS3バケットを作成します。

S3バケットとフォルダの作成

  1. S3コンソールから、sap-kna1というS3バケットを作成します。オブジェクトが一般公開されないように、Amazon S3 ブロックパブリックアクセスを使用します。.
  2. sap-kna1バケットを作成したら、[フォルダの作成]を選択します。
  3. [フォルダの作成]ページから、[出力]用の[フォルダの名前やプレフィックスの名前]を入力します。

これで、新しいバケットと階層を使用する準備ができました。

次に、Secrets Managerを使用して、認証情報と接続詳細を安全に保存します。

新しいシークレットの作成

  1. Secrets Managerコンソールから、[新しいシークレットを保存する][その他のシークレット]と選択します。
  2. [シークレットキー/値]タブから [行を追加]ボタンで次のパラメータごとの行を作成し、次の値を入力していきます。
    1. [db_username]として、[SAPABAP1]を入力します。 これは、主要なSAPスキーマへの読み取りアクセス権を持ち、参照する予定のテーブルに対する読み取り権限を持つHANAデータベースユーザーです。詳細については、DBAまたはSAP Basisチームと連携してください。
    2. [db_password]として、[NotMyPassword123]を入力します。これは、Secrets Managerを使用して暗号化するHANAデータベースユーザーのパスワードです。
    3. [db_url]として、[jdbc:sap://10.0.52.188:30013/?instanceNumber=00&databaseName=S4A]を入力します。MDCシステムのテナントデータベースに接続します。詳細については、DBAまたはSAP Basisチームと連携してください。
    4. [db_table]として、[KNA1]を入力します。ここでは、SAPの顧客マスターにあるKNA1データを使用します。
    5. [driver_name]として、[com.sap.db.jdbc.Driver]を入力します。 このエントリーは、AWS GlueジョブにSAP HANA JDBCドライバーを使用することを示しています。
    6. [output_bucket]として、[s3://sap-kna1/output/]を入力します。 これは、JDBCドライバーと出力ファイルを整理するために使用する上述で作成したバケットです。

    これらの値をすべて入力すると、画面は次のスクリーンショットのようになります。

    user interface for entering key value pairs

  3. ページの下部で、暗号化キーを選択します。この演習では、提供されているデフォルトキーを使用します。任意のキーを自由に使用できますが、そのキーにアクセスできることを確認してください。
  4. [次]を選択します。
  5. [シークレットの名前]として、[SAP-Connection-Info]を入力します。
  6. (オプション) 説明を入力します。
  7. [次]を選択します。
  8. シークレットはローテーションできますが、この演習では、デフォルトの[自動ローテーションを無効にする]のままにし、[次]を選択します。
  9. 次のページでは、シークレットの構成を確認し、[保存]を選択します。

次のスクリーンショットは、シークレットが正常に保存されたことを示しています。

store a new secret screen

次に、AWS GlueジョブのためのIAMロールを作成します。このIAMロールは、抽出ジョブを作成する前に作成するか、実行中に作成できます。この演習では事前に作成します。

IAMロールの作成

  1. IAMコンソールから、左側のナビゲーションペインで[ロール]を選択し、[ロールの作成]を選択します。信頼されたエンティティのロールタイプはAWSサービスである必要があるため、この記事ではAWSを選択します。
  2. [次のステップ: アクセス権限]を選択します。
  3. ポリシー名の下を検索し、次のポリシーのチェックボックスを選択します。
    1. [AWSGlueServiceRole]
    2. [SecretsManagerReadWrite] このポリシーにより、AWS GlueジョブはSecrets Managerに保存されているデータベースの認証情報にアクセスできます。このポリシーは公開されており、テスト目的でのみ使用されます。カスタムポリシーを作成して、ETLジョブで使用するシークレットのみにアクセスを絞り込みます。
    3. [AmazonS3FullAccess] このポリシーにより、AWS GlueジョブはS3に保存されているデータベースJARSにアクセスし、AWS GlueジョブのPythonスクリプトをアップロードできます。
    4. [AmazonAthenaFullAccess] このポリシーにより、Amazon QuickSightをサポートするために、AthenaがS3の抽出ファイルを読み取れるようになります。
  4. [次のステップ: 確認]を選択します。
  5. [ロール名]には、例えば、[GluePermissions]を入力します。
  6. (オプション) [ロールの説明]欄に説明を入力します。
  7. [ポリシー]の下に上述で選択した4つのポリシーがあることを確認します。
  8. [ロールの作成]を選択します。

IAMロールを作成したら、次のスクリーンショットに示すように、S3バケットにJDBCドライバーをアップロードします。この例では、SAPサポートサイトで入手できるSAP HANAドライバーを使用しています。

upload jdbc driver

ソリューションの構成

前提条件を設定したら、SAP HANAのためのAWS Glueジョブを作成します。

AWS Glueジョブの接続

  1. AWS Glueコンソールから、左側のナビゲーションペインで[データベース]の下の[接続]を選択し、[接続の追加]を選択します。
  2. [接続名]として[KNA1]を入力し、 [接続タイプ]として[JDBC]を選択します。
  3. (オプション) 説明を入力します。
  4. [次]を選択します。
  5. [JDBC URL][ユーザー名][パスワード][VPC]、そして[サブネット]に値を入力します。
  6. [セキュリティグループ]は、[default]を選択します。
  7. [次]を選択します。
  8. 接続プロパティと接続アクセスパラメータを確認し、[完了]を選択します。

次に、実際のAWS Glueジョブを作成します。

AWS Glueジョブの作成

  1. 左側のナビゲーションペインで[ETL]を選択し、[ジョブ]を選択します。
  2. [ジョブの追加]を選択します。
  3. ジョブプロパティを入力します。
    1. [名前]として、ジョブに名前をつけます (この演習では、KNA1)。
    2. [IAMロール]は、 上述で作成したIAMロールを選択します (GluePermissions)。
    3. [このジョブ実行]は、[ユーザーが作成する新しいスクリプト]を選択します。
    4. [Type]は、[Python shell]を選択します。
    5. [スクリプトファイル名]には、[KNA1]を入力します。
    6. [スクリプトが保存されているS3パス]には、上述で作成したS3バケットを指定します。
    7. [セキュリティ設定、スクリプトライブラリおよびジョブパラメータ]の下にある[依存 JARSパス]には、JDBCドライバーの格納場所を入力します。例えば、[s3://sap-kna1/ngdbc.jar]です。
    8. 他のすべてのフィールドはデフォルトのままにしておきます。
  4. [次]を選択します。
  5. [接続]の概要ページの[必要な接続]で接続[KNA1]を追加し、[ジョブを保存してスクリプトを編集]を選択します。スクリプトエディターが開きます。
  6. 空白のエディタの中で次のスクリプトを追加し、[保存]を選択します。
import sys
import boto3
import json
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.dynamicframe import DynamicFrame
from awsglue.job import Job


## @params: [JOB_NAME]
args = getResolvedOptions(sys.argv, ['JOB_NAME'])

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

# Getting DB credentials from Secrets Manager
client = boto3.client("secretsmanager", region_name="us-east-1")

get_secret_value_response = client.get_secret_value(
        SecretId="SAP-Connection-Info"
)

secret = get_secret_value_response['SecretString']
secret = json.loads(secret)

db_username = secret.get('db_username')
db_password = secret.get('db_password')
db_url = secret.get('db_url')
table_name = secret.get('db_table')
jdbc_driver_name = secret.get('driver_name')
s3_output = secret.get('output_bucket')

# Uncomment to troubleshoot the ingestion of Secrets Manager parameters
# By uncommenting, you may print secrets in plaintext!
#print "bucketname"
#print s3_output
#print "tablename"
#print table_name
#print "db username"
#print db_username
#print "db password"
#print db_password
#print "db url"
#print db_url
#print "jdbc driver name"
#print jdbc_driver_name

# Connecting to the source
df = glueContext.read.format("jdbc").option("driver", jdbc_driver_name).option("url", db_url).option("dbtable", table_name).option("user", db_username).option("password", db_password).load()

df.printSchema()
print df.count()

datasource0 = DynamicFrame.fromDF(df, glueContext, "datasource0")

# Defining mapping for the transformation
applymapping2 = ApplyMapping.apply(frame = datasource0, mappings = [("MANDT", "varchar","MANDT", "varchar"), ("KUNNR", "varchar","KUNNR", "varchar"), ("LAND1", "varchar","LAND1", "varchar"),("NAME1", "varchar","NAME1", "varchar"),("NAME2", "varchar","NAME2", "varchar"),("ORT01", "varchar","ORT01", "varchar"), ("PSTLZ", "varchar","PSTLZ", "varchar"), ("REGIO", "varchar","REGIO", "varchar"), ("SORTL", "varchar","SORTL", "varchar"), ("STRAS", "varchar","STRAS", "varchar"), ("TELF1", "varchar","TELF1", "varchar"), ("TELFX", "varchar","TELFX", "varchar"), ("XCPDK", "varchar","XCPDK", "varchar"), ("ADRNR", "varchar","ADRNR", "varchar"), ("MCOD1", "varchar","MCOD1", "varchar"), ("MCOD2", "varchar","MCOD2", "varchar"), ("MCOD3", "varchar","MCOD3", "varchar"), ("ANRED", "varchar","ANRED", "varchar"), ("AUFSD", "varchar","AUFSD", "varchar"), ("BAHNE", "varchar","BAHNE", "varchar"), ("BAHNS", "varchar","BAHNS", "varchar"), ("BBBNR", "varchar","BBBNR", "varchar"), ("BBSNR", "varchar","BBSNR", "varchar"), ("BEGRU", "varchar","BEGRU", "varchar"), ("BRSCH", "varchar","BRSCH", "varchar"), ("BUBKZ", "varchar","BUBKZ", "varchar"), ("DATLT", "varchar","DATLT", "varchar"), ("ERDAT", "varchar","ERDAT", "varchar"), ("ERNAM", "varchar","ERNAM", "varchar"), ("EXABL", "varchar","EXABL", "varchar"), ("FAKSD", "varchar","FAKSD", "varchar"), ("FISKN", "varchar","FISKN", "varchar"), ("KNAZK", "varchar","KNAZK", "varchar"), ("KNRZA", "varchar","KNRZA", "varchar"), ("KONZS", "varchar","KONZS", "varchar"), ("KTOKD", "varchar","KTOKD", "varchar"), ("KUKLA", "varchar","KUKLA", "varchar"), ("LIFNR", "varchar","LIFNR", "varchar"), ("LIFSD", "varchar","LIFSD", "varchar"), ("LOCCO", "varchar","LOCCO", "varchar"), ("LOEVM", "varchar","LOEVM", "varchar"), ("NAME3", "varchar","NAME3", "varchar"), ("NAME4", "varchar","NAME4", "varchar"), ("NIELS", "varchar","NIELS", "varchar"), ("ORT02", "varchar","ORT02", "varchar"), ("PFACH", "varchar","PFACH", "varchar"), ("PSTL2", "varchar","PSTL2", "varchar"), ("COUNC", "varchar","COUNC", "varchar"), ("CITYC", "varchar","CITYC", "varchar"), ("RPMKR", "varchar","RPMKR", "varchar"), ("SPERR", "varchar","SPERR", "varchar"), ("SPRAS", "varchar","SPRAS", "varchar"), ("STCD1", "varchar","STCD1", "varchar"), ("STCD2", "varchar","STCD2", "varchar"), ("STKZA", "varchar","STKZA", "varchar"), ("STKZU", "varchar","STKZU", "varchar"), ("TELBX", "varchar","TELBX", "varchar"), ("TELF2", "varchar","TELF2", "varchar"), ("TELTX", "varchar","TELTX", "varchar"), ("TELX1", "varchar","TELX1", "varchar"), ("LZONE", "varchar","LZONE", "varchar"), ("STCEG", "varchar","STCEG", "varchar"), ("GFORM", "varchar","GFORM", "varchar"), ("UMSAT", "varchar","UMSAT", "varchar"), ("UPTIM", "varchar","UPTIM", "varchar"), ("JMZAH", "varchar","JMZAH", "varchar"), ("UMSA1", "varchar","UMSA1", "varchar"), ("TXJCD", "varchar","TXJCD", "varchar"), ("DUEFL", "varchar","DUEFL", "varchar"), ("HZUOR", "varchar","HZUOR", "varchar"), ("UPDAT", "varchar","UPDAT", "varchar"), ("RGDATE", "varchar","RGDATE", "varchar"), ("RIC", "varchar","RIC", "varchar"), ("LEGALNAT", "varchar","LEGALNAT", "varchar"), ("/VSO/R_PALHGT", "varchar","/VSO/R_PALHGT", "varchar"), ("/VSO/R_I_NO_LYR", "varchar","/VSO/R_I_NO_LYR", "varchar"), ("/VSO/R_ULD_SIDE", "varchar","/VSO/R_ULD_SIDE", "varchar"), ("/VSO/R_LOAD_PREF", "varchar","/VSO/R_LOAD_PREF", "varchar"), ("AEDAT", "varchar","AEDAT", "varchar"), ("PSPNR", "varchar","PSPNR", "varchar"), ("J_3GTSDMON", "varchar","J_3GTSDMON", "varchar"), ("J_3GSTDIAG", "varchar","J_3GSTDIAG", "varchar"), ("J_3GTAGMON", "varchar","J_3GTAGMON", "varchar"), ("J_3GVMONAT", "varchar","J_3GVMONAT", "varchar"), ("J_3GLABRECH", "varchar","J_3GLABRECH", "varchar"), ("J_3GEMINBE", "varchar","J_3GEMINBE", "varchar"), ("J_3GFMGUE", "varchar","J_3GFMGUE", "varchar"), ("J_3GZUSCHUE", "varchar","J_3GZUSCHUE", "varchar")], transformation_ctx = "applymapping1")


resolvechoice3 = ResolveChoice.apply(frame = applymapping2, choice = "make_struct", transformation_ctx = "resolvechoice3")
dropnullfields3 = DropNullFields.apply(frame = resolvechoice3, transformation_ctx = "dropnullfields3")

# Writing to destination
datasink4 = glueContext.write_dynamic_frame.from_options(frame = dropnullfields3, connection_type = "s3", connection_options = {"path": s3_output}, format = "csv", transformation_ctx = "datasink4")

job.commit()

ETLジョブの実行

AWS Glueジョブを作成したので、次のステップはそれを実行することです。

  1. スクリプトエディタで、新しいジョブを保存したことを再確認し、[ジョブを実行]を選択します。
  2. パラメータを確認し、[ジョブの実行]を選択します。

今回が最初の実行のため、次のスクリーンショットに示すように、5〜10分間、日付と時刻の右側に[実行の保留中]のメッセージが表示される場合があります。舞台裏では、AWSはジョブを実行するためにSparkクラスターをスピンアップしています。

pending execution message

成功した実行ジョブのログは、次のスクリーンショットのようになります。

job log

もしエラーが発生した場合は、Amazon CloudWatch/aws-glue/jobs/配下から確認します。

  1. 抽出されたファイルを表示するには、上述で定義したS3出力バケットに移動し、ファイルをダウンロードして内容を確認します。

view extracted file

データの可視化

SAPからS3にデータを取得できました。エンドユーザーが自身のロジックを適用し、スプレッドシートで通常行うことを自動化できるように、コンテキスト化する方法が必要です。これを行うには、S3からAthena、およびAmazon QuickSightとの間でデータの統合を構成します。

AWS Glueデータベースの作成

  1. AWS Glueの画面で、[データベース][データベースの追加]と選択します。
  2. [データベース名]には[KNA1]を入力し、 それ以外のフィールドは空のまま、[作成]を選択します。
  3. [分類子][分類子の追加]と選択します。[分類子][KNA1]を入力し、[作成]を選択します。
  4. [テーブル]を選択し、[テーブルの追加]から[クローラーを使用してテーブルを追加]を選択します。
  5. クローラーの名前は[KNA1]とし、 [選択された分類子][KNA1]を追加します。
  6. [データストア]を選択し、抽出ファイルのための[インクルードパス]を指定します。
  7. [次]を選択します (他のデータストアは追加しません)。
  8. [既存のIAMロールを選択]を選択し、[GluePermissions]を選択します。
  9. この演習では、[オンデマンドで実行]を選択します。
  10. [データベース]は、データベース[KNA1]を選択します。
  11. [完了]を選択します。
  12. 次のページで、[今すぐ実行]を選択します。
  13. クローラーが完了したら、クローラーの右側にある[ログ]を選択して、CloudWatchでログを表示します。

Athenaでクエリの作成

  1. Athenaコンソールで、AWS Glueクローラーによって作成されたテーブルを選択します。
  2. テーブルをプレビューするには、[クエリ実行]を選択します。これにより、ユーザーは複数のデータセットに対してクエリを実行し、最小限のリフトでプレビューすることができます。

次に、これらのクエリを可視化に拡張して、データをさらに充実させます。

Amazon QuickSightでS3バケットアクセスの有効化

  1. Amazon QuickSightコンソールを開きます。
  2. Amazon QuickSightを初めて使用する場合は、[QuickSightアカウントの作成]ページが表示されます。[QuickSightアカウント名][KNA1]を入力し、[通知用のEメールアドレス]にメールアドレスを入力します。
  3. [完了し、Amazon QuickSightに移動]を選択します。
  4. 右上の[QuickSightの管理][セキュリティとアクセス権限]を選択します。
  5. [接続された製品とサービス]の下の[追加または削除する]を選択します。
  6. 次の画面の[接続された製品とサービス][Amazon S3][sap-kna1]と選択し、[バケットの選択]を選択します。.
  7. [更新]を選択してから、Amazon QuickSightアイコンを選択します。

Amazon QuickSightで可視化の作成

  1. Amazon QuickSightコンソールから、[新しい分析][新しいデータセット]と選択します。
  2. [Athena]を選択します。
  3. [新規Athenaデータソース]ページで、[データソース名][KNA1]を入力し、[データソースを作成]を選択します。
  4. [テーブルの選択]ページで、[データベース: 複数のテーブルを含みます。][KNA1]を選択します。[テーブル: 可視化できるデータを含みます。]には、[出力]を選択し、[選択]を選択します。
  5. [迅速に分析するためにSPICEにインポート][可視化]と選択します。インポートが完了したというメッセージが表示されます。

import complete

Amazon QuickSightのドラッグアンドドロップ機能により、S3とAthenaを使用して持ち込まれたフィールドから可視化を構成できるようになりました。

quick sight visualization

結論

この記事では、AWS Glueを使用してSAP HANAとの接続を構成し、S3にデータを抽出する方法を説明しました。これにより、SAPをさまざまな分析サービスや可視化サービスに公開し、必要な結果を得ることのできる、シームレスなメカニズムを実現します。データをスプレッドシートに出力するために、SAPのトランザクションコードSE16を使用する必要はなくなりました。データを取り扱うには別のツールにアップロードするだけで済みます。

SAPにHANAのライセンスモデルを問い合わせて、データを抽出するときにHANA内でサポート可能な機能を使用していいかを確認してください。

翻訳はPartner SA 河原が担当しました。原文はこちらです。