GmailのデータをSplunkに取り込んで分析する

# はじめに
Splunkのユーザー会Go Japan Splunk User Group通称[GOJAS](https://gojas.doorkeeper.jp/)のMeet Upで発表したネタです。

---
プライベートのGmailアドレスの受信件数がある時期より増えたように感じたので、Splunkに取り込んだら何かわかるだろうかと思い分析してみました。

---
# 概要
1. Gmailデータを用意する
2. Splunkに取り込む準備をする
3. Splunkに取り込む
4. Splunkで分析する

---
# 1.Gmailデータを用意する

分析元データを用意します。手段はいくつかありますが、他人のメールデータを使うのは
スーパーハカーでもない限り
普通は難しいので今回は自分のメールをデータとして使います。

---

メールデータを1件ずつ手動で取り出すのは面倒なので、以下のサイトを参考にGAS(Google Apps Script)を使ってメール情報を一括でGoogle Spread Sheetに出力し、その後csvファイルとしてダウンロードします。

---

参考先サイト（いつもありがとうございます。）
[[Google Apps Script]メール情報をスプレッドシートに書き出す](https://dev.classmethod.jp/etc/google-apps-script-gmail-to-spreadsheet/)
[Google Spreadsheetで各シートをCSVとしてダウンロードするためのリンクを表示する。](https://qiita.com/3mc/items/8e8b7b7eabf216c81d68)
[スプレッドシートのデータをGASを使って1クリックでCSVに吐き出すものを作る。]
(https://www.pnkts.net/2018/04/27/spreadsheet-gas-csv/)


※本当はデータの出力からcsvファイルダウンロードまで自動化したかったのですが
技術
時間がなかったので断念しました

---

今回は、メール受信日時,メール送信元,メール件名をデータとして出力してみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/10faa8e3-28df-e105-1d29-132b0c666767.png)

---
## GAS使用時の注意点

- GASを使ってGoogle Spread Sheetにメールデータを出力する場合、一度に出力できるのが最大500件までなのでご注意ください。

---

# 2. Splunkに取り込む準備をする
先ほどcsv形式で出力したファイルをSplunkに取り込みます。が、その前に今回取り込むデータを分析する個別Appを作ります。

---

なお、個別Appを作らなくても分析自体はできます。しかし、今回の分析に関する設定群を1つのAppにまとめてしまうことで、後々管理が容易になります。よって、最初の段階でAppを作ってしまったほうがよいと思います。

---

データを取り込み、分析をするためには最低限以下の設定が必要なので、App内に定義していきます。
1. インデックス定義（indexes.confで定義）※
2. ソースタイプ定義（props.confで定義）

※今回のデータを取り込むインデックスはSplunkデフォルトのインデックス(main)でもよいのですが、後々のことを考えると個別のインデックスにしてしまった方がよいです。

---

```インデックス定義の例(indexes.confに記述)
[idx_gmail]
homePath = $SPLUNK_DB\idx_gmail\db
coldPath = $SPLUNK_DB\idx_gmail\colddb
thawedPath = $SPLUNK_DB\idx_gmail\thaweddb
```

---

``` ソースタイプ定義の例(props.confに記述)
[st_gmail]
CHARSET = UTF-8
TIME_PREFIX = ^
TIME_FORMAT = %a %b %d %Y %H:%M:%S %Z
MAX_TIMESTAMP_LOOKAHEAD = 40
SHOULD_LINEMERGE = false
```

---
## ソースタイプ定義例の補足
TIME_FORMATアトリビュートは、データに含まれる時刻の書式を指定するパラメータです。GASで出力すると、行頭から以下のような書式で出力されるので、strftime形式で指定します。

>Thu Jan 31 2019 23:00:47 GMT+0900 (JST),
>Thu Jan 31 2019 20:31:13 GMT+0900 (JST),

---

# 3.Splunkに取り込む

インデックスとソースタイプを定義したら、GASで出力したcsvファイルをSplunkに取り込みます。取り込む方法は幾つかありますが、Splunkのファイルアップロード機能を使って取り込むのが手っ取り早いです。

---

ファイルアップロード機能におけるソースタイプ設定画面で先ほど定義したソースタイプを選択し、タイムスタンプが正しく認識されていることと、1行が1つのイベントとして認識されていることを確認した後、最初に作成した個別Appで作成したインデックスにデータを取り込みます。

---

次の画面はファイルアップロード時におけるソースタイプの設定画面のサンプル画面になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/6b510a32-c97a-3098-e35d-aca7bfc6ae9a.png)

---

# 4.Splunkで分析してみる
Splunkにデータを取り込んだら色々な観点で分析してみます。

---

## 時系列で分析してみる
まずは、メールの受信日時データを軸にして分析してみます。

```ruby:メール受信件数を月ごとに集計する
index=idx_gmail
| timechart span=1mon count 
| trendline sma2(count) as "移動平均"
| rename count as "受信件数"
```

---

このサーチ結果を縦棒グラフ(Column Chart)で表示してみますと以下のような感じで可視化することができます。※移動平均をグラフにオーバーレイさせています
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/0b2c2c69-e6d6-6eee-4902-a941aedfb1eb.png)

---
次に、メールの受信件数を時間帯と曜日ごとに集計してみます。

```ruby:メール受信件数を時間帯と曜日ごとに集計する(1)
index=idx_gmail
| eval date_hour=substr("00"+date_hour,-2) 
| eval date_wday=case(
    date_wday="monday","1 mon",
    date_wday="tuesday","2 tue",
    date_wday="wednesday","3 wed",
    date_wday="thursday","4 thu",
    date_wday="friday","5 fri",
    date_wday="saturday","6 sat",
    date_wday="sunday","7 sun"
    ) 
| chart count over date_hour by date_wday 
```

---

このサーチ結果を縦棒グラフ(Column Chart)の積み上げ形式で表示すると以下のような感じで可視化できます。この例では昼12時台と18時台に多くメールを受け取っていることが判ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/2864caa3-b385-2764-ebb3-ff5c65777978.png)

