Glueのデータカタログ機能て、すごい便利ですよね。
Glueデータカタログとは、DataLake上ファイルのメタ情報を管理してくれるHiveメタストア的なやつで、このメタストアを、AthenaやRedshift Spectrumから簡単に参照出来ます。マネージドサービスとなるので、メタ情報を格納用データベースはAWS側が用意してくれており、メタ情報に関しても、自動的に取得する機能(Glue crawler機能)を持っています。ファイル単位で、Hive DDL文を書かなくとも、S3上ファイルのメタ情報を管理/更新できるのです。便利だ。
ただし、ファイルのメタ情報を正確に読み取るには、厳格なフォーマットがあります。たとえば、以下のようなCSVファイルの場合(カンマ後に半角スペースがあり、値がダブルクォーテーションで囲まれている)、
"voiceroid_id", "name", "japanese_name" "1", "Yuzuki Yukari", "結月ゆかり" "2", "Tsurumaki Maki", "弦巻マキ" "3", "Tohoku Zunko", "東北ずんこ" "4", "Tohoku Kiritan", "東北きりたん" "5", "Kizuna Akari", "結星あかり" "6", "Kotonoha Akane", "琴葉茜" "7", "Kotonoha Aoi", "琴葉葵"
データカタログには、以下にようにスキーマ登録されて、
Athenaで検索すると、以下のような値で扱われています。(_は半角スペースの意)
voiceroid_id | name | japanese_name |
---|---|---|
1 | _"Yuzuki Yukari" | _"結月ゆかり" |
2 | _"Tsurumaki Maki" | _"弦巻マキ" |
3 | _"Tohoku Zunko" | _"東北ずんこ" |
つまり、「文頭に半角スペースがあり、ダブルクォーテーションが含まれた値」として扱われることになります。ダブルクォーテーションで囲まれた文字列だけを、値として扱ってほしい訳で、これでは困りますね。そんなときに、GlueのCustom Classifier(カスタム分類子)の機能を利用します。
CustomClassifier(カスタム分類子)とは
- grokパターン、またはXMLタグを使用して、データを分類するため仕組み
- crawler実行時に、カスタム分類子が呼び出され、カスタム分類子の情報をもとにデータの分類とスキーマ作成を実行する
- 事前にGlueに組み込まれている分類子では、正しくスキーマを読み取ってくれない場合に利用
grokって何?
grok
というものが出てくるのですが、知らなかったので調べてみました。分かりやすい解説がなく、なかなか苦労したのですが、僕の理解ですと...
- 正規表現をパターン化したライブラリ
- 且つ、そのライブラリを参照して処理できる文字列解析処理、みたいな
分かったような、分からないような...なので、grok構文のhelperサイトを利用して、実際にgrok構文を作成してみます。
http://grokconstructor.appspot.com/do/match
上のサイトの Some log lines
のテキストフィールドには、以下を入力します。parse対象となるメッセージですね。
"voiceroid_id", "name", "japanese_name" "1", "Yuzuki Yukari", "結月ゆかり" "2", "Tsurumaki Maki", "弦巻マキ"
その下のテキストフィールドには、上のメッセージをparseするためのgrok構文を入力します。
^"(?<voiceroid_id>%{INT})", "(?<name>%{NAME})", "(?<japanese_name>%{JAPANESE})"$
grok構文のフォーマットは以下となっており、この構文を通常の正規表現のなかに埋め込んで構文を作ってあげる訳です。
(?<設定したいフィールド名>%{利用されるgrokパターン})
数値をparseしてくれるgrokパターン INT
が、(logstash用に設計された)grok-patternsに用意されているため、INT
のgrokパターンを参照することで、行頭の数値部分を正規表現を書かずにparseしてくれます。
ちなみに、 INT
のgrokパターンは、以下のように定義されています。
INT (?:[+-]?(?:[0-9]+))
logstash-patterns-core/grok-patterns at master · logstash-plugins/logstash-patterns-core · GitHub
しかしながら、 Yuzuki Yukari
という文字列と、 結月ゆかり
という文字列に合致するgrokパターンは既存のgrokパターン・ライブラリには存在しないため、自ら定義してあげる必要あります。
そこで、 a library of some additional grok pattern
には、以下を入力します。
NAME [a-zA-Z]+ [a-zA-Z]+ JAPANESE [^\x01-\x7E]+
1行目は、 NAME
というパターン名にて、 正規表現 [a-zA-Z]+ [a-zA-Z]+
を定義しています。
2行名は、 JAPANESE
というパターン名にて、 正規表現 [^\x01-\x7E]+
を定義しています。マルチバイト文字に合致してくれる正規表現はないので、非シングルバイト文字に合致する正規表現の [^\x01-\x7E]+
を設定しています。
実際の画面では、こんな感じですね。
Go!
ボタンをクリックするとparseしてくれて、以下の結果が返ってきます。
日本語部分は文字化けしてしまっていますが、指定したフィールド名にてメッセージをparseしてくれているのが分かります。
Custom Classifier(カスタム分類子)を定義してcrawlする
grokについて理解できたところで、Glueのカスタム分類子を作成していきます。
Glueカスタム分類子のgrok構文は、通常のgrok構文と異なり、以下のフォーマットとなっています。
%{grokパターン:フィールド名:データ型}
データ型の部分には、Glueデータカタログで利用できる以下のデータ型を指定してあげます。
- string
- byte
- boolean
- double
- short
- int
- long
- float
それを踏まえてできたgrok構文が下記となります。
"%{INT:voiceloid_id:int}", "%{NAME:name:string}", "%{JAPANESE:japanese_name:string}"
grok helperのサイト同様に、nameとjapanese_nameのカラム部分には、合致する正規表現のライブラリが用意されていないため、自分で正規表現を作成してあげます。これですね。
NAME [a-zA-Z]*\s[a-zA-Z]* JAPANESE [^\x01-\x7E]+
ちなみに、GlueのCrawlerで参照されるgorkパターンのライブラリは、以下より確認できます。Logstashのgrokパターンとなっています。
これらの値をcrawlerの画面にて下記にように入力して、クロールを行います。
で、出来上がったテーブル定義にてAthenaを実行してみると、
ちゃんと出来ていないのです。うん、本当に申し訳ない。これはCSVファイルのヘッダー列がgrok構文と一致していないため、Custom Classfierが適用されなかったためです。GlueのCrawlerは、カスタム分類子が定義されている場合、カスタム分類子での解析をまず試みます。しかし、100%正しく解析できない場合、ビルトインされた分類子での解析を試みることになります。
そのため、CSVファイルからヘッダー列を削除して、新しいCrawler作成して、再度クロールします。ヘッダーがなくとも、カスタム分類子のgrok構文部分でフィールド名を指定しているため、テーブルのカラム名には与えたい名前を与えることができますね。尚、基本的にカスタム分類子を編集した場合や利用している場合には、既存のCrawlerをそのまま利用するとちゃんと解析してくれない事が多く、新しくCrawlerを作ってあげると成功する場合が多いです。
分類子の定義を変更すると、変更前の分類子を使用してクロールしたデータは再分類されません。クローラは、以前にクロールしたデータを追跡します。新しいデータは、更新された分類子で分類されるため、スキーマが更新される場合があります。データのスキーマが更新された場合は、クローラの実行時に分類子を更新してスキーマの変更を反映してください。データを再分類して不正な分類子を修正するには、更新された分類子を使用して新しいクローラを作成します。
新しく出来上がったGlueテーブル定義は以下となっています。 Serde parameters
の値を見ると、指定したカスタム分類子が利用されいていること分かりますね。
Athenaで検索すると、欲しかった形で値を取得できています。
便利だ。