Glueの使い方的な⑩(カスタムClassifierの手始め)

# Glue のClassifierを使ってテーブルスキーマを作ります
### 概要

[Glueの使い方的な①(GUIでジョブ実行)](https://qiita.com/pioho07/items/c9ce1d0677777f974ffe)

こちらの手順はシンプルなCSVファイルからParquetファイルに変換しました。

>Schemaを見るとuuidやappidなどがbigintで数値型になってます、文字列型がよければここでも修正できます。
今回は一旦このまま進めます

本文中に上記の内容があります。Glueのクローラーは自動でスキーマを作ってくれ便利ですが、場合によっては意図しない型になることもあります。appidの001などがbigintとして扱われ結果1となってしまいます。IDなので001と文字列型にしたい。そういった場合にClassifierの出番となります。

CSVファイルのスキーマをClassifierを使って定義してみます。

### クローラー名
se2_in2_classifiertest

### Classifier
test01

# 全体の流れ

* 前準備
* Classifierの作成
* クローラーの作成と実行
* スキーマ確認、Athenaでクエリ確認
* その他例(区切り文字を含むフィールドをClassifierで表現)

# 前準備

### 今回使うサンプルログファイル(19件)

"Glueの使い方的な①(GUIでジョブ実行)"と同じデータになります

```csv:csvlog.csv
deviceid,uuid,appid,country,year,month,day,hour
iphone,11111,001,JP,2017,12,14,12
android,11112,001,FR,2017,12,14,14
iphone,11113,009,FR,2017,12,16,21
iphone,11114,007,AUS,2017,12,17,18
other,11115,005,JP,2017,12,29,15
iphone,11116,001,JP,2017,12,15,11
pc,11118,001,FR,2017,12,01,01
pc,11117,009,FR,2017,12,02,18
iphone,11119,007,AUS,2017,11,21,14
other,11110,005,JP,2017,11,29,15
iphone,11121,001,JP,2017,11,11,12
android,11122,001,FR,2017,11,30,20
iphone,11123,009,FR,2017,11,14,14
iphone,11124,007,AUS,2017,12,17,14
iphone,11125,005,JP,2017,11,29,15
iphone,11126,001,JP,2017,12,19,08
android,11127,001,FR,2017,12,19,14
iphone,11128,009,FR,2017,12,09,04
iphone,11129,007,AUS,2017,11,30,14
```

#### S3に配置

```shell:
$ aws s3 ls s3://test-glue00/se2/in2_classifiertest/
2018-01-09 14:12:18          0 
2018-02-14 11:14:27        643 cvlog0.csv
```


# Classifierの作成

GlueのメニューからCrawlers->Classifiersをクリックし、画面上部の"Add classifier"をクリック

![スクリーンショット 0030-02-14 11.18.29.png](https://qiita-image-store.s3.amazonaws.com/0/27932/c6a38b00-c52e-21d2-6b2f-5f8f4e082481.png)

以下を入力し"Create"をクリック

Classifier name:test01
Classifier type:Grok
Classification:csv(custom)
Grok pattern:↓

```
%{WORD:deviceid:string},%{WORD:uuid:string},%{WORD:appid:string},%{WORD:country:string},%{NUMBER:year:int},%{NUMBER:month:int},%{NUMBER:day:int},%{NUMBER:hour:int}
```

![スクリーンショット 0030-02-14 12.08.27.png](https://qiita-image-store.s3.amazonaws.com/0/27932/b87c0405-d198-0c67-8772-a0bfe38b7a79.png)


上記のように、Grok patternでフィールド名やデータ型を定義している。私もGrokが詳しい訳ではないがこのくらいシンプルなものであれば簡単に記述できる。

基本の構文は以下

```
%{PATTERN:field-name:data-type}
```
field-nameにスキーマのカラムとなる名前
data-typeにデータ型(stringやintなど)
PATTERNには以下のGlueビルトインのものを入れる↓(一部を抜粋)
[参考](https://docs.aws.amazon.com/ja_jp/glue/latest/dg/custom-classifier.html)

```
#AWS Glue Built-in patterns
 USERNAME [a-zA-Z0-9._-]+
 USER %{USERNAME:UNWANTED}
 INT (?:[+-]?(?:[0-9]+))
 BASE10NUM (?<![0-9.+-])(?>[+-]?(?:(?:[0-9]+(?:\.[0-9]+)?)|(?:\.[0-9]+)))
 NUMBER (?:%{BASE10NUM:UNWANTED})
 BASE16NUM (?<![0-9A-Fa-f])(?:[+-]?(?:0x)?(?:[0-9A-Fa-f]+))
 BASE16FLOAT \b(?<![0-9A-Fa-f.])(?:[+-]?(?:0x)?(?:(?:[0-9A-Fa-f]+(?:\.[0-9A-Fa-f]*)?)|(?:\.[0-9A-Fa-f]+)))\b
 BOOLEAN (?i)(true|false)
 
 POSINT \b(?:[1-9][0-9]*)\b
 NONNEGINT \b(?:[0-9]+)\b
 WORD \b\w+\b
 NOTSPACE \S+
 SPACE \s*
 DATA .*?
 GREEDYDATA .*
 #QUOTEDSTRING (?:(?<!\\)(?:"(?:\\.|[^\\"])*"|(?:'(?:\\.|[^\\'])*')|(?:`(?:\\.|[^\\`])*`)))
 QUOTEDSTRING (?>(?<!\\)(?>"(?>\\.|[^\\"]+)+"|""|(?>'(?>\\.|[^\\']+)+')|''|(?>`(?>\\.|[^\\`]+)+`)|``))
 UUID [A-Fa-f0-9]{8}-(?:[A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}
```

あとは以下のGrokヘルパーでテストするのがいい。サンプルもいくつかあったりしてこの辺が有名らしい
* [Grok constructor](http://grokconstructor.appspot.com/do/match#result)
* [Grok debug](https://grokdebug.herokuapp.com/)

こんな感じ

![スクリーンショット 0030-02-14 12.15.56.png](https://qiita-image-store.s3.amazonaws.com/0/27932/5a9bbd58-fcb3-08fc-3c8e-6ed4a49e16ce.png)

![スクリーンショット 0030-02-14 12.16.09.png](https://qiita-image-store.s3.amazonaws.com/0/27932/d6bb7515-e061-c2f9-604f-acf9424684a5.png)

# クローラーの作成と実行

GlueのメニューのCrawlersをクリックし、"Add crawler"をクリック

![スクリーンショット 0030-02-14 11.20.46.png](https://qiita-image-store.s3.amazonaws.com/0/27932/be6a3ede-d082-934e-a474-13dddf426334.png)

Crawler nameに"se2_in2_classifiertest"を入力

"Description and classifiers (optional)"をクリックし、画面下部のCustom classifiersに作成したClassifierの"test01"がある。右側の"Add"をクリックする

![スクリーンショット 0030-02-14 11.22.15.png](https://qiita-image-store.s3.amazonaws.com/0/27932/b9f177e3-1f4f-4ea0-8a4e-ca31e0a329a9.png)

test01が右側に移動したことを確認し"Next"をクリック

![スクリーンショット 0030-02-14 11.22.26.png](https://qiita-image-store.s3.amazonaws.com/0/27932/b33abbed-a121-99d0-f836-7134bf97812c.png)

Include pathに"s3://test-glue00/se2/in2_classifiertest"を入力し"Next"をクリック

![スクリーンショット 0030-02-14 11.22.50.png](https://qiita-image-store.s3.amazonaws.com/0/27932/a7f4f04b-2a14-d46f-41d0-f8e39a8a9c42.png)

"Next"をクリック

![スクリーンショット 0030-02-14 11.23.00.png](https://qiita-image-store.s3.amazonaws.com/0/27932/e4fdaf09-66b0-68c9-8f36-6691305fc216.png)

権限のあるロールを選択し"Next"をクリック

![スクリーンショット 0030-02-14 11.23.08.png](https://qiita-image-store.s3.amazonaws.com/0/27932/aa4c747f-e818-478c-14fa-441e2cf10f7c.png)

"Next"をクリック

![スクリーンショット 0030-02-14 11.23.16.png](https://qiita-image-store.s3.amazonaws.com/0/27932/53e683f6-5e6d-8aea-467b-03accf97e01f.png)

以下入力し"Next"をクリックし、サマリーが出るので問題なければ"Finish"
Database:se2
Prefix:se2_

![スクリーンショット 0030-02-14 11.30.58.png](https://qiita-image-store.s3.amazonaws.com/0/27932/c0dd947e-141b-9adb-3842-9c7a6161c3ad.png)

作成されたことを確認し、画面上部の"Run crawler"をクリック

![スクリーンショット 0030-02-14 11.30.28.png](https://qiita-image-store.s3.amazonaws.com/0/27932/3e5f7423-c221-97f5-0a64-1d6f67e6b5de.png)

この辺は間違っていたら修正するトライアンドエラーをやると思いますが、注意が必要なのが現在Classifierだけ修正しえも反映がされずなぜかCrawlerを消して作り直す必要があります。
Grokの部分の確認であればGrokヘルパーなどを使った方がお金もかからず効率的なテストができると思います。

# スキーマ確認、Athenaでクエリ確認

### 作成されたテーブル

![スクリーンショット 0030-02-14 11.32.06.png](https://qiita-image-store.s3.amazonaws.com/0/27932/720cb169-5d85-1721-303a-fd726cea3d6b.png)

### テーブルの内容

![スクリーンショット 0030-02-14 12.15.22.png](https://qiita-image-store.s3.amazonaws.com/0/27932/6ea307be-725c-1044-f41e-2a2f1acc3eb9.png)

### Athenaで確認

appidやuuidがstringの型になっていることが確認できる

![スクリーンショット 0030-02-14 12.24.21.png](https://qiita-image-store.s3.amazonaws.com/0/27932/b7870c0b-06c7-def6-120d-b60ab98ecf0a.png)

クエリ結果

![スクリーンショット 0030-02-14 12.26.36.png](https://qiita-image-store.s3.amazonaws.com/0/27932/93f11071-bac3-8f1b-fe52-dcf250d8e8ec.png)

# その他例(区切り文字を含むフィールドをClassifierで表現)

以下のようなCountryのカラムのデータが"JP,TK"のような区切り文字のカンマが入ったものを１つのフィールドにみなしたい。
普通にやると区切り文字として判定してしまいうまくいきません

#### 入力ファイル

```
"iphone","11111","001","JP,TK"
"android","11112","001","FR,PR"
"iphone","11113","009","FR,PR"
```

#### Classifier作成
* Classifier name:test02
* Grok pattern:以下

```
"%{WORD:deviceid:string}","%{WORD:uuid:string}","%{WORD:appid:string}","%{CUSTOM:country:string}"
```
* Custom Pattern:以下

```
CUSTOM ((?>[\w_%!$@:.,~-]+|\\.)*)+
```

※結果的には問題なく区切り文字を回避できましたがGrokの書き方がいい書き方なのかは不明でおそらくもっと良い書き方があると思います。そのうち修正します。

![スクリーンショット 0030-02-14 23.26.33.png](https://qiita-image-store.s3.amazonaws.com/0/27932/f8ff2853-02e3-06ae-3b6f-3ce5b14a6b9a.png)

あとは前述のように作成したClassifierを指定したCrawlerを作りクローリングします

クローリング後のスキーマ

![スクリーンショット 0030-02-14 23.08.12.png](https://qiita-image-store.s3.amazonaws.com/0/27932/b836b253-966d-7903-0ac3-7a4805a8874d.png)

Athenaのクエリ結果
Countryが区切り文字のカンマを含む値として認識している

![スクリーンショット 0030-02-14 23.08.35.png](https://qiita-image-store.s3.amazonaws.com/0/27932/580f8250-21d1-4377-a1ea-596eb30b6a1f.png)


### ヘッダ行があるとうまくいかない問題

#### 入力

```
"deviceid","uuid","appid","country"
"iphone","11111","001","JP,TK"
"android","11112","001","FR,PR"
"iphone","11113","009","FR,PR"
```

上記のようにヘッダにフィールド名が入った行があると、Classifierを使わない場合なら自動で"skip.header.line.count:1"を入れてくれ読み飛ばしてくれるのですが、Classifierを使った場合は自動では入らないようで以下のように入れます

![スクリーンショット 0030-02-14 23.12.00.png](https://qiita-image-store.s3.amazonaws.com/0/27932/4840cd0e-950d-aa48-dee0-e762fe659c79.png)

設定は入りました

![スクリーンショット 0030-02-14 23.22.57.png](https://qiita-image-store.s3.amazonaws.com/0/27932/598edb8c-ec76-7881-cb70-5fc0f1ba2e5c.png)

Athenaでのクエリ実行すると結果は読み飛ばしてくれない。

![スクリーンショット 0030-02-14 23.25.40.png](https://qiita-image-store.s3.amazonaws.com/0/27932/df1843be-7ce2-433c-fdb2-4e239c0ecc2b.png)

根本的にはうまくいってないですが、スキーマとなる情報がClassifier側にあるなら二重にヘッダにも持つ必要はないのでヘッダ側を削除する設計がいいと思います。


## To Be Continue
TODO

## 参考資料

Grok constructor
http://grokconstructor.appspot.com/match

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/custom-classifier.html

Glueの使い方まとめ
https://qiita.com/pioho07/items/32f76a16cbf49f9f712f