---

次のサーチは先ほどのサーチと同じように受信件数を時間帯と曜日ごとに集計するサーチですが、結果の表示方法を変えています。

```ruby:メール受信件数を時間帯と曜日ごとに集計する(2)
index=idx_gmail
| eval date_hour=substr("00"+date_hour,-2) 
| eval date_wday=case(
    date_wday="monday","1 mon",
    date_wday="tuesday","2 tue",
    date_wday="wednesday","3 wed",
    date_wday="thursday","4 thu",
    date_wday="friday","5 fri",
    date_wday="saturday","6 sat",
    date_wday="sunday","7 sun"
    ) 
| chart count over date_hour by date_wday 
| transpose 0 header_field=date_hour 
| rename date_wday as "曜日"
```

---

このサーチ結果をヒートマップで表示すると、先ほどの積み上げグラフに比べ、どの曜日の何時ごろにメールを受け取っているかが視覚的に判るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/baf6d728-ef6c-ac13-de6d-c8bf793f949c.png)

---

なお、この表示形式にした場合、曜日と時間ごとの件数はわかりますが、一方で、積み上げグラフ表示で判った「時間ごとの総件数」が判りづらくなります。見たい内容によって最適な視覚エフェクトを使うのが重要です。

---

## 送信元で分析してみる
今度はメールの送信元情報を分析してみます。

```ruby:メール送信元トップ10をサーチする
index=idx_gmail
| rex field=_raw "^[^,]+,\"?(?P<from>[^\"<,]+)"
| top limit=10 from
```

---

このサーチ結果を円グラフ(Pie Chart)で表示すると、送信元の割合を視覚的に確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/53b6b30b-41bb-4dde-dc33-1cb34e215250.png)

楽天カードさんから届くメールが多いことが判ります。

---

### ※サーチ文の補足
2行目のrexコマンドは、正規表現を使ってGmailデータ(文字列)からメール送信元に該当する文字列をfromフィールドとして抽出しています。この正規表現を使ったフィールド抽出設定は、予め「フィールド抽出」定義としてソースタイプごとに設定することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/b18eb15a-d1bb-a088-5c5f-a3c6b289938d.png)

---

次のサーチはメール送信元の月別トップ10を分析するサーチになります。

```ruby:メール送信元の月別トップ10をサーチする
index=idx_gmail
| rex field=_raw "^[^,]+,\"?(?P<from>[^\"<,]+)"
| eval date_mon = strftime(_time,"%m")
| stats count as cnt by date_mon from
| sort date_mon - cnt
| streamstats count as rank by date_mon
| where rank<=10
```

---
この結果をトレリスで表示することで月ごとの送信元トップ10を可視化することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/b831e6ac-d115-ae94-5839-dc6b37749898.png)

---
今度はメールの送信元ドメインのトップ10をサーチします。

