DQ10のレベル上げをSplunkで可視化してみた

# はじめに
知人にSplunkのことを話したら

「じゃあ今遊んでるDQ10の経緯を見てみたい」

と言われたので、ちょっとやってみた。

# やってみた
## 元データ(冒険の履歴)

DQ10はオンラインゲーでキャラクターごとにWebのポータルがあり、そこの冒険日誌という名前でレベルが上がった履歴が見れると言うので楽勝だと思ったのだが、そううまくはいかなかった。

その冒険日誌をエクスポートできる機能がなかったのだ。

仕方ないのでコピペしてテキストファイルに張り付けてうにゃうにゃすればできるかなーと思ったのだが、冒険日誌にはレベル上げ以外に、ボスを倒しただとか、はじめてどこそこにいったというものから、写真を撮った(ゲーム内で撮影できる)履歴や、プレイヤー自身が書ける日記まであったりといろんなパターンがあって、知人の日誌は約5000件に達していたのである。

しかも、Web上では15件ずつしか表示されないので、300ページ超もあることになり、とてもじゃないけど手作業では無理と判断。

結局、スクレイピングのツールを入れて、日付(date)と１行分だけ抜き出して(msg)CSVファイルに出力することにした。スクレイピングすごい！

## 取り込ませる
CSVファイルなので、SplunkWebのアップロードを使った。

- ソースタイプ：CSVを一旦選択。
- タイムスタンプフィールド：date
- タイムスタンプフォーマット：%Y/%m/%d
- 文字コード：Shift-JIS
- 「MAX_DAYS_AGO」に「3650」を追加 → デフォルトでは1000日前までを取り込む仕様だが、ログは2012年からのものだったので、MAX_DAYS_AGOで3650＝10年前までに範囲を広げた。

この設定で、ソースタイプ名「dq10_csv」で保存

- ホスト名：キャラクターの名前
- インデックス名：main

無事、取り込めた。

## 職業とレベルを抜き出す

レベルがあがったときのメッセージは

「戦士のレベルが80になった」

ってな感じだったので、レベルのログに絞りつつ、rexコマンドを使って抽出してみた。

    index=main msg="*のレベルが*" | rex field=msg "^(?P<job>.*)のレベルが(?P<level>[0-9]*)になった"

ところがごくまれにレベルが抽出できないところが出てきたので確認したところ

「戦士のレベルが81から85になった」

と、レベルが一気に上がったときはメッセージが微妙に違うところが判明。なので、rexコマンドの正規表現をちと変えて対応。

    index=main msg="*のレベルが*" | rex field=msg "^(?P<job>.*)のレベルが[0-9から]*?(?P<level>[0-9]*)になった"

これで全職とれた。

## 統計を取る

時系列で統計を取るのはtimechartコマンド。同じ日にいくつもレベルが上がっている場合があるので、その日の最大値を取るために「max(level)」を指定。間隔は1dayにすると件数が多すぎて結果が切られてしまうため「span=3day」に、職業は全部で20個近くあるので「limit=0」を指定した。

    index=main msg="*のレベルが*" | rex field=msg "^(?P<job>.*)のレベルが[0-9から]*?(?P<level>[0-9]*)になった" | timechart max(level) span=3day limit=0 by job

![dq10_20200115_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552413/e0623f62-22a6-f4f2-f2df-d19c93118cb1.png)

ところがこれだとレベルが上がらなかった日は歯抜けになってしまう。上がらなった日はそれまでのレベルと同じになるはずなので、「filldown」を追加。これによって歯抜けのところは上の値で埋め尽くされることになる。

    index=main msg="*のレベルが*" | rex field=msg "^(?P<job>.*)のレベルが[0-9から]*?(?P<level>[0-9]*)になった" | timechart max(level) span=3day limit=0 by job | filldown

![dq10_20200115_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552413/0a7c6cd3-dac4-b02c-1a02-3efeee47b14e.png)


これで歯抜けしなくなったので、tableコマンドで職業の順を並べ替えてSPLは完成。

    index=main msg="*のレベルが*" | rex field="msg" "^(?P<job>.*)のレベルが[0-9から]*?(?P<level>[0-9]*)になった" | timechart max(level) span=3day limit=0 by job | filldown | table _time, 戦士,僧侶,魔法使い,武闘家,盗賊,旅芸人,バトルマスター,パラディン,魔法戦士,レンジャー,スーパースター,賢者,まもの使い,どうぐ使い,踊り子,占い師,天地雷鳴士,遊び人,デスマスター

視覚エフェクトで「折れ線グラフ」を選び、[名前を付けて保存]→[ダッシュボードパネル]で適宜名前を付けて保存すれば、DQ10ダッシュボードの完成！

## アノテーション

出来上がったグラフは階段状に上がっていくのだが、定期的に行われるバージョンアップとともに上限が解放されていくということで納得。ならばその「バージョンアップのタイミング」とレベルの上がり方を表してみようじゃないか。

1.  DQ10のHPに掲載されていたバージョンと日付の情報をコピペ＆整形＆UTF-8にしたCSVファイルを作成。
2. [設定]→[ルックアップ]→[ルックアップテーブルファイル]をたどり、右上の[新しいルックアップテーブルファイル]をクリックして、1.で作ったファイルを登録する。ファイル名は同名とした。
3. [設定]→[ルックアップ]→[ルックアップ定義]をたどり、右上の[新しいルックアップ定義]をクリックして、2で登録したファイル名を指定し、ルックアップ名「dq10_version」で登録
4. さっき作ったダッシュボードに移動し、[編集]→[ソース]を選んでSimpleXMLの編集画面を開く。
5. 元のサーチ文が書かれている<search>～</search>タグの後ろにアノテーションをつけるsearchタグ群を追加する。日付をstrptime()で変換して_timeに格納するのがポイント。

        <search type="annotation">
          <query>|inputlookup dq10_version | eval _time = strptime('date', "%Y/%m/%d") | eval annotation_label = ver | eval annotation_category = Info | eval annotation_color = "#00aa00" </query>
          <earliest>1343779200</earliest>
          <latest>now</latest>
        </search>

これで折れ線グラフにバージョンアップした日が注釈としてついた。

## 凡例に数値を表示

ある日にどの職業がレベルいくつになってるかを横並びで見たかったので、以下のオプションを追加した。

    <option name="charting.legend.mode">seriesCompare</option>

これで凡例＝職業の横にレベルの数値が表示されるようになった。

ついでにダークモードにしてみた。

# 結果
![dq10_20200115_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/552413/e2e2148e-d11f-684b-3579-68d419830b24.png)

バージョンアップでレベル上限が解放されると一気にレベルを上げていたけど、年を経るに従いレベル上げ緩慢になってきているのがよくわかった、とのことだった。

Splunkじゃなくても出来ることだと思うけど、アノテーションの使い方がわかっていい勉強になった。