Redash Meetup #0 ハンズオン振り返り

Redash Advent Calendar完走おめでとうございます!

qiita.com

この記事では、先日開催したRedashのハンズオンイベントの振り返りをします。

redash-meetup.connpass.com

振り返りの方法は定番のKPTでおこなうものとします。

思いついた順に書いているので前後関係がなく、ブログとしては読みにくいかもしれませんが、そういうものだと思ってご了承ください。

Keep: よかったこと、継続したいこと

  • id:kakku22 が公開したハンズオン資料を見てイベントを思いつき、同時に成功をイメージできた
  • ハンズオンを企画し、実施できた
  • 初日にキャンセル待ちになるほど募集を集めることができた
  • ハンズオンを予定通り実施できた
  • ハンズオンの欠席者が0だった
  • ブログやTwitterでハンズオンの感想をもらえた
  • ハンズオンの準備をTrelloで進捗共有・追跡できた
  • 余裕のあるスケジュールでイベントの準備ができた
  • 当日の準備や受付、進行などを円滑に進められた
  • ハンズオンの再演や、情報共有目的のMeetup実施に自信が持てた

Problem: 発生した問題、改善したいこと

  • ハンズオンの成功を第一の目標にしたため、募集人数を少なめに設定した
  • 募集から開催までの時間が約2週間と短めだった
  • 募集を先着順にしたため、あとからイベントを知った人が参加できなかった
  • Advent Calendarなどで告知をしたが、すでにキャンセル待ちになっていた
  • ハンズオン環境構築で想定外のトラブルがいくつかあった
  • ハンズオンの進行方法にばらつきがあった

Try: 試してみたいこと

  • ハンズオンの募集人数を増やす
  • 環境構築をスキップした手順にして、Redash自体を学ぶことにフォーカスする
  • ハンズオンのメンターを募集する
  • 自由演習を増やし、すでにハンズオンを試した人でも楽しめるものにする
  • Redashについての質問などを事前に募集し、ハンズオンの中で議論や事例を共有する
  • ハンズオン以外のイベントを計画する
  • Advent Calendar参加者の方にコンタクトし、イベントでの登壇をお願いする

まとめ

Redashのイベントは2年ほど前から開催してみたいと思っていましたが、どのような参加者層に向けて、何をするといいのか。というのが具体的にイメージできなかったため、実施までは至りませんでした。

今回は、各社での運用事例記事、RebuildSoftware DesignなどのメディアでRedashが紹介されたこともあり、いいタイミングでイベントを開催できたと思います。

当日ご参加いただいたみなさま、キャンセル待ちでも参加意思表明をしてくださったみなさま、そして、すばらしいハンズオン資料を提供しつつ、共同運営をTrelloドリブンに推し進めてくれた id:kakku22 のおかげでいいイベントにすることができました。

ありがとうございました!

次回の開催について

次回は1月下旬を予定にハンズオンの再演を検討しています。

今回の経験を踏まえ、ハンズオンの手順や進行をチューニングし、より多くのかたに参加していただけるよう、募集人数を増やす予定です。

現在、会場の確保を確認しており、年内には募集開始できるように進めています。

また、ハンズオンではない情報共有のイベントについても、2月ごろに一度開催したいと考えておりますので、登壇にご興味があれば、Twitterなどでお声がけいただけるとうれしいです。

Redashの長期運用を見据えてクエリの名前付けについて考える

この記事はRedash Advent Calendar 2017 24日目の記事です。

qiita.com

Redashのクエリも名前付け重要

Redashはフォーク機能によって、あるクエリをもとにした派生クエリを作成することが簡単になっており、新規クエリもUIから簡単に作成できるため、お手本のクエリを参考にしつつ、利用者が欲しいデータをエンジニアを介さずに抽出することができるようになります。

しかし、クエリの作成・フォークがカジュアルにできることによって、「クエリの名前付け」問題が少しずつ影を落としはじめるのも事実です。