```ruby:メール送信元ドメイントップ10をサーチする
index=idx_gmail 
| rex field=_raw "@(?P<from_domain>[^>]+)"
| top limit=10 from_domain
```

---

このサーチ結果をそのまま統計情報で表示すると以下のように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/b068de46-88b7-9fa8-45c5-71615b55c23b.png)

---
送信元分析の最後はメール送信元のTLDを分析してみます。

```ruby:メール送信元TLDをサーチする
index=idx_gmail 
| rex field=_raw "(?P<from_tld>\.[^\.]+(?=>,))"
| top limit=10 from_tld
```

---
この結果を表示してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/10d82df3-18be-ce72-91b2-60f1a31be0cc.png)

どうやらほとんどjpドメインから届いていることがわかりました。

---
## メールタイトルで分析してみる

最後はメールタイトルを分析してみます。

```ruby:メールタイトルのトップ50をサーチする
| rex field=_raw "^(?:[^,]+,){2}(?P<subject>.+)"
| top limit=50 subject
```

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/4395ecc8-294b-7bf7-b8f1-7443102a59cc.png)

---

メールタイトルの傾向より、似たような文言が使われているタイトルが多いので、括弧記号やコロン:を区切り文字としてタイトルを区切ってみます。

```ruby:メールタイトルを括弧で区切って集計する。
index=idx_gmail 
| rex field=_raw "^(?:[^,]+,){2}(?P<subject>.+)" 
| rex field=subject max_match=100 "(?P<word>(【[^】]+】|.+(-\s)|『[^』]+』|「[^」]+」|[^\【\「\[\(（:]+|\([^\)]+\)|（[^）]+）|\[[^\]]+\]))" 
| mvexpand word 
| eval word=trim(word) 
| where NOT (word="" OR 
    word LIKE "【%" OR 
    word LIKE "『%"
    word LIKE "「%" OR 
    word LIKE "(%" OR 
    word LIKE "[%" OR 
    word LIKE "（%" OR 
    ) 
| stats count by word 
| sort - count
```

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/80b00d6e-dd6d-0815-a41f-ec2668a0c9eb.png)
ある程度はうまく区切れましたが、癖があるタイトルはうまく区切れなかったりするようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/8628b5ab-bd89-550b-924d-fbacded52492.png)

---

## 形態素解析してみる
先ほどの分析例でメールタイトルをある程度の単語に区切ることができましたが、今度は本格的に形態素解析を行ってみます。

---

Splunk自体に形態素解析機能はないのですが、代わりにカスタムコマンドと呼ばれる外部連携機能を使って形態素解析ライブラリと連携してみます。今回はMecabを使って形態素解析をしてみます。

---

Mecabを呼び出すカスタムコマンドの実装については以下のサイトを参考にさせていただきました。ありがとうございます。
[Splunk で MeCab を使った形態素解析をする](https://qiita.com/maroon/items/c590deadd57de0dece47)

---

``` ruby:Mecabを呼び出すカスタムスクリプトを使ってメールタイトルを形態素解析し、単語の出現回数を集計する。
index=idx_gmail 
| rex field=_raw "^(?:[^,]+,){2}(?P<text>.+)" 
| run mecab 
| makemv mecab 
| mvexpand mecab 
| eval len=len(mecab),isnum=if(isnum(mecab),1,0) 
| search len>1 AND isnum=0 
| stats count by mecab 
| sort - count
```

---

サーチ結果を表形式で表示してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/1097fd52-10d8-d904-256a-62ee465a27e2.png)

---
# おわりに
今回メールのログではなくメールそのものをSplunkに取り込んで分析してみましたが、ログでなくとも色んな観点で分析することができました。

---

Splunkはログに限らず、テキストデータであれば何でも取り込めるのが強みだと思います。

---

また、取り込むデータから何を情報/キーワードとして抽出するかを事前に定義（設計）する必要もありません。このあたりがデータベースなどとの違いであり、Splunkのメリットだと思います。

---

Splunkで何をしたらいいかわからない・・・という方も、まずはデータを取り込んでみて、それから色々サーチしてみてはいかがでしょうか。課題解決につながるような原因や、まったく気づかなかった傾向や相関がみえてくるかもしれません。

---

```ruby
| makeresults
| eval thankyou="Let's Splunking!"
| table thankyou
```

---

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/170600/42e74a33-878f-b2f4-88f7-dcf5b7e2f196.png)

ここまで読んでいただき、ありがとうございました。