Talendのジョブ設計パターンとベストプラクティス(第4部)

Talendのジョブ設計とベストプラクティスという取り組みは、新たな岐路にさしかかっています。役立つコンテンツの提供という私の努力は、1つの形になりました。好評をいただいているブログシリーズ(まだお読みになっていない方は、第1部第2部第3部をぜひご覧ください)、Technical Boot Campプレゼンテーション(参加いただいた方、ありがとうございます)、コンテンツの直接配信から、社内から組織の変革を求める声が生まれています。

この記事では引き続き、ジョブ設計パターンとベストプラクティスについて解説を進めます。まず、シンプルでありながら見逃されがちな事実をお伝えしましょう。それは、Talendは、Javaコードジェネレーターであり、開発者ガイドラインを確立することで、ジョブ設計パターンによって生成されるJavaコードを強化および合理化できる、という点です。これは明白な事実ですが、この概念に基づいてキャンバスを操作し、緻密なジョブ設計を行ってクリーンなJavaコードを生成することが、最善の結果への近道です。私はこれを、「成功主導のプロジェクト」と呼んでいます。

成功主導のTalendプロジェクト

Talendジョブの作成は、非常に簡単な場合と、非常に複雑な場合があります。実装を成功へと導く秘訣は、良い習慣と必要な規範を採用し、適合させることにあります。

このシリーズの冒頭で「基本的指針」でお伝えしたように、私の目標は、ベストプラクティスに関する自由なディスカッションを行い、便利なジョブ設計パターンを確立することにあります。ジョブ設計および親子オーケストレーションは、ほとんどのユースケースにメリットをもたらします。そして、再利用可能なコードを含めることで、プロジェクト全体の成功が加速されます。もちろん、どの方法を選択するかは皆さんの自由ですが、一貫性の維持だけは必ず留意してください。

データベース開発ライフサイクル(DDLC)

このシリーズではジョブ設計のみを扱ってきましたが、データについてはどうでしょうか。ジョブで処理するのはデータであり、ほとんどのデータはデータベースに格納されています。データベースにベストプラクティスは必要でしょうか。これは、修辞的な質問でしょうか。データモデル(スキーマ)は時間と共に変化しますから、データベース設計にもライフサイクルがあるのは当然です。

データベースは進化するので、開発者はこれに対応しなければなりません。われわれはSDLCプロセスを採用していますから、データベース開発ライフサイクルの必要性も簡単に理解できるはずです。環境(DEV/TEST/PROD)がどうであれ、データベースのサポートは必要です。

  • 新規インストール - スキーマの現在のバージョンに基づきます
  • アップグレード - アップグレードによりデータベースオブジェクトを削除/作成/変更します
  • データ移行 - 破壊的な「アップグレード」(テーブルの分割など)を行います

データベースライフサイクルと、それがジョブ設計にもたらす影響を理解することは、非常に重要です。ここで鍵となるのが、データベースモデルのバージョン管理です。規定された設計プロセスに従い、設計をグラフィック化し、「データ辞書」または「グロッサリー」を作成して変更履歴を追跡します。このトピックについては、ブログの別の記事でさらに詳しく解説する予定ですので、お楽しみに。それまでは、データベースモデルを作成する際には次のプロセスを検討してください。高度な規範ではありますが、効果的です。

さらなるジョブ設計のベストプラクティス

では、すぐに役立つジョブ設計のパターンとベストプラクティスをさらにご紹介しましょう。よく使用するTalend機能やあまり使用頻度の高くない機能を詳しく解説します。ぜひ参考にしてください。

さらに検討すべき8つのベストプラクティス:

tMapルックアップ

ご存知のように、tMapの必須コンポーネントは強力な変換機能を備えているため、Tatlendジョブで広く使用されています。

