Redashで使われているPythonモジュールメモ

Redashのコードを追うときに知っておくとよさそうなモジュールを個人的にメモ。

コミットIDは以下のもので調べたので。バージョン違いなどで差異があると思う。

github.com

依存関係を調べる

requirements.txt を読んでいってもいいけど、 pipdeptree が便利そうだったので使った。

github.com

$ pipdeptree
celery==3.1.23
  - billiard [required: >=3.3.0.23,<3.4, installed: 3.3.0.23]
  - kombu [required: <3.1,>=3.0.34, installed: 3.0.37]
    - amqp [required: >=1.4.9,<2.0, installed: 1.4.9]
    - anyjson [required: >=0.3.3, installed: 0.3.3]
  - pytz [required: >dev, installed: 2016.7]
Flask-Admin==1.4.2
  - Flask [required: >=0.7, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
  - wtforms [required: Any, installed: 2.1]
Flask-Limiter==0.9.3
  - Flask [required: >=0.8, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
  - limits [required: Any, installed: 1.2.1]
    - six [required: >=1.4.1, installed: 1.10.0]
  - six [required: >=1.4.1, installed: 1.10.0]
Flask-Login==0.4.0
  - Flask [required: Any, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
Flask-Mail==0.9.1
  - blinker [required: Any, installed: 1.3]
  - Flask [required: Any, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
Flask-Migrate==2.0.1
  - alembic [required: >=0.6, installed: 0.9.6]
    - Mako [required: Any, installed: 1.0.7]
      - MarkupSafe [required: >=0.9.2, installed: 0.23]
    - python-dateutil [required: Any, installed: 2.4.2]
      - six [required: >=1.5, installed: 1.10.0]
    - python-editor [required: >=0.3, installed: 1.0.3]
    - SQLAlchemy [required: >=0.7.6, installed: 1.1.4]
  - Flask [required: >=0.9, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
  - Flask-Script [required: >=0.6, installed: 2.0.6]
    - Flask [required: Any, installed: 0.11.1]
      - click [required: >=2.0, installed: 6.6]
      - itsdangerous [required: >=0.21, installed: 0.24]
      - Jinja2 [required: >=2.4, installed: 2.8]
        - MarkupSafe [required: Any, installed: 0.23]
      - Werkzeug [required: >=0.7, installed: 0.11.11]
  - Flask-SQLAlchemy [required: >=1.0, installed: 2.1]
    - Flask [required: >=0.10, installed: 0.11.1]
      - click [required: >=2.0, installed: 6.6]
      - itsdangerous [required: >=0.21, installed: 0.24]
      - Jinja2 [required: >=2.4, installed: 2.8]
        - MarkupSafe [required: Any, installed: 0.23]
      - Werkzeug [required: >=0.7, installed: 0.11.11]
    - SQLAlchemy [required: >=0.7, installed: 1.1.4]
Flask-OAuthlib==0.9.3
  - Flask [required: Any, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
  - oauthlib [required: >=0.6.2, installed: 2.0.6]
  - requests-oauthlib [required: >=0.5.0, installed: 0.8.0]
    - oauthlib [required: >=0.6.2, installed: 2.0.6]
    - requests [required: >=2.0.0, installed: 2.11.1]
Flask-RESTful==0.3.5
  - aniso8601 [required: >=0.82, installed: 1.1.0]
    - python-dateutil [required: Any, installed: 2.4.2]
      - six [required: >=1.5, installed: 1.10.0]
  - Flask [required: >=0.8, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
  - pytz [required: Any, installed: 2016.7]
  - six [required: >=1.3.0, installed: 1.10.0]
Flask-SSLify==0.1.5
  - Flask [required: Any, installed: 0.11.1]
    - click [required: >=2.0, installed: 6.6]
    - itsdangerous [required: >=0.21, installed: 0.24]
    - Jinja2 [required: >=2.4, installed: 2.8]
      - MarkupSafe [required: Any, installed: 0.23]
    - Werkzeug [required: >=0.7, installed: 0.11.11]
funcy==1.7.1
gunicorn==19.7.1
honcho==0.5.0
httplib2==0.10.3
jsonschema==2.4.0
parsedatetime==2.1
passlib==1.6.2
pipdeptree==0.10.1
  - pip [required: >=6.0.0, installed: 9.0.1]
psycopg2==2.7.3.2
pysaml2==2.4.0
  - argparse [required: Any, installed: 1.1]
  - decorator [required: Any, installed: 4.1.2]
  - paste [required: Any, installed: 2.0.3]
    - six [required: >=1.4.0, installed: 1.10.0]
  - pycrypto [required: >=2.2, installed: 2.6.1]
  - pyOpenSSL [required: Any, installed: 16.2.0]
    - cryptography [required: >=1.3.4, installed: 2.0.2]
      - asn1crypto [required: >=0.21.0, installed: 0.24.0]
      - cffi [required: >=1.7, installed: 1.11.2]
        - pycparser [required: Any, installed: 2.18]
      - enum34 [required: Any, installed: 1.1.6]
      - idna [required: >=2.1, installed: 2.6]
      - ipaddress [required: Any, installed: 1.0.19]
      - six [required: >=1.4.1, installed: 1.10.0]
    - six [required: >=1.5.2, installed: 1.10.0]
  - python-dateutil [required: Any, installed: 2.4.2]
    - six [required: >=1.5, installed: 1.10.0]
  - pytz [required: Any, installed: 2016.7]
  - repoze.who [required: Any, installed: 2.3]
    - setuptools [required: Any, installed: 38.2.5]
    - WebOb [required: Any, installed: 1.7.4]
    - zope.interface [required: Any, installed: 4.4.3]
      - setuptools [required: Any, installed: 38.2.5]
  - requests [required: >=1.0.0, installed: 2.11.1]
  - zope.interface [required: Any, installed: 4.4.3]
    - setuptools [required: Any, installed: 38.2.5]
pystache==0.5.4
raven==6.0.0
  - contextlib2 [required: Any, installed: 0.5.5]
redis==2.10.5
RestrictedPython==3.6.0
  - setuptools [required: Any, installed: 38.2.5]
semver==2.2.1
simplejson==3.10.0
sqlparse==0.1.8
statsd==2.1.2
wheel==0.24.0
XlsxWriter==0.9.3

(自分にとって)重要そうなモジュール

Flask

github.com

WebアプリケーションフレームワークDjangoと並んで有名なのでよく使われている印象。

Redashのサーバーサイドで使われている。

Jinja2

github.com

Redashのサーバーサイドのテンプレートエンジン。

Click

github.com

CLI作成ツール。RedashのCLIでも使われている。

Flaskと同じ作者だったはず。

SQLAlchemy

github.com

DB周りのいろいろ+ORM。Redashでは以前Peeweeが使われていたけど今はこっち。

Alembic

bitbucket.org

DBマイグレーションツール。SQLAlchemyと作者が同じっぽい。

Gunicorn

github.com

WSGIに対応したアプリケーションサーバー。Flaskはこの上で動いている。

Celery

github.com

タスクキュー。RedashのクエリはすべてCelery上で動く。

pystache

github.com

MustacheのPython実装。Redashではクエリにパラメータを埋め込むときに使われている。

RestrictedPython

github.com

制限付きのPythonを実行するためのモジュール。Pythonデータソースで使われている。

まとめ

データソースに関わるもの以外では、だいたいこなれたモジュールが使われていて、コードを読もうとしたらそれなりに読めるしわかる。というのもRedashの良さの一つかもしれない。

Python ライブラリ厳選レシピ

Python ライブラリ厳選レシピ

2017年まとめ

大晦日なので振り返り。早く書いてゆっくり過ごしたいので、箇条書きでざっくり振り返る。

今年やってたこと

  • Redashを去年以上に使うようになった。Redashの活用が進むにつれてインフラ構成を変えたりもした
  • Redash絡みでPythonを書くようになった。今ではどの言語よりもPythonを書いている時間が長いと思う。その次はたぶんSQL
  • 出張でシンガポールとSFに行った。もうちょっと英語勉強したほうがいいと思いつつやってないので良くない
  • 新卒のメンターは3月で終わり。今ではすっかり主戦力になってくれて頼もしい限り
  • 社内勉強会もほどほどにやった

ブログ

イベント参加

  • あまり積極的には参加しなかった
  • 登壇はSpeaker Deckを見る限り3回ぐらい
  • よく使っているRedashを題材にイベント主催を経験できた。ペースはさておき、Redash使い続けているうちは来年も引続きイベントをやっていきたい

OSS

  • Redashなど、仕事で使っているソフトウェアにPRを送ったりした
  • 文法も単語もかなり怪しい英語だとは思うけど、去年よりはPRのコメントなどがすっと書けるようになったような気がする
  • 自作のツールをいくつかGithubで公開した。 go-zabbix-slack-alert , redash-api-client , crontoc , redashman あたりは仕事でもよく使ってる

買ってよかったもの

Amazonの購入履歴見たところ、今年は過去最多の購入数な気がする。定期おトク便もかなり使った。

Nintendo Switchは久しぶりのゲームコンソール購入だったけど、ゼルダBotWをキッカケにゲーム熱が再燃しつつあって、今はゼノブレイド2を買おうか悩んでる。

まとめ

  • 他にもいろいろあったけど、今年も楽しくやれたと思う
  • 自分のキャリアとか方向性は全然考えることがなく、目の前の仕事をひたすらこなしていた。という感じが強くて少し悩みもある
  • 去年は英語を課題にしていたけど、1年経ってみてそれほど変わって無い気もするし、少し良くなった気もする。定量的に判断できないので、年1回TOEICを受けるぐらいのことはしておいたほうがいいかもしれない
  • 今年はPythonをそれなりに書けるようになったので、来年はJavaScriptを少しがんばってみるかもしれない
  • Redashのイベントは早速来月末に予定。ハンズオン以外のイベントも企画する

かなりざっくりだけど、以上でまとめおわり。今年もおつかれさまでした!良いお年を!

Raspberry Pi 2にRedashをインストールする

「Re:dash on Raspbery Pi」という投稿を見かけたので、ちょっとしたお遊びでやってみた。

discuss.redash.io

使用したデバイス

ちょっと古いけど検証にはRaspberry Pi 2 Model Bを使用。Raspberry Pi 3でも動くと思う。

Raspberry Pi 2 Model B (2015年2月発売品)

Raspberry Pi 2 Model B (2015年2月発売品)

OSはRaspbian stretch Lite(November 2017)を使いました。

www.raspberrypi.org

インストール

セットアップスクリプト

Raspbianも名前からしDebian系なので、RedashのUbuntu向けセットアップスクリプトにすこし改変を加えて使う。

github.com

@@ -41,7 +41,7 @@
     # Base packages
     apt install -y python-pip python-dev nginx curl build-essential pwgen
     # Data sources dependencies:
-    apt install -y libffi-dev libssl-dev libmysqlclient-dev libpq-dev freetds-dev libsasl2-dev
+    apt install -y libffi-dev libssl-dev libmariadbclient-dev libpq-dev freetds-dev libsasl2-dev
     # SAML dependency
     apt install -y xmlsec1
     # Storage servers
@@ -71,6 +71,9 @@
 }
 
 install_python_packages() {
+    sed -i 's/cryptography==1.4/cryptography==2.1.4/' /opt/redash/current/requirements.txt
+    sed -i 's/pyOpenSSL==0.14/pyOpenSSL==16.2.0/' /opt/redash/current/requirements_all_ds.txt
+    sed -i 's/cassandra-driver==3.1.1/#cassandra-driver==3.1.1/' /opt/redash/current/requirements_all_ds.txt
     pip install --upgrade pip
     # TODO: venv?
     pip install setproctitle # setproctitle is used by Celery for "pretty" process titles

変更点は以下の通り。

  • Raspbian StretchはMySQLではなくMariaDBを使うのが標準なので、 libmysqlclient-dev ではなく libmariadbclient-dev を使う
  • pip install でエラーになるため、 cryptographypyOpenSSL のバージョンを上げる
  • Cassandra データソースはデフォルトで有効になっていないわりに依存ライブラリのビルドに時間がかかるのでコメントアウト

RaspbianにRedashをインストール

セットアップスクリプトをRaspbianをクリーンインストールしたRaspberry Piに転送し、実行する。

$ sudo bash bootstrap.sh.raspi

そのまま動いてくれればいいのだけれど、以下のようなエラーが pip あたりで起きて止まる。

TypeError: unsupported operand type(s) for -=: 'Retry' and 'int'

pip の設定やオプションで解決したかったけど、解決方法が特定できなかったので pip install を何度か実行して成功するまで繰り返した。

PIP_DEFAULT_TIMEOUT を長めにしておくと少しエラーが減った気がするが、気のせいかもしれない。

$ export PIP_DEFAULT_TIMEOUT=600
$ sudo pip install -r /opt/redash/current/requirements.txt
$ sudo pip install -r /opt/redash/current/requirements_all_ds.txt

pip install が実行できたら、 /opt/redash を削除してから再度セットアップスクリプトを実行する。

pip install は先の手順で実行済みなので割と早く終わるはず。

$ sudo rm -rf /opt/redash
$ sudo bash bootstrap.sh.raspi

これでRedashが起動するので、ブラウザで http://raspberrypi.local/setup など、Raspberry PiのURLにアクセスしてadminユーザーを作る。

動作確認

SQLiteでさくっと動作確認。

$ cd /tmp
$ wget https://github.com/wallymathieu/sakila-sample-database-ports/raw/master/sqlite-sakila-db/sqlite-sakila.sq

SQLiteデータソースを作成してから、以下のクエリを実行してみる。

SELECT * FROM actor LIMIT 10;

f:id:ariarijp:20171229235740p:plain

動いたっぽい。

まとめ

実用上どうするかはさておき、Raspberry Pi上でもRedashは動くということがわかった。 だけど、MicroSDのIOがとにかく遅いのであんまりおすすめしない。

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の記事にしたので、来年はこの記事で紹介したスクリプトを使って、少しずつ運用を改善していきたいと思います。