クエリ名前付けに関わる問題としては、以下のような問題が考えられます。

  • 何をするためのクエリなのかわからない
  • 同じような名前のクエリがいくつもある
  • フォークを繰り返した結果、"Copy of (#2) Copy of (#1).." のようなクエリが乱立する

過去にはエウレカさんのエンジニアブログでも、「命名規則」についても言及されており、Redash運用において、名前付け問題が避けて通れないことを表しているようにも感じます。

developers.eure.jp

クエリの命名規則を考える

どのような情報をクエリ名に埋め込むべきかは、Redashの導入目的や運用によって異なるものだと思いますが、この記事では例として、以下のようにシンプルな命名規則を定義することにします。

[プロジェクト]_[データソース]_[説明]

情報量の多いクエリ名ではありませんが、作成者や作成日時はクエリ一覧画面で確認することができる一方、どのプロジェクトや案件で使われているのか、どのデータソースを使用しているのかは一覧で表示されないものになるため、このような命名規則としてみました。

kakakakakku/redash-hands-onの資料を例に取ってみると 国の一覧 というクエリ名は ハンズオン_MySQL_国の一覧 のように書き換えられます。

命名規則を運用することの難しさ

シンプルな命名規則を定義できたのであれば、あとは運用するだけです。利用者に周知し、必要であればマニュアル化し、命名規則を徹底してもらいましょう。

さて、これで本当にすべてのクエリが命名規則に従って運用されるでしょうか?

悪気がなくてもクエリの命名規則を間違えてしまったり、フォークしたときの名前をそのまま使ってしまう、緊急対応で命名規則に注意が向かないなど、人間が作業をする以上、100%実行することは難しいと考えています。

クエリ名を定期的にチェックする

人間は必ず間違える、という前提に立ちつつ、命名規則を健全に運用するにはどうするのが良いでしょうか。

私のアイディアとしては、クエリ名を定期的かつ自動的にチェックし、命名規則違反や重複などを検出するのがいいと考えています。

Advent Calendarでもいくつか紹介のあった、Redashのメタデータを使用する方法も考えられますが、この記事では、 redashmanPythonスクリプトを使って、クエリ名が命名規則に従っているかをチェックしてみます。

サンプルスクリプト

redashman がインストールされている前提で、以下のPythonスクリプトを使用します。

#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function

import json
import os
import subprocess
import re

REDASH_API_KEY = os.environ.get('REDASH_API_KEY')
REDASH_URL = os.environ.get('REDASH_URL')
PAGE_SIZE = 100
NAMING_CONVENTION_PATTERN = '\A[^_]+_[^_]+_[^_]+\Z'

names = set()
page = 1

while True:
    cmd = 'redashman query list %d %d --api-key=%s --url=%s --json' % (
        PAGE_SIZE, page, REDASH_API_KEY, REDASH_URL)
    stdout, stderr = subprocess.Popen(cmd, stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE, shell=True).communicate()
    if stderr:
        break

    queries = json.loads(stdout)
    for query in queries['results']:
        name = query['name']
        warning = ''
        if re.match(NAMING_CONVENTION_PATTERN, name) is None:
            warning = u'%s (id: %d) must be follow the naming convention' % (name, query['id'])
        elif 'Copy of' in name.encode('utf-8'):
            warning = u'%s (id: %d) contains "Copy of" in its name' % (name, query['id'])
        elif name in names:
            warning = u'%s (id: %d) is duplicated' % (name, query['id'])

        if warning:
            print(warning)

        names.add(name)

    page += 1

このスクリプトでは、 redashman でクエリの一覧を取得し、

  • [プロジェクト]_[データソース]_[説明] の形式になっていない
  • "Copy of" を含んでいる(Forkしたままのクエリ名になっている)
  • 他のクエリ名と重複している

上記のいずれかの条件に一致する場合は警告メッセージを表示するようになっています。

動作確認

以下のようにクエリが登録してあることを前提として、動作確認します。

