re:dashのQuery Snippetsについて

re:dash Advent Calendar 2016 2日目の記事です。

qiita.com

Query Snippetsとは

0.12で追加されたre:dashの新機能で、よくあるSQLを文字通りスニペットとして登録することができ、クエリエディター上でSQLを書く際に、特定のキーワードに反応してスニペットを保管してくれます。

今年のre:dash Advent Calendar 1日目の記事でも少し触れられていました。

blog.redash.io

qiita.com

スニペットを登録する

0.12ではSettingsにメニューが追加されていますので、試しにスニペットを登録してみます。

f:id:ariarijp:20161202150141p:plain

Triggerにはどんな文字列が入力されたときにスニペットで補完するかを指定できるので、ここでは__cnt としています。アンダースコア2つを付けたのは、スニペットだとわかるようにするためですが、どんな文字列でもよいと思います。

Descriptionは必須ではないのですが、説明を書いておいたほうがよいでしょう。

Snippetに補完したいSQLを書きます。

ここで ${1:table} という文字列を使用していますが、これについては後述します。

一通り書き終わったら保存しましょう。

f:id:ariarijp:20161202150155p:plain

スニペットを使用する

スニペットを登録したら、クエリエディターで使用してみます。

f:id:ariarijp:20161202150209g:plain

クエリエディター上で __ と入力すると __cnt が補完され、決定すると __cnt でトリガーされるスニペットがエディター上に展開されます。

先程、 ${1:table} と入力した箇所はプレースホルダーになりますので、その箇所をテーブル名で置き換えてクエリーを実行しました。

プレースホルダーは複数記述することができ、エディター上ではTABキーで移動しながら入力できます。

テーブル名やカラム名の補完も相まって、すばやくSQLを書くことができますね。

まとめ

スニペットを使うことで作業の効率化はもとより、エンジニアでなくてもある程度お決まりのSQLが書けるようになるかもしれません。

また、似たようなクエリーを無邪気にForkしていくと、あっという間にクエリーが増えていくので、使い回しの効くものをスニペットにしておくというような運用もよさそうです。

とはいえ、実は現在プロダクションで使用しているバージョンが0.10なので、アップデートから検討しなければいけないというのが、個人的な悩み事です。

re:dash Advent Calendar 2016 について

まだまだ枠が空いているようです。

今年はre:dashが話題にあがることも多かったですし、実際に使われているかたも増えているような印象なので、小ネタでも参加してみてはいかがでしょうか?

supersetをVagrantで起動する

iktakahiro.hatenablog.com

週末にこの記事を読んでsupersetを試してみたくなったので、Vagrantで起動できるようにしてみました。

supersetのお試し環境構築 · GitHub

VagrantfileでShell Provisioningしている環境構築手順は、ほぼ公式ドキュメントのインストール手順通りです。

Installation & Configuration — Superset's documentation documentation

使い方

Gistからシェルスクリプトをダウンロードして実行するだけです。

$ mkdir superset
$ cd superset
$ wget https://gist.githubusercontent.com/ariarijp/f04c51feff8bfff73a53e7958474a942/raw/db67ddac46e53dbd3db139c3e7abdf8a4f70f504/run.sh
$ chmod +x run.sh
$ ./run.sh

VMが起動したら、ブラウザで http://localhost:8088/ にアクセスすると、以下のような画面が表示されます。

f:id:ariarijp:20161128232758p:plain

ユーザー名とパスワードは admin / superset としていますので、それらを入力してログインします。

f:id:ariarijp:20161128232923p:plain

ログインできました。あとはサンプルのダッシュボードを見たりしてみましょう。

まとめ

DockerではなくVagrantを使ってみましたが、ドキュメント通りで特に困ること無く環境構築できました。

FullPageOSでRaspberry Piをキオスク端末にする

なぜか家に2つも転がっているRaspberry PI 2を見て、ふと思い立ったのでキオスク端末にしてみました。あまり使わないけれど、Raspberry Pi 3がなんとなく欲しいです。

Raspberry Pi Kiosk」で検索すると、起動時にChromiumを自動的に実行するように設定するのが一般的なようですが、FullPageOSというそれっぽい名前のRaspbian派生OSを見つけました。