tMapコンポーネントの最も一般的な用途は、ソース入力からターゲット出力へのデータフロースキーマのマッピングです。これは、シンプルな処理です。ソースとターゲットに複数のスキーマデータフローを使用することもできるため、データフローの複雑な結合や分割にも対応できます。また、変換式を使用すれば、どの入力データをどのような方法でダウンストリームに分割するかを制御できます。tMapコンポーネント内の式は、ソースとターゲットのスキーマに適用できます。また、tMapコンポーネントで定義した変数を使用することも可能です。以上の操作方法は、「Talend Components Reference Guide」で詳しく解説されています。使用する際には、「大いなる力には大きな責任が伴う」ことを念頭に置いてください。

tMapコンポーネントには、ソースデータフローと結合するルックアップを使用するという素晴らしい用途もあります。tMapコンポーネントに適用できるルックアップに物理的な上限はありませんが、実際には配慮すべき項目があります。

この基本的な例をご覧ください。ソースとルックアップという2つの行が生成されます。実行時には、まずルックアップデータが生成され、次にソースデータが処理されます。

ルックアップデータの結合が[Load Once]に設定されているため、レコードすべてがメモリにロードされ、ソースデータの結果セットに対して処理が行われます。これはデフォルト設定であり、結合で優れたパフォーマンスを発揮でき、非常に効率的です。

また、数百万のルックアップ行と数十のカラムをロードする場合には、かなりのメモリ容量が必要になります。数百万行のルックアップを複数回実行する場合はどうでしょうか。メモリ容量はどの程度必要でしょうか。レコード数が多い場合やカラム数が数百にのぼる場合には、ルックアップを慎重に検討してください。

では、メモリとパフォーマンスのトレードオフについて考えてみましょう。ルックアップには、3つのモデルがあります。

  • Load Once(一括ロード)- 該当するすべてのレコードをメモリに読み込みます
  • Reload at each Row(行ごとに再ロード)- ソースレコードごとに該当する行を読み込みます
  • Reload at each Row(行ごとに再ロード - キャッシュ)- ソースレコードごとに該当する行を読み込み、キャッシュに格納します

ソースとの結合を目的にメモリにロードされたルックアップデータは、非常に高速です。ただし、メモリに制限があってルックアップデータを大量に読み込めない場合や、すべてのロックアップデータのロードが必要ないユースケースでは、「Reload at each Row(行ごとに再ロード)」を使用してください。このルックアップモデルを使用する際には、コツを理解する必要があります。

まず、tMapコンポーネント内で、ルックアップモードを「Read at each Row」に変更します。下の領域が広がるので、ルックアップを実行する「Key(s)」を入力します。キーを追加すると、tMapコンポーネント外部でグローバル変数が定義されます。

ルックアップコンポーネントでは、(datatype)globalMap.get(“key”)関数をSQL構文の「WHERE」句で指定します。これにより、tMapで定義して保存されたキー値が、ルックアップデータセットに適用されます。以上で、ルックアップでソースから各レコードを抽出する設定は完了です。

次に、ルックアップを効率化する方法を説明します。

グローバル変数

グローバル変数」の定義と使用には複数の側面があります。開発者がグローバル変数を作成し、Talendジョブで使用するとき、この変数は「コンテキスト変数」と呼ばれます。また、「組み込み」(ジョブに対してローカル)と呼ばれることや、「プロジェクトリポジトリ」内でコンテキストグループとして使用し、複数のジョブで再利用されることもあります。

いずれにおいても、これらはすべて「グローバル変数」であり、その値は実行時に決定され、変数を定義するジョブ内であればどこででも使用できます
context.varnameをコンポーネント、式、トリガーに組み込むときには、必ずグローバル変数が使用されます。よく使用される変数を「参照プロジェクト」に配置することで、複数のプロジェクトへのアクセスを最大化できます。

Talendが提供するtSetGlobalVarコンポーネントとtGlobalVarLoadコンポーネントを使用して、「グローバル変数」を実行時に定義、格納、使用できます。 tSetGlobalVarコンポーネントは、「コンテキスト変数」を使用する場合と同様に、キーと値のペアをジョブ内に格納することで、的確な制御(エラー処理など)を実行します。この例では、単一のMAX(date)値を取得し、その後のSQLクエリーで使用することにより、別のレコードセット取得をフィルター処理しています。

