はじめに
Hello World!!
前回もそうでしたが、記事の間隔が空きました。まぁいろいろありますが、平穏無事とはいえないまでも、なんとか生きています。
さて、今回は備忘録的な記事です。
Talendのダイナミックスキーマについて、いろいろと触れる機会があったのでまとめてみようと思います。
本記事の概要
本記事は、以下の2点を実現した際の備忘録です。
- 一つのジョブを使いまわし、インターフェース仕様の異なる複数種類のファイルを処理したい
- 連携ファイルから、特定のカラムのみを抜き出して連携したい
ダイナミックスキーマ is 何?
軽く説明します。
公式ドキュメントの記載
公式ドキュメントでは、以下のように記載されています。
Talend Studioでは、ジョブ内の特定のコンポーネントのスキーマにダイナミックカラムを追加できます。ダイナミックカラムは、スキーマ内の唯一のカラムで構成されている場合もあれば、既知のカラム(スキーマの最後のカラムなど)の後に追加されることもあります。
ダイナミックカラムでは、スキーマで定義されていないカラムが取得されます。そのため、ジョブの設計時は不明なソースカラムが実行時には認知され、スキーマに追加されます。それによってジョブデザインが非常に容易になり、多くのカラムで一対一によるマッピングが可能になります。ダイナミックカラムには用途が数多くあります。たとえば、開発者はデータ移行タスクで、カラムを個別にマッピングせずにデータのカラムを他の場所にコピーできます。
スキーマエディタで設定された静的オブジェクト(データパターンやデフォルト値など)はダイナミックカラムには考慮されないので、注意が必要です。
公式ドキュメント
要はどういうことよ
正直、この文字列だけでは何を言っているかわかりにくいので、具体例を挙げてみます。
現在インターフェース仕様の策定中で、"id"だけが確定、その他の仕様はfixしていない状況。現時点で"id"と"name"のカラムを持った以下のようなcsvファイルがあるとします (※例としてcsvファイルを挙げましたが、input側はDBでも何でもいいです)。
id,name
1, Kouda
2, Shimizu
3, Ohtani
これをtFileInputDelimitedのコンポーネントで読むとき、通常、スキーマはこんな感じで設定します。
この設定で上記のcsvファイルを読み込めば、問題なく処理が行えます。以下はtLogRowで読み込んだ内容を表示した結果です。
.--+--------.
| tLogRow_1 |
|=-+-------=|
|id|name |
|=-+-------=|
|1 | Kouda |
|2 | Shimizu|
|3 | Ohtani |
'--+--------'
さて、ここでインターフェースの仕様変更が発生し、以下のように名字と名前を別に持つ仕様になったとします。
id, first_name, last_name
1, Mitsuo, Kouda
2, Yusuke, Shimizu
3, Kazuki, Ohtani
これを、上記のスキーマで読み込ませようとしても、3カラム目の"last_name"のカラムが保持できず、2カラム目の"first_name"はカラム名の変更が反映されません。その結果、以下のような表示になります。
.--+-------.
|tLogRow_1 |
|=-+------=|
|id|name |
|=-+------=|
|1 | Mitsuo|
|2 | Yusuke|
|3 | Kazuki|
'--+-------'
このため、カラムを正しく保持するためにはジョブの改修が必要になります
正直なところ、インターフェース仕様が頻繁に変わる場合に毎回ジョブの改修が発生するのは面倒ですよね。必要なカラムだけあればいい、みたいなケースであればなおさら。
そこで使うのがダイナミックスキーマです。
スキーマの設定時、以下のように設定します。
こうしたうえで、先ほどの変更後のcsvファイルを読み込ませると
.--+------------------.
| tLogRow_1 |
|=-+-----------------=|
|id|dynamic |
|=-+-----------------=|
|1 | Mitsuo - Kouda |
|2 | Yusuke - Shimizu|
|3 | Kazuki - Ohtani |
'--+------------------'
はい、名字を含めたデータが全件読み込めました。
変更前のファイルを読み込ませた場合も
.--+--------.
| tLogRow_1 |
|=-+-------=|
|id|dynamic |
|=-+-------=|
|1 | Kouda |
|2 | Shimizu|
|3 | Ohtani |
'--+--------'
と、問題なく読めています。
このように、固定のカラム以外をまとめて読みだせる便利カラムというようなイメージで考えていただければ大丈夫です。
ダイナミックスキーマを利用する場合、tFileInputDelimitedのヘッダの指定を無視して、データの1行目を強制的にヘッダとして認識するため、ヘッダなしのcsvファイルを取り込みたい場合には注意が必要です。この回避として、筆者は
- コンテキスト変数でヘッダを持たせる行を用意し、ヘッダを格納
- ヘッダ + データ行で仮のcsvファイルを作成
- 手順2. で作成したファイルを読み込む
という手順を取ることが多いです。もっといい方法があればこっそり教えてください。
ダイナミックスキーマの応用
さて、ここまでは基礎のお話でした。基礎の段階で「一つのジョブを使いまわし、インターフェース仕様の異なる複数種類のファイルを処理したい」の方の説明は済みましたので、応用ではもう片方
ダイナミックカラムから特定のカラムのみを抜き出して連携したい
について説明します。
Javaのお話
唐突ですが、TalendのベースとなっているのはJavaです。
ダイナミックカラムも例外ではなく、コード上での扱いはJavaのList型の延長にあるようです。興味がある方は実際のコードを見てみてください。600行くらいあるので、ここでは割愛します。
- カラムの情報取得
- カラムの値取得
- カラムの追加・置き換え・削除
- ダイナミックスキーマを別名で複製する
などができそうです。
ダイナミックスキーマから特定カラムを削除する
今回使うのは以下の関数です。
public void removeDynamicElement(String columnName) {
if (columnName != null) {
for (int i = 0; i < this.getColumnCount(); i++) {
if (columnName.equalsIgnoreCase(this.metadatas.get(i).getName())) {
removeDynamicElement(i);
}
}
}
}
見たらわかると思いますが、「カラム名を渡して、カラム名が一致するカラムを見つけたら削除する」という処理です。
ファイル読み込みのコンポーネントからtJavaRowにrow接続し、tJavaRowに以下のコードを記述します。
Dynamic dynamic = input_row.dynamic.clone();
if (! StringUtils.isEmpty((String)globalMap.get("row1.columns"))) {
JSONArray columns = new JSONArray((String)globalMap.get("row1.columns"));
List<Object> column_list = columns.toList();
for (int i = 0; i < input_row.dynamic.getColumnCount(); i++) {
DynamicMetadata meta = input_row.dynamic.getColumnMetadata(i);
if (! column_list.contains(meta.getName())) {
dynamic.removeDynamicElement(meta.getName());
}
}
}
output_row.dynamic = dynamic;
- ダイナミックスキーマの内容を複製
- 連携対象カラムを記載した情報 (今回の実装ではjson形式で記述、全件連携の場合はキー自体が記述されない想定) を読み込み、空でなければリスト形式に変換
- ダイナミックスキーマを読み込み、連携対象に含まれていなければ、上記の関数で削除
- 最後に、編集したダイナミックスキーマをoutput
という処理をしています。
今回の実装自体はだいぶ前に行ったのですが、記事作成に際して見返したとき、普通にindexでの削除
public void removeDynamicElement(int index) {
if (index < getColumnCount()) {
metadatas.remove(index);
values.remove(index);
}
}
でよかったと思いました。
おわりに
いかがでしたか。
弊社は6月が期末にあたるため、今期最後ということで少し気合い入れて記事を作成してみました。
Qiitaへの記事投稿も今年から始めた試みですが、この1年、新しいことも今まで通りのこともやって、去年の自分よりも今の自分の方が技術者としていろいろできるようになったことを実感しています (まぁ、そうでないと困るわけでもありますが)。
さて、こんな形で情報を出して、というのを何度かやってきて、それが誰かのお役に立てているかは正直わからないですが、そうであってほしいと思うし、そうであれば嬉しいです。
来期もネタを見つけたらこんな感じで情報出していこうと思います。ご縁があれば読んでいただけると嬉しいです。
以上、ここまでお読みいただきありがとうございました。