github.com

FullPageOSも起動時にChromiumをキオスクモードで起動しているだけではあるのですが、インストールするだけで目的が達成できそうなので、これを使ってみることにしました。

インストール

READMEに記載されているミラーサイトからダウンロードします。

2016/11/14現在は「2016-07-20_2016-05-27-fullpageos-jessie-lite-0.7.0.zip」が最新版のようです。

ダウンロードしたファイルをunzipなどで展開すると、2016-05-27-fullpageos-jessie-lite-0.7.0.imgファイルができるので、このファイルをRaspbian導入時と同じようにddコマンドなどでSDカードに書き込みます。

www.raspberrypi.org

起動

起動については特に他のOSと変わらず、MicroSDを挿した状態で電源ケーブルを差し込むだけです。

ディスプレイを繋いでも表示されない場合は、HDMIケーブルを挿した状態で電源ケーブルを挿し直してみてください。

起動が完了するとChromiumでWelcomeページが表示されます。

f:id:ariarijp:20161128134337p:plain

SSHでログイン

FullPageOSはBonjourを使って fullpageos.local でアクセスできるようになっているので、このアドレスを使ってSSHログインすることができます。

デフォルトのユーザー名/パスワードはRaspbian同様に pi / raspberry です。

無線LANの設定

無線LANの環境があれば配線も楽なので、Raspberry Piも無線で使いたい場合が多いと思います。

FullPageOSは起動時にChromiumがフルスクリーンで起動されるため、GUIで設定をすることは(おそらく)できません。

代わりに、ネットワークなどの主要な設定はテキストファイルに記述することができます。

無線LANの設定は /boot/fullpageos-network.txt を書き換えることで設定できます。

...
## WPA/WPA2 secured
iface wlan0-fullpageos inet manual
    wpa-ssid "アクセスポイントのSSID"
    wpa-psk "パスワード"
...

表示される画面の設定

FullPageOSには、いくつかの画面をローテーション表示する仕組みがデフォルトで備わっています。

github.com

仕組みと言っても、中身は登録されたURLをiframeで表示し、一定時間で切り替えるだけの簡素なものですが、ブラウザ上でタブの追加・削除ができるようになっており、画面を表示するだけなら特に不自由もないと思います。

また、 http://fullpageos.local/FullPageDashboardRaspberry Pi以外のブラウザからもアクセスすることができます。

以下の例はDashingのデモページを表示するようにしてみたものです。

f:id:ariarijp:20161128134814p:plain

不便なところ

外部のブラウザからFullPageDashboardで設定を書き換えたときに、画面を再読込することができないため、毎回 reboot などで再起動することになります。

多少不便ではありますが、そんなに画面を追加・削除するものでもないですし、起動も数分で済むのでこれは気にしないようにしていますが、少し不便です。

Raspberry Piにキーボードを繋げてしまえばそれで済む話なのですが、それなら再起動してしまったほうが楽かなと思ってそうしています。

まとめ

執務室内にダッシュボード的に大型のディスプレイを置く会社も増えてきていますが、最近のディスプレイはUSB端子もあるので、USB給電が可能という点でもRaspberry Piを使用するというのもよいかもしれません。

その場合、Raspberry Pi 3は電源を選ぶので、あえてRaspberry Pi 2というのもありですね。

エンジニア立ち居振舞い: なぜ必要なのかをちゃんと聞く

お題「エンジニア立ち居振舞い」

なぜ必要なのかをちゃんと聞く

今の主な仕事は社外向けと社内向けのものがあって、今回は後者の話。

いわゆる「社内ツール」というようなやつで、定形作業の負荷を少しでも減らすとか、誰かの職人芸でなんとかやってる作業を、うまく仕組みにして誰でもできるようにするとか、あとはデータを上手く集めて、ちょっと扱いやすく加工したりとか、そういうこともやっている。