グローバル変数へのアクセスには、(datatype)globalMap.get(“key”)関数をSQLの「WHERE」句で使用します。非常に効果的な関数なので、使用方法をよく理解しておいてください。

tGlobalVarLoadコンポーネントは、tSetGlobalVarコンポーネントを使用できないビッグデータジョブで、同様の機能を提供します。例では、値を集約し、その後の読み取りで使用することにより、返すレコードを評価しています。

このトピックでは、さらにお話しすべきことがあります。「システムグローバル変数」は、ジョブ内で使用でき、コンポーネント自体が値を決定します。このシリーズのエラー処理に関するベストプラクティスでは、CHILD_RETURN_CODEとERROR_MESSAGEについて説明しましたが、これもシステムグローバル変数の1つです。システムグローバル変数は、コンポーネントの実行によって値が設定されると、すぐに使用可能になります。使用できるシステム変数はコンポーネントによって異なります。以下に、一部を示します。

  • ERROR_MESSAGE / DIE_MESSAGE / WARN_MESSAGE
  • CHILD_RETURN_CODE / DIE_CODE / WARN_CODE / CHILD_EXCEPTION_STACK
  • NB_LINE / NB_LINE_OK / NB_LINE_REJECT
  • NB_LINE_UPDATED / NB_LINE_INSERTED / NB_LINE_DELETED
  • global.projectName / global.jobName(システムレベルの変数であり、用途は明らかです)

コンテキストのロード

コンテキストグループ」は、非常に再利用性の高いジョブ設計を的確にサポートします。ただし、コンテキスト変数のデフォルト値を外部で維持したい場合など、さらなる柔軟性が必要なケースもあります。これには、ファイルやデータベースに格納する方法で対応できます。値を外部でも維持できる機能があれば非常に便利であり、セキュリティ上の課題も解決できる可能性があります。ここで威力を発揮するのが、tContextLoadコンポーネントです。

上記の例は、実行時に、コンテキスト変数を初期化するジョブを設計する簡単な方法を示しています。ロードに使用する外部ファイルには、キーと値のペアがカンマ区切りで格納されており、このファイルを読み込むことで、ジョブ内で定義されているコンテキスト変数の値が上書きされます。この場合、データベース接続の詳細をロードすることで、必要な接続情報が設定されます。若干のエラー処理制御も可能であり、「Die on Error(エラー強制終了)」でジョブをプログラム的に即時終了できます。もちろん、tContextLoadコンポーネントではデータベースクエリーを簡単に使用できるので、この方法を採用しているユーザーも存在します。

これに対応するのが、tContextDumpコンポーネントです。このコンポーネントは、コンテキスト変数の現在値をファイルまたはデータベースに書き出します。適応性の高いジョブ設計を作成する際に便利なコンポーネントです。

ダイナミックスキーマの使用

私のところには、ダイナミックスキーマに対応したジョブを作成する方法に関する質問が数多く寄せられます。実際、ダイナミックスキーマにはさまざまなユースケースがあるため、質問の答えもさまざまです。最も一般的なのは、テーブルが数多く存在し、そのデータを異なるデータベースシステムのテーブル間で移動するユースケース(OracleからMS SQL Serverなど)でしょう。このようなデータ移動を実行するジョブは簡単に作成でき、時間もかかりませんが、テーブルごとにジョブを作成する方法は現実的ではありません。たとえば、テーブルが何百個もある場合、各テーブルにジョブを1つずつ作成しなくてはなりません。残念ながら、これはTalendの制限なのですが、この問題は2つのジョブで解決できます。1つのジョブでデータをダンプし、もう1つのジョブでデータをロードしてください。

このサンプルジョブでは、3つの接続を確立しています。最初の2つでTableリストとColumnリストを取得し、3番目で実際のデータを取得します。次に、tSetDynamicSchemaコンポーネントを使用して、データを固定長フラットファイルに読み書きします(DUMPプロセス)。そして、3番目の接続を除いた同じジョブで固定長ファイルを読み取り、ターゲットのデータストアに書き込みます(LOADプロセス)。

