Photo by Reza Rostampisheh on Unsplash
パーサーの世界で、テキスト解析の機能性とパワーの最先端に位置するのが、抽象構文木(AST)を構築できるパーサーです。ASTの最大の利点は、解析結果の分類情報を含むJSON文字列として扱える点にあります。これは非常に有用で、その上にサービスを構築するのも容易です。入力テキストがSQL文であれば、なおさらです。
名の通ったSQLエディタはどれもパーサーを使っています。superQueryではpegJsというJavaScriptベースのパーサーを採用しており、現在DoiT Internationalに買収されたチームの手によって、Google BigQueryの構文の大部分も効率的に処理できるよう拡張されています。
zetaSQLについて
2019年初頭、GoogleはASTベースのパーサーであるzetaSQLをオープンソースとして公開しました。Google BigQueryやCloud Spannerでクエリの解析・フォーマットに本番運用されているパーサーです。リポジトリはこちら。zetaSQLはbazelでコンパイルでき、主にC++で書かれていますが、Java実装も用意されています。
コードを掘り下げてみると、このパーサーには次のような多彩な機能が備わっていることがわかります。
- SQL文のフォーマット(sql_formatter.h)
- SQL文の解析(analyzer.h)
- 構文エラーの検出と、エラー内容・行・列の返却(parse_helpers.h)
リポジトリを見るかぎり、ビルドはそれほど難しくなさそうです。時間を節約するためにお伝えしておくと、.bazelrcというファイルが非常に重要です。このファイルがC++コンパイラのバージョンを、Googleの他ソフトウェアでサポートされる適切なレベルに設定してくれます。ビルド時には必ずこのファイルを用意してください。
また、本家のzetaSQLリポジトリには、最新版のzetaSQLをビルド・コンパイルするためのDockerfileが(現時点では)用意されていません。Ubuntu 18.04と最新版のbazelをベースにしたものをこちらで公開しています。
私の実装(zetasql-analyzer-server)は、上記3点目の構文エラー検出を担うものです。これはapstndb氏によるzetasql-format-server(2点目を担うDocker実装)をベースにしています。内部的にはGoで書かれたサーバーがzetaSQLのフォーマッター(あるいはアナライザー)APIをラップし、Google Cloud Run上でエンドポイントとして提供します。
使用例
シンプルな例
誤ったクエリSELEC 1(Tが抜けています)をアナライザーエンドポイントに渡したときの出力例です。

シンプルなクエリに対して、エラー位置・行・列・エラーメッセージが返ってきます。
複雑な例
次の例では、クエリの2つ目のネストでSELECTが抜けています。パーサーがその情報を示しているのが確認できます。

少し複雑なクエリに対するエラー位置の表示。
速度とパフォーマンスは?
限定的に行ったテストの範囲では、ほとんどのレスポンス(600行を超えるクエリであっても)は1秒以内に収まり、平均は300ms程度でした。
以下は、高速インターネット接続のノートPCから実行した、先ほどの2例のタイミンググラフです。

「SELE 1」のイベント応答時間

少し複雑な上記の例におけるイベント応答時間。
この高速な解析を支えているのは、distrolessコンテナイメージ(https://github.com/GoogleContainerTools/distroless)と、入力言語にC++を用いたserverlessなハードウェア実装(Cloud Run)を組み合わせたスタックです。
インストールと使い方
インストール手順については、こちらのREADMEをご覧ください。詰まったところがあればお知らせください。
Cloud Runでエンドポイントを作成したら、curlコマンドで情報を取得できます。
curl -X POST -H 'Content-type: application/text' --data 'SLECT 1, ' https://<your endpoint goes here>
おわりに
それでは、よいパースを!
参考資料
- zetasql-analyzer-server: https://github.com/ebendutoit/zetasql-analyzer-server
- zetaSQL: https://github.com/google/zetasql
- zetasql-format-server: https://github.com/apstndb/zetasql-format-server