はじめに
こんにちは、DR&MLOps チームの hyamamoto です。 もうすぐ新居への引っ越しを控えていてバタバタしながらも、期待に胸を膨らませています。
さて、今回は Redash のクエリを検索するツールを OSS として公開した話をします。
背景
弊社では BI ツールとして QuickSight と Redash の 2 つを利用しています。 Redash では Dashboard 化するほど仕様が定まっていない、一時的な分析やデバッグのためにクエリを活用しています。 このため、日々大量のクエリが様々なユーザーによって作成されています。
このあたりの BI ツールの使い分けについての意思決定については下記をご参照ください。 data.gunosy.io
Redash の用途はアドホックな分析ではあるものの、自分や他の人が過去に書いたクエリを参照したいということはよくあります。 しかしながら、Redash はクエリをタイトルで検索することはできるものの、クエリの中身を検索することはできません。
そこで、以前から Redash のクエリを検索するツールを作りたいと考えていました。 また、OpenSearch の自由文字列検索を試してみたいという思いもあり、OpenSearch の練習の題材にちょうどいいと思い実装に取り組みました。
もともとは個人のレポジトリで開発をしていたのですが、Redash 前提のツールなのもあり、弊社のレポジトリに移動することで今後も継続的にメンテナンスを行っていきたいと考えています。 下記のリポジトリに実装を公開しているので、興味がある方はぜひ利用してみてください。
- アプリケーション: https://github.com/gunosy/redash-searcher
- docker-compose を利用して手元で実行確認をすることができます
- Helm Chart: https://github.com/gunosy/public-helm-charts/tree/main/charts/redash-searcher
- Helm Chart を利用して Kubernetes 上で実行することができます
技術仕様
今回作成したクエリ検索ツールの技術仕様について説明します。
画面例
今回作成したクエリ検索ツールの画面例は下記のとおりです。
ファセットとして作成時刻やユーザー名などを入れているため、柔軟な絞り込みが可能です。
AND
や OR
検索も使え Redash 内のクエリに対して検索をかけることができます。
アーキテクチャ
アーキテクチャとしては下記のとおりです。 弊社の環境で利用するために作ったものなので、Kubernates 上にデプロイすることを前提としています。
graph LR subgraph "Kubernetes" sync["Deployment: Sync Application (Rust)"] ingress["Ingress"] subgraph External Services redash["Deployment: Redash API"] opensearch["StatefulSet: OpenSearch"] end nextjs["Deployment: SSR Frontend App & API (Next.js)"] ingress -->|Routes| nextjs nextjs -->|API Calls| opensearch sync -->|Sync Redash Queries| opensearch sync -->|Get Redash Queries| redash end user["User Client"] user -->|Access| ingress
コンポーネント
上記のアーキテクチャにおけるコンポーネントは下記のとおりです。
- Sync Application
- Redash のクエリを OpenSearch に同期するアプリケーション
- Rust を書くプロジェクトを離れて書きたくなったので Rust で実装
- Frontend App & API
- クエリ検索のためのフロントエンドアプリケーション
- フロントエンドに詳しくないため、個人的にまだ使い慣れている Next.js で実装
- OpenSearch
- クエリの検索を行うための検索エンジン
- Redash 上のクエリは全て登録し直しても数分以内で終わるのため、マネージドサービスは利用せず、StatefulSet でデプロイ
- Redash
- 今回検索したいクエリを保存している BI ツール
- クエリの情報を取得するために API を利用
工夫した点
検索条件の拡充
Sync Application が Redash の API から定期的にクエリの情報を取得し、OpenSearch に同期します。 この際、ユーザー情報や作成時刻などを検索条件(ファセット)として登録することで、より柔軟な絞り込みが可能になっています*1。
OpenSearch の proxy を提供
Next.js の API 機能を使うことで、OpenSearch への proxy サーバーを用意しました。 これにより、OpenSearch の API を直接社内ユーザーに公開することなく利用できるようになっています。 なお、Next.js で OpenSearch を利用するために Searchkit と Elastic UI を利用しました。
Elasticsearch Site Search UI Components – Searchkit Elastic UI
検索条件の表示や検索フォームなど OpenSearch を利用する上で必須なステートの管理やコンポーネントを省略して実装することができたので、かなり楽に画面の作成ができました。
検索クエリによる URL の更新
検索クエリに基づいて URL を更新するようにしました。 これにより、他の人に検索結果を共有する際に、URL を共有するだけで検索結果を共有することが可能になっています。
AND や OR などの複雑な検索クエリのサポート
今回のツールは AND
や OR
などの複雑な検索クエリをサポートしています。
このために、検索クエリをパースして OpenSearch に渡すクエリを生成するようにしました。
Next.js における実行時の環境変数の切り替え
今回のコードは Kubernetes 上で動かすことを前提としていることや、OSS として公開することを前提としていたため、環境変数の切り替えを実行時に行う必要があります。 一方で本来 Next.js はビルド時に環境変数を埋め込むことを前提としているため、実行時に環境変数を切り替えることはできません。
そこでこの記事に書かれている方法を利用して、実行時に環境変数を切り替えるようにしました。
簡単に説明すると、Dockerfile 上で先に環境変数にダミーな値を埋めておき、起動時の entrypoint においてビルド済みのファイル一覧を検索し sed でダミーな値を実行時の環境変数に置き換えるという方法です。 なかなかトリッキーな方法ではありますが、これにより無事に実行時に環境変数を切り替えることができました。
まとめ
今回は Redash のクエリを検索するツールを OSS として公開した話をしました。 実際社内で公開後、他の人のクエリも検索することができて便利だったという声も頂いており、作成した身としてはとても嬉しく思っています。
OpenSearch のチューニングを十分できていないなどまだまだ課題もあるので、今後も継続的にメンテナンスを行っていきたいと考えています。 興味がある方はぜひ利用してみてください。 また、利用してみての要望などはぜひ Issue に投げていただけると嬉しいです。
*1:Redash の WebUI からは自分以外のユーザーに対するの絞り込みを行うことはできません