#zpnightZulipにPGroongaサポートを実装した須藤です。Night」を開催しました。2017のベストトークに選ばれました。NightではPGroongaの紹介とZulipの全文検索インデックスの更新方法の紹介をしました。背景ZulipではPostgreSQL標準のtextsearchを使って全文検索を実現しています。textsearchは言語特化型のインデックスを作るため、同時に複数の言語をサポートすることができません。日本語を含むアジア圏の言語のサポートが不十分なため、日本語を全文検索できないという問題もあります。そこで、私はZulipでPGroongaを使えるようにしました。PGroongaは言語特化型のインデックスも言語非依存のインデックスも作れます。言語非依存のインデックスを作れば同時に日本語も英語もいい感じに全文検索できます。私がZulipにPGroongaサポートパッチを送ったのは自分たちが必要だからです。クリアコードではチャットツールとしてZulipを使っています。その前はSkypeを使っていました。お客さんとの連絡でSkypeを使う必要があったため、その流れでなんとなく使っていました。Skypeはあまり活用していませんでした。クリアコードはフリーソフトウェアを推進したい会社なのでフリーソフトウェアではないSkypeを使っていることをどうにかしたいと考えていました。そこで、いくつかフリーソフトウェアなチャットツールを検討しました。そのうちの1つがZulipでした。Zulipのネックは日本語全文検索できないことでした。ネックがあるので選択肢から外すという考え方もあると思いますが、私たちは、自分たちで日本語全文検索できるようにして使うことにしました。フリーソフトウェアのよいところは自分たちで改良できることだからです。Zulipの全文検索インデックスの更新方法Zulipは書き込み時のレイテンシーを小さくしておくために工夫をしています。チャットアプリケーションでは書き込みがすぐに終わることはよい使い勝手に直結するからです。書き込み時はデータをPostgreSQLに書き込むだけで、全文検索インデックスの更新は別途バックグラウンドで実行します。このためにトリガーとNOTIFYとLISTENを使っています。具体的な実装を簡単に紹介します。興味のある人はZulipのコードを見てください。既存のコードから学習することができることもフリーソフトウェアのよいところです。zerver_messageがメッセージ(チャットの書き込み)を保存しているテーブルです。この中に全文検索対象のデータを入れるカラムを定義します。メッセージのテキストそのものとは別に定義することがポイントです。search_tsvectorがそのカラムです。(PGroongaを使うときの実装ではなくtextsearchを使うときの実装です。tsvector);この全文検索対象のデータを入れるカラムには全文検索用のインデックスを作ります。(この例ではPGroongaのインデックスではなくtextsearchのインデックスを作っています。(search_tsvector);このメッセージ用のテーブルにトリガーを設定します。このトリガーはメッセージが追加・更新されたときに「更新ログ」テーブル(fts_update_logテーブル)にメッセージのIDを追加します。END$$;「更新ログ」テーブルの定義は次の通りです。全文検索インデックスを更新するべきメッセージのIDを入れているだけです。NULL);これで後から全文検索インデックスを更新するための情報を保存する仕組みができました。通常通りメッセージテーブルを操作するだけで実現できていることがポイントです。することでアプリケーション側をシンプルにしておけます。残りの処理は、後から全文検索インデックスを更新する、です。この処理のためにNOTIFYとLISTENを使います。NOTIFYはLISTENしている接続に通知する仕組みです。LISTENしている接続はNOTIFYされるまでブロックします。NOTIFYとLISTENを組み合わせることで、ポーリングしなくてもイベントが発生したことに気づくことができます。今回のケースでは「更新ログが増えた」というイベントに気づきたいです。このイベントが来たら全文検索インデックスを更新したいからです。そのために、「更新ログ」テーブルにトリガーを追加します。「更新ログ」テーブルにレコードが追加されたらNOTIFYするトリガーです。do_notify_fts_update_log();NOTIFYする関数の実装は次の通りです。この関数を実行すると、fts_update_logというイベントをLISTENしている接続のブロックが解除されます。$$;全文検索のインデックスを更新するSQLはPythonから発行しています。全文検索のインデックスの更新処理は必要なときだけ(更新ログがあるときだけ)実行したいです。必要がないときも更新処理を実行し続けるとムダにCPUを使ってしまうからです。必要なときだけ処理を実行するために、LISTENでブロックします。ブロックが解除されたら(NOTIFYされたら)必ず更新ログがあるので、処理を実行します。↓には入っていませんが、処理が終わったら次のNOTIFYがあるまでまたブロックする実装になっています。することで必要なときだけ処理を実行できるためムダにCPUを使わずにすみます。(ids,))このような複数プロセスでの待ち合わせを実現するためにRDBMSとは別の仕組みを使うことも多いでしょう。RedisのPub/Subを使えるでしょう。別の仕組みを使うと運用が面倒になります。PostgreSQLにはNOTIFY/LISTENがあるので、PostgreSQLを使っていて待ち合わせを実現しなければいけないときはNOTIFY/LISTENを使うことを検討してみてください。まとめZulipとPGroongaのイベントでZulipとPGroongaの情報を紹介しました。クリアコードはZulipを使っていて、今ではなくてはならないツールになっています。みなさんもZulipを使ってみてください。Zulipは基本的に自分たちで運用しますが、運用を任せる選択肢もあります。Zulipの開発チームがクラウドサービスでの提供を進めているのです。オープンソースコミュニティは無料で使えるそうです。興味のある人はzulipchat.comを確認してください。2017に来てください。日本PostgreSQLユーザ会(JPUG)が主催のPostgreSQLのカンファレンスです。ここでPGroongaの最新情報を紹介する予定です。4.0とGFDLのデュアルライセンスで自由に利用できます。クリアコードはプログラミングが楽しいソフトウェア開発者を1名募集しています。クリアコードは「クリアコードをいい感じにする人」を1名募集しています。クリアコードはフリーソフトウェア開発で培った技術力を提供しています。Thunderbird)とRubyとGroonga(全文検索)に関連した開発を得意としています。