このシナリオを使用する場合には、ホストデータベースの内部処理について少し理解しておく必要があります。Oracle、MS SQL Server、MySQLなど、ほとんどのデータベースには、「情報スキーマ」というシステムテーブルが存在します。ここには、テーブルとそのカラムを含め、データベースに関するオブジェクトメタデータが格納されています。以下のクエリーは、TAC v6.1 MySQLデータベースからテーブル/カラムリストを抽出します(私のお気に入りのSQL構文フォーマットです)。

一般的にこのデータベースは保護されているので、接続の認証情報に「SELECT」権限を設定してください。

このサンプルでは、tJavaFlexコンポーネントを使用して、検出されたテーブル名を反復しています。個々の「テーブル名」を保存し、「コントロールブレイク」フラグを確立します。次に、検出されたテーブルごとに反復し、格納されているカラムのリストを取得します。カラム長がnullの場合の調整を行うと、保存された「ダイナミックスキーマ」が完成します。テーブル名が変わったら条件付き「IF」で「コントロールブレイク」フラグをチェックし、現在のテーブルでDUMPプロセスを開始します。

動的SQLコンポーネント

動的コードは非常に効果的です。Talendでは、複数の方法で実装できます。上記のジョブ設計では、テーブルリストとカラムリストをデータベースから直接取得するアプローチを使用しました。Talendでは、同じ処理を実行できるホストシステム固有のコンポーネントが提供されています。t{DB}TableListコンポーネントとt{DB}ColumnListコンポーネント({DB}はホストコンポーネント名)は、「情報スキーマ」メタデータに直接アクセスします。アクセス対象に関する情報は必要ありません。このコンポーネントは、上記の例のDUMP/LOADプロセスで使用することができるのですが、何が違うのでしょうか。

SQLクエリーでは、データの取得と保存ではなく、他のデータベース操作が必要な場合もあります。このような要件を満たすのが、t{DB}Rowコンポーネントとt{DB}SPコンポーネントです。最初のコンポーネントは、「DROP TABLE」など、結果セットを返さないほぼすべてのSQLクエリーを実行できます。もう1つでは、「ストアドプロシージャー」を実行できます。

そして、t{DB}LastInsertIdコンポーネントも重要です。データベース出力コンポーネントから、最後に入力された「ID」を取得します。状況によっては、非常に便利です。

CDC

「TalendはCDC(変更データキャプチャー)をサポートしますか」という質問もよく寄せられます。もちろん、TalendはCDCをサポートしており、ホストデータベースシステムに直結した「Publish/Subscribe」メカニズムを使用します。ただし、すべてのデータベースシステムがCDCをサポートするわけではありませんから、注意が必要です。以下は、TalendジョブでのCDCサポートを示す「現時点での」リストです。

次の3つのCDCモードを使用できます。

  • トリガー(デフォルト)- 挿入、更新、削除を追跡するDBホストトリガーを使用します
  • REDO/アーカイブログ - Oracle 11以前のみで使用できます
  • XStream - Oracle 12とOCIのみで使用できます

最も使用されるのは「トリガー」モードなので、このアーキテクチャを見てみましょう。

CDCのプロセス、設定、Studioやホストデータベースシステムシステムとの使用については、Talendユーザーガイドの第11章で包括的に説明されています。概念は非常にわかりやすいものの、かなりのセットアップが必要になります。要件、CDCモード、ジョブ設計パラメーターを事前によく把握し、開発者ガイドラインにまとめておいてください。

確立されたCDC環境は、ダウンストリームターゲット(一般的にはデータウェアハウス)を最新の状態に更新する堅牢なメカニズムとなります。Talendジョブでt{DB}CDCコンポーネントを使用することで、前回の抽出以降に変更されたデータを抽出できます。CDCの設定と稼働には時間と手間がかかりますが、非常に役立つ機能です。

カスタムコンポーネント

Talendのパレットでは1,000を優に超えるコンポーネントが提供されていますが、さまざまな理由から、独自コンポーネントの作成が必要になります。Talendの開発者の多くは、特殊機能をカスタムコンポーネント内にカプセル化します。また、コンポーネントの作成とプロダクト化を行うケースや、先頃最新になったTalend Exchange公開し、無償アクセスを提供するケースもあります。パレット上にないコンポーネントは、Talend Exchangeで検索すると見つかるかもしれません。この操作には「Talend Forge」アカウントが必要ですが、すでにアカウントを作成されている方もいるでしょう。

