docker-composeのファイルもあるのでとりあえず試してみる
当ブログへのアクセスはGoogleAnalyticsでアクセス解析しています
そのデータをmysqlに突っ込んでグラフを表示したいと思います
インストール
curl https://raw.githubusercontent.com/getredash/redash/master/docker-compose-example.yml > docker-compose.yml docker-compose up
これだけでredashの起動はできます
実際に使用したcompose.ymlの一部抜粋(localで動作させるだけなのでnginxは除外した)
- docker-compose
redash:
image: redash/redash:latest
ports:
- "5000:5000"
links:
- redis
- postgres
environment:
REDASH_STATIC_ASSETS_PATH: "../rd_ui/dist/"
REDASH_LOG_LEVEL: "INFO"
REDASH_REDIS_URL: "redis://redis:6379/0"
REDASH_DATABASE_URL: "postgresql://postgres@postgres/postgres"
REDASH_COOKIE_SECRET: veryverysecret
REDASH_DATE_FORMAT: "YYYY-MM-DD"
REDASH_ALLOW_SCRIPTS_IN_USER_INPUT: "True"
redis:
image: redis:2.8
postgres:
image: postgres:9.3
volumes:
- ./data/postgres-data:/var/lib/postgresql/data
入力フォームを使いたいためREDASH_ALLOW_SCRIPTS_IN_USER_INPUTをセットする
初期データ作成
初期データを入れないといけないようなので下記からDLしてきて実行する
curl https://raw.githubusercontent.com/getredash/redash/master/setup/docker/create_database.sh > create_database.sh
sudo sh create_database.sh
中身を見るとdocker-compose runでコンテナ内でコマンド実行してpostgresのユーザー追加などのセットアップをしている模様
再度dockerを起動する
sudo docker-compose up
5000 番でダッシュボードにアクセスできるようになります
- ipass
user:admin pass:admin
データソースを作成する
mysqlにデータを突っ込みます
見たいデータに合わせてデータソースを選択するか作成します
以前GoogleAnalyticsのレポートデータを取得するようにしたのでそれを使ってMySQLにデータを突っ込んでおきます
Net::Google::Analytics でページごとのpageview数を取得する - notebook
クエリを作る
集計したいデータ、もしくはグラフを作れるようなデータを出力するクエリを作成します

こんな感じになります
定期実行させる
作ったクエリを定期実行させます
Refresh Schedule Never の箇所をクリックして設定します

1分毎、5分毎.... 毎日何時に実行など
crontab程の柔軟性はないものの十分な印象でした
ダッシュボードを作る
特に難しいことはなく右上のメニューボタンからAdd Wigetで作成したグラフやテーブルを追加していきます
クエリで作ったクエリの実行結果のテーブル、visualizationで作成したグラフなどを選択できます
こんな感じ

フォームを作る
動的な値をクエリに含める場合テキストボックスにフォームを作成します

Widgetにもフォームはありますがテキストボックスにフォームを入れておけばダッシュボード中のすべてのグラフに対してクエリを送ることができます
なので期間でデータを区切ったグラフをまとめてダッシュボードに詰めてフォーム用のテキストボックスを作れば入力に応じて複数のグラフが変わるようにできたりするようです
というか、テキストボックスでコードが書けるならいろいろやりようはありそうですね
ただ、現状だとテキストボックスの値は一度登録したら編集ができない模様。。。。
- textboxの記述例
<form action="/dashboard/memo-by-date-report" id="daterange" method="get">
<div style="width: 80%">
<div style="text-align: center;">期間選択</div>
<input type="button" value="Yesterday" data-key="Yesterday" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="Last 7 Days" data-key="Last 7 Days" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="Last 30 Days" data-key="Last 30 Days" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="This Month" data-key="This Month" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="Last Month" data-key="Last Month" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="Last 1 Year" data-key="Last 1 Year" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="Last 2 Year" data-key="Last 2 Year" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="button" value="All Time" data-key="All Time" class="btn btn-sm btn-default btn-block" onClick="dateRangeSubmit(this)" />
<input type="hidden" name="p_start" id="p_start" class="daterange" value="" />
<input type="hidden" name="p_end" id="p_end" class="daterange" value="" />
</div>
</form>
<script type="text/javascript">
function dateRangeSubmit(e){
moment.locale('ja');
var ranges = {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
'This Month': [moment().startOf('month'), moment().endOf('month')],
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')],
'Last 1 Year': [moment().subtract(1, 'years'), moment()],
'Last 2 Year': [moment().subtract(2, 'years'), moment()],
'All Time': [moment('2013-03-01'), moment().subtract(1, 'month').endOf('month')]
};
var startInput = document.getElementById("p_start");
startInput.setAttribute("value", ranges[e.dataset.key][0].format( "YYYY-MM-DD" ));
var endInput = document.getElementById("p_end");
endInput.setAttribute("value", ranges[e.dataset.key][1].format( "YYYY-MM-DD" ));
var rangeForm = document.getElementById("daterange");
rangeForm.submit();
}
</script>

hiddenフォームの値を作成してボタンがクリックされたらsubmitするようにしました(日付処理はmoment.js)
moment.jsもbootstrapも既にredashに組み込まれているようなので特に新たに読み込み直さなくてもOK
本当はdaterangepickerを使って楽しようと思ったのですがjqueryの依存か何かでうまく実装できなかったのでこういう形に
一日単位でずらして見比べるよりある程度の間隔を区切ってデータを見るような感じの内容だってのでこれで十分という判断で付け焼刃実装。。。
すべてのデータを保存する
クエリやダッシュボードのデータはpostgresに保存されているのでグラフを作り終えたらダンプしておけばどの環境でもダッシュボードを再現できます
もちろんdatasourceのデータも再現できるようにしておく必要はありますが...
上述のcreate_database.shも結局のところpostgresに対してデータを追加しているようなのでダンプしてあげればOKそう
postgresについては他記事に書いてます
今回は公式のpostgresイメージで動かしているので初期データとして所定のディレクトリに配置することで起動時に実行してくれる
entrypoint.shの中身を見ると下記のようなコードがありました
79 >...>...for f in /docker-entrypoint-initdb.d/*; do ..... .....
ということで、/docker-entrypoint-initdb.d/以下にdump用のSQLファイルを置けばよさそうですね
まとめ
- widgetでHTMLを直接書いたりできるのでアイデア次第で面白いことができそう
- widgetの幅が現状だと画面の半分か全ての二つしかない、かつ縦の位置も調整があまり賢くない
- datasourceに対するクエリは自分で書かなくてはいけないのである程度各datasourceに対する知識が必要
- 欲しいデータをすらすら問い合わせできるようになっていないと大変そう
- URLのシェアはできるがクエリパラメータには対応していない?
- povotテーブル、コホートが使えるので便利
- クエリごとに定期実行ができるのでものによって調整できる
- テーブル表示の際に特定のカラムに対してfilterをかけられるのは便利
- 現状だと複数datasourceを組み合わせての可視化はできない
今回は集計用のデータの作成から行ったので結構時間がかかりました。
(といったものの、GoogleAnalyticsのデータであればスプレッドシート経由で特に苦労せずに可視化できるようです。。。完全に無駄なことをしました。後日やってみます)
あと、各datasourceに対する知識は必要なのでうまく使わないと結構コストがかかるイメージ
今回使ったデータはMySQLのみだったので今度は他のdatasourceからredashで可視化してみたいと思いました
参考
いつの間にかre:dashの設定が簡単になってた(Dockerを使えば) - ただふれたものについて書くブログ
re:dashのダッシュボードで入力フォームを活用する - Qiita