f:id:ariarijp:20171223212037p:plain

命名規約違反やクエリ名重複など、運用で困りそうなクエリ名が見受けられますね。

$ export REDASH_URL="http://localhost"
$ export REDASH_API_KEY="adminユーザーのAPIキー"
$ python query_naming_convention.py
ハンズオン_MySQL_都市の一覧 (id: 6) is duplicated
New Query (id: 5) must be follow the naming convention
緊急調査用 (id: 4) must be follow the naming convention
Copy of (#2) Copy of (#1) ハンズオン_MySQL_国の一覧 (id: 3) contains "Copy of" in its name
Copy of (#1) ハンズオン_MySQL_国の一覧 (id: 2) contains "Copy of" in its name

実行してみると、先程定義したルールに従ってクエリ名がチェックされていることがわかります。

このサンプルコードではシンプルにメッセージを表示するだけになっていますが、結果をSlackで送るようにするなどして、運用者が命名規則違反に気づくことができれば、対症療法的な面はありつつも、ルールが破綻しないように運用することができると思います。

Pythonで書いていることを活かし、クエリ名の類似度を取って、紛らわしい名前付けを発見するなどの応用も効きそうです。

まとめ

Redashを長期間運用すると、何に使っているのかわからないようなクエリが混乱のもとになることがあります。

クエリの利用状況をメタデータなどでウォッチすることも有用ではありますが、利用者が見つけやすく、クエリの作成目的がひと目で分かるようなクエリの名前付けを意識し、それを定期的にチェックすることで、ルールの破綻を防ぐことができると考えます。

実のところ、現状は私が運用しているRedashでも、クエリ命名に一貫性がないものが多く、似たような名前のクエリによって調査や対応に手間取るようなことも起き始めています。

せっかくAdvent Calendarの記事にしたので、来年はこの記事で紹介したスクリプトを使って、少しずつ運用を改善していきたいと思います。

pandashでRedashのAPIが返す結果をPandasのDataFrameとして取得する

今日はRedash Advent Calendar 2017 17日目ですね。

qiita.com

mtomitomi.hatenablog.com

上記の記事ではRedashのAPIとPandasを組み合わせる例が紹介されていますが、私も似たようなことをやっているので、この記事では私が実務で使っている方法についても紹介してみます。

事前準備

Redash Advent Calendarでは定番になりつつある以下のリポジトリを使用して、Redashが利用できるようになっていることを前提にします。

github.com

クエリID1として、以下のクエリを登録しておきました。

SELECT * FROM city WHERE CountryCode = '{{CountryCode}}' ORDER BY Population DESC;

また、RedashユーザーのAPIキーが必要になりますが、その手順については、先程も紹介した記事に記載がありますので、そちらを参照してください。

RedashのAPI

業務でもヘビーにRedashを使っているのですが、Redashの /api/queries を例に取ると、アクセスはブラウザからでなくスクリプトからのアクセスが7割を超えています。

Redashのキラーフィーチャーは各社の導入目的によって異なるものだというのをAdvent Calendarに参加して強く感じていますが、私は以下の特徴についてRedashに大きな魅力を感じています。

  • 様々なデータソースに対応している
  • Webアプリとして提供されるためアプリをインストールする必要がなく、誰でもすぐに使い始められる
  • フォーク機能やクエリパラメータを使用して、エンジニアでなくてもある程度クエリをカスタマイズできる
  • APIが提供されているため、外部スクリプトでクエリ結果を使用した処理が作れる

あえて太字にしましたが、特にAPIが提供されているところが、私たちの生産性を大きく押し上げています。

私の場合、APIがなかったらここまでRedashにどっぷりハマることもなかったでしょう。

さらにRedashのAPI、特にクエリ実行をクエリパラメータつきで実行することができる、RedashDynamicQueryがPythonのモジュールとして使用できるので、Redashの便利な機能を気軽に使うことができます。

github.com

余談ですが、RedashDynamicQueryを見つけるまでは、APIではなくスクレイピングCSVダウンロードしていたこともあります。

RedashとPandas

さて、ここまではRedashとRedashDynamicQueryの紹介でしたが、Pythonでデータを扱うとなると、Pandasも関わりの強いモジュールといえます。

Python Data Analysis Library — pandas: Python Data Analysis Library

先程紹介したAdvent Calendarの記事でも、APIの結果をPandasのDataFrameにしてJupyter Notebookで扱うといった例になっていました。

Pandasはデータ操作の機能が便利なのはもちろんのこと、scikit-learnなどの機械学習ライブラリとの相性もいいので、どんなデータでもDataFrameに持ち込んで、あとはPandasで自由にデータ操作できるのがとても便利です。

私の場合、現時点ではRedashのクエリ結果をJOINすることが必要になった場合、RedashのPythonデータソースは使わずにAPIでクエリ結果を取得し、Pandas上で結合するようにしています。

余談ですが、PandasやDataFrameについて、個人的にはRebuildの以下のエピソードの中で出てきた、「DataFrame is JSON for Data Science」という表現がしっくりきました。

rebuild.fm

とにかくDataFrameにしてしまえばあとはどうにでもなる感じがしています。

pandash を使ってRedashのAPIの結果をPandasのDataFrameにする

では、実際にRedashのクエリ結果をPandasのDataFrameとして取得する例を紹介します。

Pandasだけでもそれほど難しい処理にはなりませんが、私は自作の pandash というモジュールを使っています。

github.com

前フリがかなり長くなりましたが、このモジュールを使ってRedashの結果を取得してみます。

インストール

環境に合わせて virtualenvvenv を使っていただくとして、モジュールはREADMEの通り以下のコマンドでインストールできます。

pandash は今のところPyPIには公開していません。

$ pip install redash-dynamic-query
$ pip install git+https://github.com/ariarijp/pandash

サンプルコード

以下のコードを main.py として保存します。

from redash_dynamic_query import RedashDynamicQuery

from pandash import query_to_df

redash = RedashDynamicQuery(endpoint='http://localhost',
                            apikey='REDASHのユーザーAPIキー',
                            data_source_id=1,
                            max_wait=60)

df = query_to_df(redash, 1, {'CountryCode': 'JPN'})

print(df.head(10)[['District', 'Name', 'Population']])

このコードでは、Redash上のクエリID1をクエリパラメータを指定して実行し、結果を上位10件の都道府県名、都市名、人口を表示しています。

これを実行してみると以下のような結果が表示されます。

$ python main.py
    District                 Name  Population
0   Tokyo-to                Tokyo     7980230
1   Kanagawa  Jokohama [Yokohama]     3339594
2      Osaka                Osaka     2595674
3      Aichi               Nagoya     2154376
4   Hokkaido              Sapporo     1790886
5      Kyoto                Kioto     1461974
6      Hyogo                 Kobe     1425139
7    Fukuoka              Fukuoka     1308379
8   Kanagawa             Kawasaki     1217359
9  Hiroshima            Hiroshima     1119117

とてもシンプルなコードでRedashのクエリ結果をPandasのDataFrameにすることができました。

まとめ

Redashのクエリ結果をPandasのDataFrameとして扱えるようになると、データをPandasの統一されたインターフェースで操作できるため、クエリ結果にひと手間かけたい、別の処理に渡す前の前処理をしたいなど、データ活用の幅が広がると思います。

よろしければRedash活用の際にRedashDynamicQueryやPandasとあわせて、 pandash も検討していただけるとうれしいです。

SchemaSpyを使ってRedashのテーブル定義確認を捗らせる

Redashのテーブル定義を確認しようとしたとき、 psql コマンドでも十分だけど、何か便利なツールを探してみたらSchemaSpyがよさそうだったのでメモ。

SchemaSpy • Database Documentation Built Easy.

ツール自体はJavaで書かれているようだけど、Dockerイメージが公開されているので以下の記事を参考にしてDocker上で動作させた。

qiita.com

使ってみる

Redashの検証環境を構築するときはDocker Composeを使っているので、Redashの docker-compose.production.yml を以下のように変更した。

diff --git a/docker-compose.production.yml b/docker-compose.production.yml
index f0b9812d..d4911ae0 100644
--- a/docker-compose.production.yml
+++ b/docker-compose.production.yml
@@ -50,3 +50,10 @@ services:
     links:
       - server:redash
     restart: always
+  schemaspy:
+    depends_on:
+      - postgres
+    image: schemaspy/schemaspy:snapshot
+    command: /entrypoint.sh -t pgsql -host postgres:5432 -db postgres -u postgres -hq
+    volumes:
+      - $PWD/schemaspy/output:/output

これでRedashを起動すると schemaspy/output ディレクトリーに結果が出力される。

index.html を開くと、テーブルの定義やER図が表示されて便利。

画面サンプル

テーブル一覧

f:id:ariarijp:20171216231344p:plain

テーブル定義

f:id:ariarijp:20171216231406p:plain

ER図

f:id:ariarijp:20171216231452p:plain

まとめ

DockerイメージになっているとJREをインストールしたりしなくて良いので楽。

もちろんRedash以外でも使えるツールなので、テーブル定義をさっと確認したいときは便利だと思う。

redashmanを使ってRedashのクエリをお手軽にバックアップする

今日はRedash Advent Calendar 16日目ですが、この記事はAdvent Calendarの記事ではありません。

qiita.com

12/16の記事はvankobeさんによる、Redashの結果をGoogleスプレッドシートで扱う事例の記事です。

qiita.com

Redashの便利さと、その裏にあるつらみ

Redashを活用しはじめて1年半ほど経ちますが、今ではRedashなしで業務が回らなくなるほどに使い倒しています。

しかし、Redashの活用が進んだことによって「Redashが落ちたら全てが止まる」といった状況になりつつあることも事実で、たまにRedashの収容サーバーからアラートが飛んでくると、背筋が凍る思いをしています。

それだけでなく、Redashの利点でもある「誰でもクエリを実行・編集できる」というのが、運用上問題になることも何度か経験してきました。

この記事ではRedashのクエリのバックアップについて、自作のツール redashman の宣伝もしつつ紹介していきます。

Redashのバックアップ

ざっくりですが、すぐ思いつくバックアップ方法は以下の2つと考えています。

  • Redashインスタンスのディスクイメージのスナップショットを取得する
  • Redashの管理DB(PostgreSQL)のDBバックアップを取得する

構成にもよりますが、ディスクイメージのバックアップはIaaSを使っていれば、もっとも簡単かつ安心できる方法かと思います。

管理DBのバックアップは、バックアップスクリプトや保存先を用意する必要がありますが、PostgreSQLについて少し知識があれば簡単に実現できる方法と言えます。

上記のように、ディスクやデータベースの単位でバックアップをとっておくことは運用上重要なことですが、「クエリ」のバックアップについても考えてみます。

Redashは誰でも気軽にクエリを実行・編集することができる一方で、悪意の有無に関わらず、誤ってクエリを編集してしまい、クエリが実行できなくなってしまうことが考えられます。

しかし、先に紹介したディスクやデータベースによるバックアップは「クエリ」のバックアップという点で考えるとリストアの手間もあり、少し大げさに感じる部分があります。

redashman について

現在、私は redashman という自作のツールを用いて、Redashのクエリを定期的にバックアップしています。

github.com

Redashを管理するので redashman という名前にしましたが、なぜか青いロボットが針に当たってティウンティウンする光景が目に浮かんだかたは個別にご連絡ください。私はX4が好きです。

このツールはクエリの一覧、取得、作成などをCLIから実行するためのツールとして作成しましたが、その中にクエリの定義を取得するものがあるので、それを使ってクエリをバックアップしています。

インストール

redashman はGoで書いたので、go get で簡単にインストールできます。

$ go get -u github.com/ariarijp/redashman

redashman を使用したクエリのお手軽バックアップ

redashman 自体の使い方についてはREADMEを参照していただくとして、付属のPythonスクリプトを使用してバックアップをしてみます。

$ mkdir redash_backup
$ cd redash_backup
$ cp $GOPATH/src/github.com/ariarijp/redashman/scripts/backup_queries.py ./
$ export REDASH_URL=http://localhost
$ export REDASH_API_KEY="Redashのadmin権限があるユーザーのAPIキー"
$ python ./backup_queries.py
$ ls -la backup
total 48
drwxr-xr-x  8 ariarijp  wheel  272 12 16 14:34 .
drwxr-xr-x  4 ariarijp  wheel  136 12 16 14:34 ..
-rw-r--r--  1 ariarijp  wheel   23 12 16 14:34 0001.sql
-rw-r--r--  1 ariarijp  wheel   51 12 16 14:34 0002.sql
-rw-r--r--  1 ariarijp  wheel   89 12 16 14:34 0003.sql
-rw-r--r--  1 ariarijp  wheel   83 12 16 14:34 0004.sql
-rw-r--r--  1 ariarijp  wheel   89 12 16 14:34 0005.sql
$ cat backup/0001.sql
SELECT * FROM country;

これでクエリのバックアップを取得することができるようになりました。

定期的にバックアップし、変更履歴も残す

定期的にバックアップをするには、もう一手間かける必要があります。

そのために、以下のスクリプトbackup.sh として保存し、実行権限を与えておきます。

#!/bin/bash

export REDASH_URL=http://localhost
export REDASH_API_KEY="Redashのadmin権限があるユーザーのAPIキー"

cd `dirname $0`

if [ ! -d '.git' ]; then
  git init
fi

python backup_queries.py
git add . && git ci -a -m `date '+%Y%m%d%H%M%S'`

これを実行すると、先ほどのPythonスクリプトでクエリのバックアップを取得し、そのファイルがGitリポジトリにコミットされます。

$ ./backup.sh
Initialized empty Git repository in /private/tmp/redash_backup/.git/
[master (root-commit) 820ae32] 20171216144840
 8 files changed, 49 insertions(+)
 create mode 100755 backup.sh
 create mode 100644 backup/0001.sql
 create mode 100644 backup/0002.sql
 create mode 100644 backup/0003.sql
 create mode 100644 backup/0004.sql
 create mode 100644 backup/0005.sql
 create mode 100644 backup_queries.py

このスクリプトcron などを使って適当な間隔で定期実行すれば、クエリのバックアップを定期的に、かつ、Gitを使用することで履歴とタイムスタンプ付きで保存することができるようになります。

まとめ

Redashの気軽さを維持しつつ、redashman でクエリを定期的にバックアップすることで、クエリを誤って編集してしまったなどのトラブルに対処できるようになり、副産物としてクエリの編集履歴もGitという多くの開発者の手に馴染んだツールで管理できるようになります。

Redashの利用をこれから検討している方にも、ぜひ redashman の導入を検討してみてほしいです。

宣伝

id:kakku22 と私の主催で、ハンズオン形式のRedash Meetup #0 を12/19(火)に開催しますが。ありがたいことにキャンセル待ちが出ています。

redash-meetup.connpass.com

ハンズオンイベントについては来年1月に再演を計画していますので、今回予定が合わなかったり、キャンセル待ちから繰り上がらなかった方も、改めて参加を検討していただけるとうれしいです。

また、今後はハンズオンイベントではなく、各社の導入事例を成功も失敗も含めて共有できるような企画も検討しておりますので、Redashに興味があるかたは、よろしければConnpassのRedash Meetupグループに参加してみてください。

redash-meetup.connpass.com

このグループに参加していると、次回のハンズオンも含め、今後のイベント日程もチェックしやすくなると思います。