この記事は 一休.com アドベントカレンダー 2017 の 14 日目です。
昨日に引き続き、一休データサイエンス部の id:kitsuyui です。 13 日目のエントリでは Embulk, Redash, DatabaseMEMO の導入の経緯について解説しました。 とても素晴らしいツールを導入できましたが、実はそのままでは一休に導入することができない箇所がいくつもありました。
GitHub 上でどんなアクションをしたかを振り返りたいとおもいます。 その後、自分なりに見出したコントリビューションのコツと反省点について説明します。
私の英語力が不足していますので、つたない英語のプルリクエストを送ってしまっています。 この点についてはご容赦ください。
コントリビューション例
Re:dash + SQL Server が日本語が含まれていると正しく動作しない問題
Re:dash には Google のユーザ認証でログインする機能があるのですが、 このユーザ名と SQL Server の Query Runner がバッティングする問題がありました。
Re:dash から発行したクエリには SQL のコメントでユーザ名を埋め込むのですが、 そこが文字化けを引き起こしていました。
Re:dash のような Python 2.7 系ではありがちなこと (オープンソースソフトウェアの世界ではありがちなこと) ですが、文字コードを正しく扱っていないという基本的な点でした。
データソースの設定で文字コードを指定出来るようにし、クエリもエンコードするようにしてプルリクエストを出し、マージしていただきました。
https://github.com/getredash/redash/pull/1104
Re:dash の Azure SQL Data Warehouse 対応
Azure SQL Data Warehouse という Microsoft 公式の SQL Server 互換の DWH 向けソリューションがあるのですが、 こちらが Re:dash に対応していない、という問題がありました。
そもそも Re:dash は SQL Server に対して pymssql (+ FreeTDS) を利用したクエリランナーを持っていたのですが、 こちらが Azure SQL Data Warehouse には対応していませんでした。
Python を使用して Azure SQL Database に照会する の解説にもある通り、 Microsoft としては pyodbc での実行ができることは検証されているため、 こちらを利用してアクセスできるようにし、プルリクエストを出し、マージしていただきました。
https://github.com/getredash/redash/pull/1906
embulk-output-jdbc で SQL Server Native Client (BCP) 対応
embulk は embulk-output-jdbc というプラグインをインストールすることで、各種の JDBC 互換のデータソースを出力先に追加することができます。 この embulk-output-jdbc には embulk-output-sqlserver が含まれています。
embulk-output-sqlserver には Windows 独自の機能として、 Native Client という Windows の DLL を利用した (非 JDBC) ロード方法があります。 これが SQL Server の最速の Bulk Insert 機能となっていますが、前述の通り Windows にしか対応していないという欠点がありました。
しかし、近年 Microsoft は Linux, macOS 環境にも力をいれており、公式で ODBC ドライバを配布しています。 こちらの ODBC のライブラリの中に Native Client (BCP) 周りの実装も含まれているため、 Linux, macOS でも実行可能であることがわかりました。
embulk-output-sqlserver の Windows 専用となっていた箇所にメスを入れ、 Linux, macOS にも対応し、 プルリクエストを出し、マージしていただきました。
具体的には、 Windows で読んでいる sqlncli11.dll というライブラリの代わりに Linux や macOS では msodbcsql.so, msodbcsql.dylib を使うように書き換えました。
途中 Shift_JIS (CP932) を前提とした箇所があったのを UTF-8 に対応する際にミスをし、一時的にバグを追加してしまいました。 こちらもすぐに修正をプルリクエストし、マージしていただきました。現在ではどの OS でも高速なロードができるようになりました。
一休内では予約情報のトランザクションや会員の行動履歴といった件数の非常に多いデータをロードする際にこのモードを活用しています。 該当の箇所で 5 倍以上の高速化が実現できました。
https://github.com/embulk/embulk-output-jdbc/pull/209 https://github.com/embulk/embulk-output-jdbc/pull/214
embulk-input-bigquery のバージョン変化に伴うプルリクエスト
embulk-input-bigquery という BigQuery を入力データソースとして使えるようにする embulk のプラグインがあるのですが、 こちらが依存しているライブラリ google-cloud-ruby が動作しなくなっていました。
バージョンアップによりインターフェースが変わり、クエリ結果のカラム名などを渡すインターフェースが、文字列ではなく Ruby のシンボルに変化していたためです。 embulk-input-bigquery にもこの変更を加え、プルリクエストを出し、マージしていただきました。
https://github.com/medjed/embulk-input-bigquery/pull/7
DatabaseMEMO (dmemo) の SQL Server 対応について
dmemo はテーブル情報を取得するデータソースとして、 MySQL, PostgreSQL, Redshift に対応しているのですが、 未だ SQL Server には対応していませんでした。
内部の実装をみたところ、テーブル情報を取得する際に、 Rails の Active Record を使っているようでした。
activerecord-sqlserver-adapter という、 SQL Server 用のアダプタを見つけたので、こちらを利用できるように実装しました。
なんとなく勘所はつかめましたので、 Active Record 用のアダプターさえあれば、ほかの種類のデータベースも移植できるかもしれないと考えています。一休ですと、他に BigQuery, Presto などが候補としてあります。
こちらは私 kitsuyui の方の実装がまだこなれていない点があるので、 GitHub 上でやりとりさせていただいている最中です。 https://github.com/hogelog/dmemo/pull/91
DatabaseMEMO (dmemo) を閲覧のみログインせずできるようにする
DatabaseMEMO は Google のアカウントでログインできるのですが、ログインせずに社内からの閲覧のみは許可したいケースがありました。全員が Wiki の編集者とならずとも、利用はできるようにしたいのです。 こちらは crowi-plus などにも 「ログインしていないユーザーにも閲覧のみ許可するオプション」があるのと同様の意図です。
こちらも GitHub 上でやりとりさせていただいている最中です。 https://github.com/hogelog/dmemo/pull/93
まとめ
SQL Server について
基本的には「SQL Server に対応してない」のケースは多いです。 しかし、実際には社会的な土台はほぼ整っていて、ソフトウェア的には少しの修正で対応できてしまう、というケースが多いです。
以前であれば、 SQL Server はエンタープライズ製品・導入が難しい・検証には Windows 機が必要、といういろいろな壁があったかと思います。 しかし、今ではありがたいことに SQL Server には Docker 版 が存在し、 Linux や macOS でも充分に検証できるようになりました。
SQL Server 自体はオープンソースソフトウェアではないですが、実行環境自体がオープンソースソフトウェアに近い構造で用意されていることで、 検証にかかるコストがグッと減りました。
この点は大きな転換点になると思います。
コントリビューションのコツ
期待以上の動作をさせてみる
私なりのコントリビューションのコツは、オープンソースソフトウェアを使い始めたときに、期待以上の使い方をすることです。
- あえて Linux で embulk-output-sqlserver を Native Client で動作させようとしてみる
- あえて DatabaseMEMO (dmemo) を SQL Server で動かしてみる
- あえて Re:dash で Azure SQL Data Warehouse を使ってみる
こういうときに、最初から期待以上の動作をすることはありません。しかし、そっと閉じるのではなく、 想像力を働かせて「似た環境では動いてるはずなのに、なぜ?」「誰かの環境では動いているのに、なぜ?」といった問いからスタートして、あとは地道に帳尻を合わせていくことです。
できそうな材料をしらべる
ここまでわかれば、まずは一点だけが突破するような状態を作ることができます。
- embulk-output-sqlserver で呼んでいる DLL の関数を調べ、全てが ODBC ドライバにもあるかを調べる
- DatabaseMEMO で使っているフレームワーク (Rails) のドライバを調べ、 SQL Server 版が使えないか調べる
- Re:dash の実装言語である Python で Azure SQL Data Warehouse に接続する方法を調べる
道具を揃える
材料があっても、見知らぬ環境ではうまく戦えません。道具を調べます。 ビルド方法・テスト方法・デバッグ方法・インタプリタ・パッケージマネージャあたりをおさえておけば大丈夫です。
- embulk の場合は ./gradlew を叩けばビルドができます。 embulk irb でインタプリタに入れます。
- DatabaseMEMO は Dockerfile があるので Docker で環境をつくれます。
rails console
コマンドで Rails の irb に入れます。 - Re:dash は (Python なので私はあまり困りませんでしたが)
./manage.py shell
でインタプリタに入れます
また、未知のオープンソースソフトウェアの場合だと、これらを調べるのに時間がかかってしまうことがあります。
その場合には
- strace (Linux のプロセスが実行するシステムコールを見ることができるコマンドです)
- netcat (ポートの開閉をしらべたり、ポートを転送したり、サーバをでっちあげたりするのに使います)
- print デバッグ (あまり上品ではありませんが、どこでも使えます)
などの、より低レベルな道具を使えば問題ありません。 (どこでも使える、というメリットもあります。)
また、利用するソフトウェアに CONTRIBUTION.md やライセンス等がある場合、それらも読み込んでおきます。
一点突破
後先考えずにあちこちに手を入れて、一点でいいので動くようにします。 このレベルでは 100% の状態である必要はありません。ボロボロでも疎通までができれば最高です。
- DLL のパスだけ .so や .dylib に変えてコンパイルすると、 Linux でも文字化けした状態でなら文字列が挿入できる状態
- SQL の実行の大部分は失敗するが、 DatabaseMEMO から SQL Server への接続まではできる状態
- 幾つかのデータベースが見えないが、 Re:dash で
SELECT 1
クエリが実行できる状態
きれいにする
一点突破したら、あとはそこを中心に綺麗に整地していきます。 一点突破したときにソースコードを散らかしてしまった場合も、このタイミングできれいにしていきます。
なるべく git diff
が最小になるようにします。場合によっては複数のプルリクエストに分けます。
- ドライバのパスや名称を指定出来るようにする ・文字化けしないように修正
- SQL Server 用にソースコードをちまちま修正 (
SELECT ... FROM ... LIMIT n
をSELECT TOP n ... FROM ...
に、といった翻訳) - データベース一覧のクエリなどを修正する
あとはコミッタの方と相談
ここまでできたら、プルリクエストが作れます。 当たり前ですがコミッタやメンテナのほうが、自身のソフトウェアに対して深い洞察とモチベーションをもってます。
できるさえわかったら、深追いする前に Issue などで挙げて、具体的な実装については相談しつつ進めるのが良いと思います。
反省点
自分の場合、原因がわかると修正も同時にできてしまうことが多いので、 Issue とプルリクエストを同時に送ってしまう、 またはプルリクエストのみを送ってしまうというということが多かったです。だいぶ失礼なことをしてしまったと今は反省しています。
また、 Issue でのディスカッションを踏まえて実装に入るほうが、より問題の本質を捉えやすかったかな?とも思います。 この点は 2018 年は改善していきたいです。
最後に
日頃いろいろなオープンソースソフトウェアにお世話になることが多いので、来年もどんどんオープンソースソフトウェアを利用し、ガンガン還元していきたいです。
明日 (15 日目) は tsuchidah さんによる「アプリアイコンをクリスマス仕様にしたらどうなった」です。