まず、カスタムコンポーネントを格納するディレクトリを適切に設定します。[Preferences]メニューから、すべての開発者が共有する場所を指定します。[Apply]をクリックし、[OK]をクリックしてください。

メニューバーの[Exchange]リンクでは、コンポーネントの選択とインストールを実行できます。この機能を初めて使用する際には、[Always run in Background]を選択し、[Run in Background]ボタンをクリックしてください。大量のオブジェクトリストのロードに時間がかかるため、この操作が必要になります。オブジェクトリストから目的のオブジェクトを表示およびダウンロードできます。ダウンロードが完了したら、[Downloaded Extensions]をクリックすることで、コンポーネントはインストールされ、Studioで使用可能になります。処理が完了すると、コンポーネントは[Installed]と表示され、パレットで使用できるようになります。

インストールしたコンポーネントと関連ファイルが見つからない場合には、次の2つの場所を確認してください。

{talend}/studio/plugins/org.talend.designer.components.exchange{v}{talend}/studio/plugins/org.talend.designer.components.localprovider{v}

カスタムコンポーネントを作成する場合には、Studioでパースペクティブを「コンポーネントデザイナー」に切り替えます。ほとんどのカスタムコンポーネントが「JavaJet」を使用します。これは、「Eclipse IDE」のJavaコードをカプセル化するためのファイル拡張です。初めて使用する方は、「カスタムコンポーネントの作成方法」に関するチュートリアルをご利用ください。少し古いものの(2013年頃)、必要な基本情報が解説されています。また、サードパーティによるチュートリアルも提供されています(一部は、上記のチュートリアルでも紹介されています。Talendの事例:カスタムコンポーネントがお勧めです)。「カスタムコンポーネント」の作成方法については、インターネット検索も役立ちます。

JobScript API

Talendジョブの作成には、「デザイナー」を使用してJavaコードを生成するのが一般的ですが、Talendジョブは自動生成も可能です。まず、ジョブを1つ開いてください。キャンバスの下に、[Designer]、[Code]、[Jobscript]という3つのタブがありますね。[Code]タブは、生成したJavaコードの検査に使用したことがある方も多いでしょう。では、[Jobscript]タブを使用したことはありますか。クリックしたことがあるとしても、そこで何を実行できるのか、わからなかったのではないでしょうか。このタブには、ジョブ設計を示すスクリプトが表示されます。次にこのタブをクリックしたときには、内容をじっくり見てください。ジョブ設計に関する情報が表示されているはずです。

たとえば、ジョブ設計に関するメタデータを作成してどこかに保存し、(作成した)プロセスエンジンで実行します。これにより、適切なフォーマットのJobScriptを生成し、キー要素を調整して複数の組み合わせを作ったとします。

Project Repository」の[Code] > [Routines]セクションにある[Job Scripts]フォルダーを見てください。まず、JobScriptを新規作成します(「test_JobScript」という名前を付けました)。ジョブを開いて[JobScript]タブの内容をコピーし、JobScriptファイルに貼り付けて保存します。JbScriptを右クリックし、[Generate Job]を選択します。すると、[Job Designs]フォルダーに新たに生成されたジョブが表示されます。この機能は、さまざまな用途に活用できます。

まとめ

Talendジョブ設計の作成と保守に関するベストプラクティスは以上です。ベストプラクティスはこれだけではありませんが、それについては皆さんがコミュニティで参照してください。一連のベストプラクティス(全部で32)では、Talendを使用するプロジェクトを成功へと導く幅広く深い情報を提供できたのではないかと思います。

次回の記事では、ベストプラクティスを従来型のユースケースに適用する方法について解説します。テクノロジーの活用、確立された手法、成果を実現できるソリューションをご紹介し、ベストプラクティスとジョブ設計パターンを使用すべき領域を説明します。お楽しみに。

Talendを使う準備はできていますか?