で、社内でそういった困り事を相談してくれる人たちは、当然ながら自分よりも彼らの業務をよく知っていて、そのうえで「こんなことをしたい」という相談をしてくれるし、自分もある程度はその業務がどのように改善されるかとか、どんな設計にしたらいいか、どんなデータを集めてあげればいいかは想像がすることができる程度の業務知識はあるけど、そういった話のなかですっぽりと抜け落ちることがあるのが「なんでそれが必要なのか」じゃないかと思う。

自分はせっかちなので、「なるほど。そういうことね」とか、「あ、これでいける」と思ったらすぐに手を動かしてしまいたくなる。そういうときこそ、ちょっと意識的に「なんでそれがあると嬉しいんだろう?なんで必要なんだろう?」というのを、ここ数年は考えたり、直接聞いてみたりするようになった。

「なぜ必要なのか?」と改めて聞いてみると、自分のイメージ通りだったりもするし、ズレてた認識を修正できるかもしれないし、それはすでに別のツールがカバーしている問題かもしれないし、もしかしたら、もっと別の大きな課題が今の状況を引き起こしていることに気づくかもしれない。特に最後に挙げたようなものが見つかれば儲けものだ。

「ユーザーは自分が何を求めているか、ユーザー自身はそれを本当に知っているのか?」というのを、この前プロダクトマネージャーカンファレンスでも聞いた気がする。ちょっとした社内ツールでも、「なんでそれが必要なのか?」を(社内の)ユーザーから引き出し、エンジニアとして彼らの困り事を本当に解決するものを作っていきたいなと思っている。

re:dashでよく使われているクエリーを調べる

re:dashのFork機能はすごく好きなんだけど、便利すぎて気軽にForkされる結果、使ってるのか使ってないのかわからないクエリーが増えてしまいがち。

qiita.com

この記事をみたら統計情報っぽいのが取れるようなので、ちょっといじって以下のようにした。

使用しているバージョンは 0.10.1+b1836

SELECT 
  object_id AS query_id, 
  SUM(CASE WHEN action = 'view' THEN 1 ELSE 0 END) AS view,
  SUM(CASE WHEN action = 'execute' THEN 1 ELSE 0 END) AS execute
FROM 
  events 
WHERE 
  object_type = 'query' 
  AND object_id != ''
  AND created_at BETWEEN to_date('2016-11-01', 'YYYY-MM-DD') AND to_date('2016-11-17', 'YYYY-MM-DD')
GROUP BY 
  object_id 
ORDER BY 
  execute DESC;

結果はこんな感じ。

object_id | view | execute
-----------+------+---------
 78        |  125 |      99
 68        |  123 |     106
 87        |   68 |      66
 79        |   68 |      55
 85        |   68 |      42
 103       |   63 |      50
 107       |   59 |      43
 8         |   58 |      13
 89        |   53 |       7
 125       |   52 |      28
 109       |   48 |      21
 104       |   44 |      11
 112       |   39 |      21
 100       |   39 |      19
 115       |   31 |       2
 122       |   25 |       9

この結果をみて、使用頻度の低いクエリーは積極的にアーカイブすることができそう。

おまけ

events テーブルはこんな感じ。

                                        テーブル "public.events"
          列           |            型            |                       修飾語
-----------------------+--------------------------+-----------------------------------------------------
 id                    | integer                  | not null default nextval('events_id_seq'::regclass)
 org_id                | integer                  | not null
 user_id               | integer                  |
 action                | character varying(255)   | not null
 object_type           | character varying(255)   | not null
 object_id             | character varying(255)   |
 additional_properties | text                     |
 created_at            | timestamp with time zone | not null
インデックス:
    "events_pkey" PRIMARY KEY, btree (id)
    "events_org_id" btree (org_id)
    "events_user_id" btree (user_id)
外部キー制約:
    "events_org_id_fkey" FOREIGN KEY (org_id) REFERENCES organizations(id)
    "events_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id)

action, object_typeにはこんな値が入っていた。

action

add_data_source
add_member
api_get
archive
autorefresh
cancel_execute
change_data_source_permission
create
delete
edit
edit_description
edit_name
execute
execute_query
fork
login
pivot
remove_data_source
remove_member
search
update
update_data_source
view
view_source

object_type

dashboard
data_source
datasource
group
group_data_sources
page
query
redash
user
visualization
widget