エキサイト株式会社 エンジニアのあはれん です。
弊社では、アプリケーションのデータベースとしてはAmazon RDS for Oracleを利用し、 データ分析にAmazon Redshiftを使っています。
Amazon RDS for Oracleデータ(データストア)からAmazon Redshift(データターゲット)にデータを転送するため、AWS Glueを利用しています。
今回は、AWS Glueを使ってデータを転送する際に発生した問題とその対処方法について説明します。
問題
AWS Glue ジョブを実行時に以下のエラーが発生しました。
pyspark.sql.utils.IllegalArgumentException: Oracle identifier cannot be more than 30 characters.
「Oracleの識別子(テーブル名)が30文字を超えている」というエラーです。
Oracle 12cR1以前は30文字以内という仕様になっていましたが、Oracle 12cR1以降は128文字まで利用可能になっています。 弊社で利用しているOracleは12cR1以降のものでしたので、アプリケーションで使っている時は128文字でも利用できていました。
この件をAWSのサポートセンターに相談したところ、 2022年3月時点では、 GlueのJDBCドライバーの接続種別(connectionType)にOracleを指定した場合、 Glue サービス側で当該エラーを出力している状況となっており、利用者側から回避することができないという回答をいただきました。
対処方法として、SparkのDataFrameとしてOracle テーブルの情報を取得する方法を提案いただきました。
これまでは、GlueのJDBCドライバーを利用して設定したデータカタログからOracleテーブルの情報を取得していましたが、 SparkのDataFrameとしてOracle テーブルの情報を取得することにしました。
対処方法
df = spark.read \ .format("jdbc") \ .option("url", "[JDBC データストアのURL]") \ .option("dbtable", "[テーブル名]") \ .option("user", "[データベースのユーザ名]") \ .option("password", "[データベースのパスワード]") \ .load()
SparkのDataFrameの取得方法は上記のようになります。 詳細は以下のドキュメントを参照ください。
JDBC データストアのURLについてAWS公式が、データベースエンジンごとの構文を紹介しています。
Oracleの場合は以下の構文パターンになります。
jdbc:oracle:thin://@host:port/service_name
jdbc:oracle:thin://@host:port:SID
SparkのDataFrameとしてデータを取得後は、AWS Glueで利用されているDynamicFrameに変換します。
DynamicFrame.fromDF([変換するDataFrame],[GlueContextクラスオブジェクト],[結果の DynamicFrame の名前])
DynamicFrameに変換後は、Glueで自動生成されてるスクリプトと同じ処理を行うことができます。
コード例
import sys from awsglue.context import GlueContext from awsglue.dynamicframe import DynamicFrame from awsglue.job import Job from awsglue.transforms import * from awsglue.utils import getResolvedOptions from pyspark.context import SparkContext sc = SparkContext() glueContext = GlueContext(sc) spark = glueContext.spark_session job = Job(glueContext) job.init(args['JOB_NAME'], args) # SparkのDataFrameとしてOracle テーブルの情報を取得する df = spark.read \ .format("jdbc") \ .option("url", "[JDBC データストアのURL]") \ .option("dbtable", "[テーブル名]") \ .option("user", "[データベースのユーザ名]") \ .option("password", "[データベースのパスワード]") \ .load() # DataFrameをDynamicFrameに変換 datasource0 = DynamicFrame.fromDF(df, glueContext, 'datasource0') // 以降はGlueで自動生成されてるスクリプトと同じ処理で問題ない applymapping1 = ApplyMapping.apply(....
その他
ジョブのバージョンや利用言語について
Glue version :Glue 2.0 - Support spark 2.4, Scala 2, Python 3 Language: Python 3
Glueの接続
AWS Glue ジョブはAWS Glue 接続を使用して特定の種類のデータストアにアクセスします。 今回の場合も、Amazon RDS for Oracleデータ(データストア)にアクセスするために設定しました。設定方法に関しては以下を参照ください。
最後に
同じエラーが出た方のお役に少しでもなれたらと思います。 最後まで読んでいただきありがとうございます。
エキサイトではデザイナー、フロントエンジニア、バックエンドエンジニア、アプリエンジニアを絶賛募集しております! 興味がありましたらご連絡ください。