株式会社クリアコード > ククログ

ククログ

タグ:

PHPカンファレンス2017 - PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム - OSS Gate東京ワークショップ #phpcon2017

はじめてPHPカンファレンスに参加した須藤です。午前に「PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム」という話をして、午後に「OSS Gate東京ワークショップ2017-10-08 - PHPカンファレンス2017会場編 -」を開催しました。

「PostgreSQLとPGroongaで作るPHPマニュアル高速全文検索システム」のスライドは次の通りです。発表後にオートコンプリートの候補を登録する方法を話し忘れたことに気づいたので追記しました。

動画もあります。

関連リンク:

背景

第115回 PHP勉強会@東京PGroongaのことを話す機会があったので、そのデモのためにPHPのマニュアルをPGroongaで全文検索するアプリケーションを作りました。作ってみたところ、PHPユーザーにも便利そうな気がしてきたので、使ってもらったり開発に参加してもらうとよさそうだなぁと思い、PHPカンファレンス2017でも紹介しました。後述するOSS Gateワークショップの開催も第115回 PHP勉強会@東京のときに相談した結果として実現できたので、とてもよい機会でした。

今回の発表では、第115回 PHP勉強会@東京での内容に次の内容を加えました。

  • 類似マニュアル検索の実現方法
  • 同義語展開の実現方法

今回の発表の成果は悪くないです。このPHPマニュアル検索システムの開発に参加する人は増えていないのですが、この検索システムを運用してもらえることになりました!

PHPユーザーで、(PGroongaではなく)MroongaユーザーでもあるWEICさんが運営することになりました!今月中の運用開始を目指しています。URLは以下になる予定です。

運用が始まったら、おそらくWEICさんのお知らせページで告知されるので、チェックしてください!

簡単に使えるようになったらユーザーも開発者も増えることを期待しています。

そうそう、WEICさんはPHPエンジニアを大募集中だそうです!

OSS Gateワークショップ

午後は2時間45分の枠をもらってOSS Gateワークショップを開催しました。(終了時間を勘違いしていて25分早く終わらせてしまいました。。。)

このワークショップには通常バージョンとショートバージョンがあり、通常バージョンは5,6時間、ショートバージョンは2,3時間です。今回は3時間弱の枠だったのでショートバージョンで開催しました。

ショートバージョンは過去にOSS Gate東京ワークショップ for Mastodon in ピクシブ 2017-06-29で実施していて、今回もそれと同じように進めました。通常バージョンからの差は次の通りです。

  • できるだけ事前に対象OSSを決める
  • ミニふりかえりなし
    • 進行役・サポートメンターが随時まわってミニふりかえり的なことをしていく
  • 「ユーザーとして動かす」と「フィードバック」の時間を一緒にする
    • フィードバックポイントが見つかったらすぐにフィードバックに取り組む

今回、私が終了時間を勘違いしていたため最後のアンケートとふりかえりも省略しました。アンケートとふりかえりをやる時間はあったので失敗でした。

今回は時間内にフィードバックまでいけた人はほとんどいませんでした。フィードバックポイントに気づくところまではほとんどの人が経験していたので、フィードバックをまとめる時間が足りなかったということになります。予想した要因は次の通りです。

  • サポーター1人でビギナー2人だとサポートが手薄
    • ピクシブさんで開催したときはサポーター1人でビギナー1人だった
    • ビギナーの人がもう少しサポートを厚くできると時間を短くできそう

試してみたいことは次の通りです。

  • サポーター2人でビギナー3人をサポート
  • サポーター1人でビギナー2人をサポートするけど、サポーター2人つきサポートメンターが1人サポート
    • 今回はサポーター4人につきサポートメンターが1人サポート

今回、初めてPHP関連のOSS限定のOSS Gateワークショップを開催しました。今回だけで終わりにせずに今回が始まりにしていきたいので、PHP関連のOSSの開発に参加する人が増えるとうれしいという人はぜひ一緒にやっていきましょう!Gitterのoss-gate/tokyo-phpでオンラインで相談しています。まずはここに来てください!現状は、今回ワークショップに参加した人と次回の開催について相談するところです。

まとめ

PHPカンファレンス2017で、PGroongaの話をして、OSS Gateワークショップも開催しました。今回の機会をぜひ今後につなげていきたいです。

タグ: Groonga
2017-10-10

db tech showcase Tokyo 2017 - MySQL・PostgreSQLだけで作る高速でリッチな全文検索システム #dbts2017

この発表のためにmroonga_query_expand()を実装した須藤です。db tech showcase Tokyo 2017で「MySQL・PostgreSQLだけで作る高速でリッチな全文検索システム」という話をしました。一昔前の全文検索システムはそこそこ速く全文検索してキーワードをハイライト表示できれば普通でしたが、最近の全文検索システムはそれだけだと機能不足で、オートコンプリートやクエリー展開や関連エントリー表示機能などがあって普通というくらいにユーザーの要求レベルがあがっています。これは、GoogleやAmazonなど便利な検索サービスに慣れたユーザーが増えたためです。そんな時代の変化に対応できる全文検索エンジンがGroongaです。GroongaはMySQL・MariaDB・PostgreSQLから使えるためSQLを使って簡単にイマドキの全文検索システムを実装できます。しかも、運用も楽です。そんな話です。

関連リンク:

内容

まず、どういうときにMroonga・PGroongaを使うアプローチを選べばよいかという指針を示しました。

  • 全文検索の知識ナシ
    • 全文検索だけできれば十分
      • データが少ない(数十万件とか):RDBMSでLIKE
      • データが多い:Mroonga・PGroonga
    • イマドキの機能が必要
      • Mroonga・PGroonga
  • 全文検索の知識アリ
    • カリカリにチューニングしたい
      • RDBMS + 全文検索サーバー
    • それ以外
      • Mroonga・PGroonga

次に、以下の機能をMroonga・PGroongaで実現するにはどういうSQLを使えばよいか説明しました。

  • 全文検索
  • キーワードハイライト
  • 周辺テキスト表示
  • 入力補完
  • 同義語展開
  • 関連文書の表示

最後に、次のステップとして構造化データ(オフィス文書・HTML・PDFなど)の対応方法について少し言及しました。Groongaプロジェクトは構造化データからテキスト・メタデータ・スクリーンショットを取得するツールとしてChupaTextを開発しています。コマンドラインでもHTTP経由でもライブラリーとしても使えます。HTTP経由で使う場合はDocker・Vagrantを使うのが便利です。依存ライブラリーを揃える手間がないからです。

まとめ

Mroonga・PGroongaを使ってイマドキの全文検索システムを実装する方法を紹介しました。コンサルティングやチューニングや開発支援などを提供するサポートサービスがあります。社外秘のデータでお困りの場合はお問い合わせください。NDAを結んだ上で対応できます。

Mroongaはインサイト・テクノロジーさんが進めているPinkshiftでも活用されています。MySQL・MariaDB・PGroongaで高速全文検索が必要ならMroonga・PGroongaを試してみてください。

タグ: Groonga
2017-09-08

Zulip & PGroonga Night - PGroonga & Zulip #zpnight

ZulipPGroongaサポートを実装した須藤です。PyCon JP 2017に参加するためにZulipの開発者の1人であるGregさんが来ていたので、日本PostgreSQLユーザ会(JPUG)さんに主催してもらってZulipとPGroongaのイベント「Zulip & PGroonga Night」を開催しました。

なお、GregさんのPyConJP 2017でのトーク「Clearer Code at Scale: Static Types at Zulip and Dropbox」(動画)はPyConJP 2017のベストトークに選ばれました。すごい!

Zulip & PGroonga NightではPGroongaの紹介とZulipの全文検索インデックスの更新方法の紹介をしました。

関連リンク:

背景

ZulipではPostgreSQL標準のtextsearchを使って全文検索を実現しています。textsearchは言語特化型のインデックスを作るため、同時に複数の言語をサポートすることができません。また、日本語を含むアジア圏の言語のサポートが不十分なため、日本語を全文検索できないという問題もあります。

そこで、私はZulipでPGroongaを使えるようにしました。PGroongaは言語特化型のインデックスも言語非依存のインデックスも作れます。言語非依存のインデックスを作れば同時に日本語も英語もいい感じに全文検索できます。

クリアコードがZulipを選んだ理由

私がZulipにPGroongaサポートパッチを送ったのは自分たちが必要だからです。クリアコードではチャットツールとしてZulipを使っています。その前はSkypeを使っていました。お客さんとの連絡でSkypeを使う必要があったため、その流れでなんとなく使っていました。Skypeはあまり活用していませんでした。

クリアコードはフリーソフトウェアを推進したい会社なのでフリーソフトウェアではないSkypeを使っていることをどうにかしたいと考えていました。そこで、いくつかフリーソフトウェアなチャットツールを検討しました。そのうちの1つがZulipでした。Zulipのネックは日本語全文検索できないことでした。ネックがあるので選択肢から外すという考え方もあると思いますが、私たちは、自分たちで日本語全文検索できるようにして使うことにしました。フリーソフトウェアのよいところは自分たちで改良できることだからです。

Zulipの全文検索インデックスの更新方法

Zulipは書き込み時のレイテンシーを小さくしておくために工夫をしています。チャットアプリケーションでは書き込みがすぐに終わることはよい使い勝手に直結するからです。

書き込み時はデータをPostgreSQLに書き込むだけで、全文検索インデックスの更新は別途バックグラウンドで実行します。このためにトリガーとNOTIFYLISTENを使っています。

具体的な実装を簡単に紹介します。興味のある人はZulipのコードを見てください。既存のコードから学習することができることもフリーソフトウェアのよいところです。

zerver_messageがメッセージ(チャットの書き込み)を保存しているテーブルです。この中に全文検索対象のデータを入れるカラムを定義します。メッセージのテキストそのものとは別に定義することがポイントです。search_tsvectorがそのカラムです。(PGroongaを使うときの実装ではなくtextsearchを使うときの実装です。)

CREATE TABLE zerver_message (
  rendered_content text,
  -- ... ↓Column for full text search
  search_tsvector tsvector
);

この全文検索対象のデータを入れるカラムには全文検索用のインデックスを作ります。(この例ではPGroongaのインデックスではなくtextsearchのインデックスを作っています。)

CREATE INDEX zerver_message_search_tsvector
  ON zerver_message
  USING gin (search_tsvector);

このメッセージ用のテーブルにトリガーを設定します。このトリガーはメッセージが追加・更新されたときに「更新ログ」テーブル(fts_update_logテーブル)にメッセージのIDを追加します。

-- Execute append_to_fts_update_log() on change
CREATE TRIGGER
  zerver_message_update_search_tsvector_async
  BEFORE INSERT OR UPDATE OF rendered_content
    ON zerver_message
  FOR EACH ROW
    EXECUTE PROCEDURE append_to_fts_update_log();

メッセージのIDを追加する関数の実装は次のようになります

-- Insert ID to fts_update_log table
CREATE FUNCTION append_to_fts_update_log()
  RETURNS trigger
  LANGUAGE plpgsql AS $$
    BEGIN
      INSERT INTO fts_update_log (message_id)
        VALUES (NEW.id);
      RETURN NEW;
    END
$$;

「更新ログ」テーブルの定義は次の通りです。全文検索インデックスを更新するべきメッセージのIDを入れているだけです。

-- Keep ID to be updated
CREATE TABLE fts_update_log (
  id SERIAL PRIMARY KEY,
  message_id INTEGER NOT NULL
);

これで後から全文検索インデックスを更新するための情報を保存する仕組みができました。通常通りメッセージテーブルを操作するだけで実現できていることがポイントです。こうすることでアプリケーション側をシンプルにしておけます。残りの処理は、後から全文検索インデックスを更新する、です。

この処理のためにNOTIFYLISTENを使います。NOTIFYLISTENしている接続に通知する仕組みです。LISTENしている接続はNOTIFYされるまでブロックします。NOTIFYLISTENを組み合わせることで、ポーリングしなくてもイベントが発生したことに気づくことができます。

今回のケースでは「更新ログが増えた」というイベントに気づきたいです。このイベントが来たら全文検索インデックスを更新したいからです。

そのために、「更新ログ」テーブルにトリガーを追加します。「更新ログ」テーブルにレコードが追加されたらNOTIFYするトリガーです。

-- Execute do_notify_fts_update_log() on INSERT
CREATE TRIGGER fts_update_log_notify
  AFTER INSERT ON fts_update_log
  FOR EACH STATEMENT
    EXECUTE PROCEDURE
      do_notify_fts_update_log();

NOTIFYする関数の実装は次の通りです。この関数を実行すると、fts_update_logというイベントをLISTENしている接続のブロックが解除されます。

-- NOTIFY to fts_update_log channel!
CREATE FUNCTION do_notify_fts_update_log()
  RETURNS trigger
  LANGUAGE plpgsql AS $$
    BEGIN
      NOTIFY fts_update_log;
      RETURN NEW;
    END
  $$;

全文検索のインデックスを更新するSQLはPythonから発行しています。全文検索のインデックスの更新処理は必要なときだけ(更新ログがあるときだけ)実行したいです。必要がないときも更新処理を実行し続けるとムダにCPUを使ってしまうからです。

必要なときだけ処理を実行するために、LISTENでブロックします。ブロックが解除されたら(NOTIFYされたら)必ず更新ログがあるので、処理を実行します。↓には入っていませんが、処理が終わったら次のNOTIFYがあるまでまたブロックする実装になっています。こうすることで必要なときだけ処理を実行できるためムダにCPUを使わずにすみます。

cursor.execute("LISTEN ftp_update_log") # Wait
cursor.execute("SELECT id, message_id FROM fts_update_log")
ids = []
for (id, message_id) in cursor.fetchall():
  cursor.execute("UPDATE zerver_message SET search_tsvector = "
                   "to_tsvector('zulip.english_us_search', "
                               "rendered_content) "
                 "WHERE id = %s", (message_id,))
  ids.append(id)
cursor.execute("DELETE FROM fts_update_log WHERE id = ANY(%s)",
               (ids,))

このような複数プロセスでの待ち合わせを実現するためにRDBMSとは別の仕組みを使うことも多いでしょう。たとえば、RedisのPub/Subを使えるでしょう。別の仕組みを使うと運用が面倒になります。PostgreSQLにはNOTIFY/LISTENがあるので、PostgreSQLを使っていて待ち合わせを実現しなければいけないときはNOTIFY/LISTENを使うことを検討してみてください。

まとめ

ZulipとPGroongaのイベントでZulipとPGroongaの情報を紹介しました。クリアコードはZulipを使っていて、今ではなくてはならないツールになっています。ぜひみなさんもZulipを使ってみてください。

Zulipは基本的に自分たちで運用しますが、運用を任せる選択肢もあります。Zulipの開発チームがクラウドサービスでの提供を進めているのです。オープンソースコミュニティは無料で使えるそうです。興味のある人はzulipchat.comを確認してください。

PGroongaが気になる人は、11月3日開催のPostgreSQL Conference Japan 2017に来てください。日本PostgreSQLユーザ会(JPUG)が主催のPostgreSQLのカンファレンスです。ここでPGroongaの最新情報を紹介する予定です。

タグ: Groonga
2017-09-07

Redmine大阪 第17回勉強会 - 全文検索でRedmineをさらに活用! #RedmineOsaka

大阪に行くのは今年3回目な須藤です。1回目が2017年2月25日のOSS Gate大阪ワークショップ、2回目が2017年5月27日の関西Ruby会議2017、そして3回目の今回がRedmine大阪 第17回勉強会です。

関連リンク:

内容

発表内容は2017年5月13日に開催されたredmine.tokyo第12回勉強会の発表内容をアップデートしたものです。

Redmineの全文検索機能はLIKEベースで実現されていて、「どのくらい検索クエリーに適合していそうか」の概念がないため、「それっぽい検索結果を上位に並び替える」ことができません。そのため、探している情報はヒットしているけど、検索結果の中からなかなか見つけられない、という状態になりがちです。

Groongaベースの全文検索プラグインを導入すると「それっぽい検索結果を上位に並び替える」ため、探している情報をすぐに見つけられるようになります。

これだけだと「Redmineの不便なところを解消した」というレベルなのですが、このプラグインで目指しているものはもっと先にあります。ユーザーの手間をできるだけ減らしつつ、必要なときに必要な情報をユーザーに提供することを目指しています。

現在開発を進めているのが類似issue検索です。閲覧中のissueと似ているissueを自動で検索して表示する機能です。

有効に活用されているRedmineには過去の問題対応の詳細が記録されています。新しく問題が発生したとき、以前は類似の問題にどのように対応したかがわかると、新しい問題にも素早く適切に対応できます。

現在のRedmineの機能では、過去に類似の問題があったかどうかは人が明示的に探さなくてはいけません。人が探す場合、なにかキーワードを知らなければいけません。既存メンバーは「そういえば似たような問題があったな…」という記憶からキーワードを手繰り寄せられるかもしれませんが、新しく入ってきたメンバーにはそれはできません。

大量のデータから検索するのは機械が得意な処理です。データを活用して機械が人をサポートする方法の1つが類似issue検索です。現在の実装は、単に字面だけで類似度を計算していますが、今後は、字面だけでなく意味で類似度を計算する、テキストデータだけでなくメタデータも使って類似度を計算するなど、有用なデータを活用して精度をあげていく予定です。

類似issue検索はデータを活用して機械が人をサポートする1つのアプローチに過ぎません。類似issue検索以外にもRedmine内のデータを活用して人がより有意義なことに時間を使えるようにしていきたいです。

そこを目指すためにはデータが必要不可欠です。クリアコード内のデータだけでは足りません。Redmine内のデータを活用してもっと自分たちの活動を有意義にしていきたい方はぜひ開発にご協力ください。開発に協力する方法はいろいろあります。たとえば、「自分たちのRedmineのデータを活用して自分たちの活動を有意義にするサポートをして欲しい」という仕事をクリアコードに発注する方法があります。この方法では、発注者には自分たちの活動をより有意義にできるというメリットがあり、クリアコードにはお金を得られる・現実のデータを使って現実の人たちの活動を支援するノウハウを得られるというメリットがあります。

私たちは成果(この場合は改良したプラグイン)をだれでも自由に利用できるようにします。「自分たちがお金を払って改良した分を他の会社がお金を払わずに使えるようになるのは損だ」と考える人も多いかと思いますが、実際は損になることはほとんどありません。

たとえば、メンテナンスコストが下がるので、運用後の費用面で得になります。一社向けに提供するソフトウェアのメンテナンスコストは当然一社で持つことになります。一方、大勢が利用するソフトウェアのメンテナンスコストは大勢で持ちます。そのため、だれでも自由に使えるようにした方がメンテナンスコストが下がるのです。

他社が使える状態になったとしても、すぐに追いつかれるわけではありません。他社はノウハウがない状態からのスタートになるからです。しかも、自分たちのノウハウを公開しても損にはなりません。情報は発信しているところに集まります。ノウハウを公開することで新しいノウハウを得やすくなります。他社が自社のノウハウを得られても、自社にはもっとノウハウが集まります。他社を抑えることを頑張るよりも、自社がより伸びることを頑張る方が結果として得をします。

Redmine内のデータを活用してもっと自分たちの活動を有意義にしていきたい方はぜひお問い合わせください。一緒に実現しましょう。

まとめ

Redmine大阪 第17回勉強会でRedmine用の全文検索プラグインを紹介しました。単にいい感じの全文検索機能を提供するだけでなく、検索を軸にRedmineを使っている人たちの活動をいい感じにすることを目指しています。もっとRedmineを活用したい方はお問い合わせください。検索まわりはもちろん、Redmine本体の修正・改良や既存のRedmineプラグインの修正・改良もできますし、新規プラグインを開発して問題を解決することもできます。もちろん、変更部分はRedmine本体やプラグインの開発元にフィードバックします。

タグ: Groonga
2017-08-27

MySQL・PostgreSQL上で動かす全文検索エンジン「Groonga」セミナー - Mroonga・PGroongaを使った全文検索システムの実装方法 #groonga #mysql #mariadb #postgresql

cairo色付きフォントサポートが入ったので、今回のスライドではNoto Color Emojiを使ってRabbitで色付きの絵文字を表示した須藤です。

2017年8月1日にMySQL・PostgreSQL上で動かす全文検索エンジン「Groonga」セミナーを開催しました。今回は業務でGroonga(Mroonga・PGroonga)を使いたい人向けのイベントだったので平日の午後に開催しました。

関連リンク:

内容

これまでのMroonga・PGroongaの紹介資料では、速さや機能を紹介するまとめ方が多かったのですが、今回の資料は「イマドキの全文検索システムを作るにはこんなSQLを使えばよい」というまとめ方にしました。逆引きレシピのようなまとめ方です。

話の流れは次のようになっています。全文検索システムを作る機会がある人は参考になるはずです。

  • イマドキの全文検索システムとは?
  • ミドルウェアの選び方は?判断基準は?
    • 全文検索サーバーを使う?
    • RDBMSだけでがんばる?
    • RDBMSに全文検索エンジンを組み込む?
  • イマドキの全文検索システムに必要な以下の機能をMroonga・PGroongaで実装するには?
    • 全文検索機能
    • キーワードハイライト機能
    • 周辺テキスト表示機能
    • 入力補完機能(今回はPGroongaのみ)
    • 同義語展開機能(今回はPGroongaのみ)
    • 関連文書の表示機能
  • 構造化された文書を検索対象にするには?
    • 構造化された文書の例:オフィス文書(Word・Excel・PowerPoint・LibreOfficeなどで作成した文書)
    • 構造化された文書の例:HTML(ヘッダー・フッター・サイドバーのテキストを取り除くなど、単にbody.innertTextの値を取得するだけではノイズが増えるので、いろいろケアが必要)
    • 構造化された文書の例:PDF
    • HTTPでテキスト抽出・スクリーンショット作成できるChupaTextの紹介
    • Dockerで使う:chupa-text-docker
    • Vagrantで使う:chupa-text-vagrant

まとめ

Mroonga・PGroongaでイマドキの全文検索システムを作る方法を紹介するセミナーを開催しました。クリアコードは全文検索システムの受託開発・設計支援・開発支援・障害調査支援など全文検索関係のもろもろをサポートするサービスを提供しています。とりあえず話を聞いて欲しいというレベルからでも結構ですので困っていることがあればお問い合わせください。

タグ: Groonga
2017-08-02

第115回 PHP勉強会@東京:PHPでPostgreSQLとPGroongaを使って高速日本語全文検索! #phpstudy

はじめてまともにPHPを書いた須藤です。

第115回 PHP勉強会@東京で「PHPでPostgreSQLとPGroongaを使って高速全文検索!」という話をしました。

関連リンク:

内容

PGroongaを使えばPHPで簡単にリッチで高速な全文検索システムを作れるよ!ということを伝えたかったので、実際にPHPで「PHPのドキュメントを全文検索するシステム」を作ってそれを紹介しました。詳細はスライドで説明していますが、次のような機能があります。

  • 探したいものが見つかる高速全文検索機能(基本機能)
  • キーワード周辺のテキストをハイライト(基本機能)
  • 入力補完(基本機能)
    • ローマ字でも入力補完可能(リッチな機能)
      • 例:「seiki」→「正規表現」

サービスとしては動かしていないのですぐに試せませんが、ソースコードはフリーソフトウェアとして公開しているのでローカルで動かすことができます。動かし方のドキュメントは書いていませんが、標準的なLarabelの使い方だと思っているので、Larabelを使ったことがある人なら動かせるのではないかと思います。

私はこれまでまともにPHPを書いたことがありませんでしたが、3日で実装できました。簡単にリッチで高速な全文検索システムを作れることが示せたのではないかと思います。

おねがい

このイベントのために作ったPHP document searchですが、PHPユーザーにとって有用なサービスになるのではないかと思うので、だれかサービスとして運用したり、メンテナンスしたりしませんか!?私は日常的にPHPを書くことはないのでサービスとして運用する予定はないのですが、技術的なサポートはするつもりです。

興味がある方はissueで連絡してください。

まとめ

PHPユーザーにPGroongaを紹介する機会があったのでPHPのドキュメントを検索するPHP document searchを作ってそれを元にPGroongaを紹介しました。PHP document searchの運営者・メンテナーを募集しているので、ぜひご連絡ください!

おしらせ

8月1日(火)14:00-16:00にMySQL・PostgreSQL上で動かす全文検索エンジン「Groonga」セミナーを開催します。PGroongaを使いたくなった人はぜひこの機会をご活用ください!

つづき: 2017-10-10
タグ: Groonga
2017-07-20

OSS on Azure 非公式コミュニティ #5 『Azure Database』勉強会:MySQLとPostgreSQLと日本語全文検索 - Azure DatabaseでMroonga・PGroongaを使いたいですよね!? #AzureDB

品川のマイクロソフトさんのオフィスに行ったのはRubyHiroba 2013以来な気がする須藤です。

db tech showcase OSS 2017の懇親会でAzure Database for MySQL / PostgreSQLというセッションがありました。Azure DatabaseでMroongaPGroongaを使えるようになったりしませんか!?と聞いてみたところ、「月末にAzure Databaseを開発している人がくるAzure DatabaseのイベントOSS on Azure 非公式コミュニティ #5 『Azure Database』勉強会があるので、そこでMroonga・PGroongaを紹介すると話が進むかも!?」ということだったので紹介してきました。

関連リンク:

内容

この発表では次のことを紹介しました。

  • Mroonga・PGroongaが高速なこと
  • Mroonga・PGroongaはMySQL・PostgreSQLユーザーなら簡単に使えること
  • Mroonga・PGroongaはWindowsでも動くこと
  • PGroongaではJSON内のテキスト全部を全文検索できること
  • PGroongaでは簡単に入力補完を実現できること

話の最初と最後でAzure DatabaseでMroonga・PGroongaを使いたい人はどのくらいいるか聞いてみました。最初は1割くらいでしたが最後は半分くらいの人が使いたい気持ちになっていました。Azure Databaseの開発をしている方は持ち帰ってチームで検討すると言っていました。Azure Database for MySQL/PostgreSQLは今はまだプレビュー期間中ですが、一般公開時にはMroonga・PGroongaをサポートしているかもしれません。Azure Database for MySQL/PostgreSQLでMroonga・PGroongaを使いたい方はぜひAzure Databaseのサポートに「Mroonga・PGroongaを使いたい!」とフィードバックしてください。

まとめ

Azure DatabaseがMySQLPostgreSQLをサポートしようとしています。どちらも現状では日本語全文検索が苦手ですが、Azure DatabaseがMroonga・PGroongaをサポートすれば日本語全文検索が得意なDBaaSになります。まだMroonga・PGroongaをサポートすることになったわけではないので、Azure DatabaseでMroonga・PGroongaを使いたい方はサポートにフィードバックしてください。

おしらせ

8月1日(火)14:00-16:00にMySQL・PostgreSQL上で動かす全文検索エンジン「Groonga」セミナーを開催します。Mroonga・PGroongaを検討しているという方はぜひこの機会をご活用ください!

タグ: Groonga
2017-07-19

LaravelでPostgreSQLとPGroongaを使って日本語全文検索を実現する方法

はじめに

※この記事は、Laravelを使った開発の経験がある人を対象としています。Laravelの基本的な使い方自体の説明は含まれていませんので、ご注意下さい。

Webアプリケーションを開発していると、「検索窓に入力された語句を含むレコードを一覧表示する」といった機能を付けたくなる場面がよくあります。この時よく使われる手軽な方法としてSQLのLIKEがありますが、LIKEには検索対象のレコードの数が増えれば増えるほど処理に時間がかかるという欠点があります。そこで登場するのが全文検索という手法です。全文検索では事前に用意しておいたインデックス情報を使うことにより、レコード数が増加しても安定して高速な検索を行うことができます。サービスの利用者が増加して数万・数十万といった数のレコードを取り扱うような必要が生じてきた場合、全文検索の導入を検討する価値は十分にあるでしょう。

以前、Ruby on Railsで作ったアプリケーションからPGroongaを使って日本語全文検索機能を実現する方法を紹介しました。今回はそのPHP版として、Laravelで作ったブログ風のアプリケーションにPGroongaを使った日本語全文検索機能を組み込む方法をご紹介します。

この記事では、適当なLaravelアプリケーションが手元に無い場合を想定し、解説用に用意したLaravelアプリケーションとPostgreSQLとの組み合わせに対して、全文検索機能を組み込む手順を解説しています。すでに開発中・運用中のPostgreSQLを使用したアプリケーションがある場合には、そのアプリケーションに組み込む手順としてテーブル名等を適宜読み替えて下さい。

また、タイトルにも書いてある通りですが、この記事で紹介しているPGroongaは、PostgreSQLに対して全文検索機能を提供するソフトウェアです。開発・運用中のアプリケーションがPostgreSQL以外のデータベースを使用している場合にはPGroongaを使えませんので、くれぐれもご注意下さい。(他のデータベースを使っている場合、例えばMySQLやMariaDBであれば、PGroongaの代わりにMroongaを使うことになります。その場合の手順はここでは解説していませんので、あしからずご了承ください。)

開発環境の準備

それでは、開発環境を用意していきます。まず、以下の2つを用意します。

  • Homesteadを動作させるホストマシン(ここではUbuntu 16.04LTSと仮定します)
  • 動作確認用のWebブラウザが動作するクライアント

ホストマシンとしてLinuxのデスクトップ環境を用意して、ホストマシン自身をクライアントとして使うのが最も簡単です。別々のマシンを使う場合には、両者は同じネットワーク上に存在するか、もしくはホストマシンのネットワーク上の任意のコンピュータにクライアントから自由に接続できるものとします。

Laravelには開発環境を簡単に構築するためのHomesteadという枠組みがあり、今回はそれを使ってみることにします。Vagrantが必要なので、事前にホストマシンにVagrant 1.9以上VirtualBoxをインストールしておいて下さい。

VMの準備(ホストマシン上の操作)

開発環境のboxイメージが公開されているので、まずはそれを導入します。

% vagrant box add laravel/homestead
==> box: Loading metadata for box 'laravel/homestead'
box: URL: https://atlas.hashicorp.com/laravel/homestead
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) parallels
2) virtualbox
3) vmware_desktop

ここではVirtualboxのイメージを使うので2を選択します。

Enter your choice: 2
==> box: Adding box 'laravel/homestead' (v2.1.0) for provider: virtualbox
box: Downloading: https://atlas.hashicorp.com/laravel/boxes/homestead/versions/2.1.0/providers/virtualbox.box
==> box: Successfully added box 'laravel/homestead' (v2.1.0) for 'virtualbox'!
vagrant box add laravel/homestead 14.75s user 7.42s system 19% cpu 1:53.24 total

boxを正常にダウンロードできたので次に進みます。

Homesteadの準備(ホストマシン上の操作)

Homesteadのリポジトリを以下のようにホストの作業ディレクトリにcloneします。

% mkdir ~/work
% cd ~/work
% git clone https://github.com/laravel/homestead.git

masterブランチは不安定な場合があるため、今回はリリースブランチを使います。

% cd homestead
% git checkout v5.4.0
...
HEAD is now at f54a9f0... Tagging 5.4.0 (#595)
(END):
Homestead.yamlの準備(ホストマシン上の操作)

ホストにて init.sh を実行します。

% bash init.sh
Homestead initialized!

すると以下の3つのファイルが同じディレクトリに作成されます。

  • Homestead.yaml
  • after.sh
  • aliases

Homestead.yaml はVMの設定ファイルです。

今回は以下の項目を変更します。

  • ip: 異なるネットワークのIPアドレスを指定する。(ホストマシンが接続しているネットワークが192.168.10.0/24なら、192.168.20.0/24などのアドレスにする)
  • authorize: ホストマシンで作成したsshの公開鍵のパスを指定する。
  • keys: ホストマシンで作成したsshの秘密鍵のパスを指定する。
  • folders: ホストマシンのディレクトリーをゲスト上から見えるようにする指定だが、ホストマシン上にはLaravelアプリケーション用のファイルを設置しないため不要なので、コメントアウトする。
  • sites: ゲスト上にこれから作成するアプリケーションに合わせてパスを書き換える。
  • networks: ゲストがホストマシンが接続しているネットワークにブリッジ接続するための設定を追加する。

上記変更を反映した Homestead.yaml は次の通りです。

Homestead.yaml
---
ip: "192.168.20.10" # ホストマシンと異なるネットワークになるようにする。
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/id_homestead.pub #公開鍵のパス

keys:
    - ~/id_homestead #秘密鍵のパス

#folders:
#    - map: ~/work/Blog
#      to: /home/vagrant/Blog

sites:
    - map: homestead.app
      to: /home/vagrant/Blog/public # 後々、この位置にファイルが作られる。

databases:
    - homestead

networks:
    - type: "public_network"
      bridge: "eth0" # "wlan0"など、ホストマシンの主なインターフェースに合わせる。

IPアドレスやブリッジのインタフェース名、鍵の情報は環境に応じて適宜読み替えてください。

VMの起動(ホストマシン上の操作)

設定ファイルとコマンドの準備ができたので、ホストマシンからVMを起動します。

% vagrant up

設定に問題なければVMが正常起動します。 続けて、クライアントからゲスト上のLaravelアプリケーションに接続するために、起動したVMのブリッジ接続でのIPアドレスを調べます。

% host_if=eth0
% host_nw="$(ip addr | grep -o "inet.*$host_if" | cut -d ' ' -f 2 | cut -d '.' -f -3)."
% vagrant ssh -- ip addr | grep "$host_nw"
    inet 192.168.10.52/24 brd 192.168.10.255 scope global enp0s9

この例では192.168.10.52が割り当てられているので、クライアントからは http://192.168.10.52/ をブラウザで開けば動作を確認できることになります。

hostsファイルの編集(クライアント上の操作)

http://192.168.10.52/のようなIPアドレスの直接入力は煩雑なので、クライアントのhostsファイルを編集して、homestead.appというホスト名で参照できるようにしておきます。クライアントのhostsに以下の内容を書き足しましょう。

192.168.10.52 homestead.app

クライアントがUbuntuのデスクトップ環境の場合、hostsは /etc/hostsです。クライアントがWindowsの場合は、hostsは C:\windows\system32\drivers\etc\hosts の位置にあります。

以上で準備完了です。クライアント上のWebブラウザで http://homestead.app/ を開いてみて下さい。以下のようなエラーページが表示されるはずです。

(エラーページのスクリーンショット)

これはHomestead上のnginxが返しているエラーで、所定の位置にまだLaravelアプリケーションが存在していないという事を示しています。

Laravelアプリケーションのセットアップ

それではLaravelによるブログ風のアプリケーションを用意していきます。といっても、Laravelでのブログ風アプリケーションの開発の仕方そのものはここでは重要ではないので、あらかじめこちらで用意したサンプルのブログ風アプリケーションを使うことにしましょう。

まず、ホストマシンからゲストマシンへsshでログインします。

% vagrant ssh
vagrant@homestead:~$

そうしたら、サンプルアプリケーションのGitリポジトリをcloneします。この時、clone先のディレクトリ名をBlogと明示して、ファイルの設置先がホストマシン上のHomestead.yamlの内容と一致するようにする必要があることに気をつけて下さい。

vagrant@homestead:~$ git clone https://github.com/clear-code/pgroonga-example-laravel.git Blog

cloneし終えたら、アプリケーションを初期化します。

vagrant@homestead:~$ cd Blog
vagrant@homestead:~/Blog$ composer install
vagrant@homestead:~/Blog$ php artisan migrate
vagrant@homestead:~/Blog$ php artisan db:seed
サンプルアプリケーションの仕様

以上の手順をすべて実施したら、クライアントから http://homestead.app/posts を開いてみて下さい。以下のような記事一覧ページが表示されるはずです。

(サンプルアプリケーションのスクリーンショット)

Homestead.yamlの設定(例えば、Laravelのアプリケーションの設置先パス)を間違えていると、先のエラーページと同じ物が表示されるかもしれません。その場合、Homestead.yamlを修正してから vagrant provision を実行し、ゲスト上のnginx等を再起動する必要があります。

記事一覧ページの右上にある検索窓に「Groonga」のようなキーワードを入力すると、そのキーワードの検索結果として、postsテーブルのレコードのうちbodyカラムにキーワードを含むレコードの一覧が表示されます。ただ、コントローラの実装(app/Http/Controllers/PostController.php)を見ると分かりますが、これは以下のような単純なSQLのLIKEによる絞り込みの結果です。Groonga OR Mroongaのような凝った検索は行えません。

app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
  public function index(Request $request)
  {
    $query = $request->get('query');
    if (!empty($query)) {
      $posts = \App\Post::where('body', 'like', "%{$query}%")->orderBy('id', 'desc')->get();
    }
    else {
      $posts = \App\Post::orderBy('id', 'desc')->get();
    }
    return \View::make('posts.index')
             ->with('posts', $posts)
             ->with('query', $query);
  }
}
注意点

Homesteadの環境で普通にlaravel new Blogすると、MySQLを使うように設定されたLaravelアプリケーションが作られます。しかし今回はPGroongaの使い方の解説なので、この例では以下のように.envを編集して、データベースにはPostgreSQLを使うよう設定してあります。

commit 5f48f346ccf36e07aefdf062b2f374d83dc6151d
Author: YUKI Hiroshi <yuki@clear-code.com>
Date:   Mon Jun 26 01:56:56 2017 +0000

    Use PostgreSQL by default

diff --git a/.env b/.env
index f41ce19..ceaa34d 100644
--- a/.env
+++ b/.env
@@ -5,9 +5,9 @@ APP_DEBUG=true
 APP_LOG_LEVEL=debug
 APP_URL=http://localhost
 
-DB_CONNECTION=mysql
+DB_CONNECTION=pgsql
 DB_HOST=127.0.0.1
-DB_PORT=3306
+DB_PORT=5432
 DB_DATABASE=homestead
 DB_USERNAME=homestead
 DB_PASSWORD=secret
diff --git a/config/database.php b/config/database.php
index cab5d06..abf3d43 100644
--- a/config/database.php
+++ b/config/database.php
@@ -13,7 +13,7 @@ return [
     |
     */
 
-    'default' => env('DB_CONNECTION', 'mysql'),
+    'default' => env('DB_CONNECTION', 'pgsql'),
 
     /*
     |--------------------------------------------------------------------------

冒頭にも述べていますが、PGroongaはPostgreSQLに対して全文検索機能を提供する物なので、それ以外のデータベースに対しては使えません。ご注意下さい。

PGronngaによる全文検索機能の組み込み(ゲスト上での作業)

お待たせしました! ようやくここからが本題です。

すでにあるLaravelアプリケーションでPGroongaを使って全文検索をするには、以下の4つのステップを踏みます。

  1. PGroongaのインストール
  2. PGroongaの有効化
  3. インデックスの作成
  4. PGroongaを使って検索するように問い合わせ部分を変更

それでは順番に見ていきましょう。

PGroongaのインストール

何はともあれPGroongaのインストールが必要です。Homesteadの環境はUbuntu 16.04ベースということで、今回はUbuntu用のインストール手順を参照しました。以下は実際に実行したコマンドです。

$ sudo add-apt-repository -y universe
$ sudo add-apt-repository -y ppa:groonga/ppa
$ sudo apt-get update
$ sudo apt-get install -y -V postgresql-9.5-pgroonga

PGroongaのインストール手順は実行環境によって異なります。Ubuntu 16.04以外の環境でのインストール手順については、PGroongaのプロジェクトサイトで公開されているインストール手順の説明を参照して下さい。

PGroongaの有効化

PGroongaは、サーバー上にパッケージをインストールしただけでは使えません。機能を利用するには、PostgreSQLのデータベースに対してCREATE EXTENSION pgroonga;というSQL文を明示的に実行する必要があります。

ということで、このSQL文を実行するためのマイグレーションを作成します。

$ php artisan make:migration install_pgroonga
Created Migration: 2017_06_23_091529_install_pgroonga
database/migrations/2017_06_23_091529_install_pgroonga.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class InstallPgroonga extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
      // ここから追記
      DB::statement('CREATE EXTENSION pgroonga');
      // ここまで追記
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
      // ここから追記
      DB::statement('DROP EXTENSION pgroonga CASCADE;');
      DB::statement('DELETE FROM pg_catalog.pg_am WHERE amname = \'pgroonga\';');
      // ここまで追記
    }
}

upに書かれている内容はPGroongaのインストール手順にあるもので、downに書かれている内容はアンインストール手順にあるものです。

用意ができたら、このマイグレーションを実行します。

$ php artisan migrate

これでPGroongaを使う準備ができました。

検索対象のカラムに全文検索用のインデックスを作成する

次に、PGroongaで全文検索するためのインデックスを作ります。

Laravelのマイグレーションではindexメソッドでインデックスを定義します。

$ php artisan make:migration add_posts_body_index
Created Migration: 2017_06_23_091530_add_posts_body_index
database/migrations/2017_06_23_091530_add_posts_body_index.php
<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddPostsBodyIndex extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
      // ここから追記
      Schema::table('posts', function($table) {
        $table->index(['id', 'body'], 'pgroonga_body_index', 'pgroonga');
      });
      // ここまで追記
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
      // ここから追記
      Schema::table('posts', function($table) {
        $table->dropIndex('pgroonga_body_index');
      });
      // ここまで追記
    }
}

PGroongaを正しく使えているという事を説明するために、PGroongaのチュートリアルで説明されている内容との対応関係を見ていきます。 このチュートリアルでの説明に倣うと、インデックス作成用のSQL文は以下のようになります。

CREATE INDEX pgroonga_body_index ON posts USING pgroonga (id, body);

ここで、pgroonga_body_indexはPGroongaでの慣習に倣って付けた任意のインデックス名、postsはテーブル名です。USING pgroonga (id, body)は、インデックスの種類としてHashやB-treeなどと同列の物としてPGroongaを選択し、インデックスにはid(主キー)とbodyの両方を含めるという意味になっています。

database/migrations/2017_06_23_091530_add_posts_body_index.php
  Schema::table('posts', function($table) {
    $table->index(['id', 'body'], 'pgroonga_body_index', 'pgroonga');
  });

Laravelのマイグレーションでは、テーブル名はSchema::table('posts'...の部分で示されています。indexメソッドでインデックスを作成しており、この第1引数の['id', 'body']がインデックスに含めるカラム名の配列、第2引数がインデックス名、第3引数がインデックスの種類を示しています。PGroongaのチュートリアルで説明されている情報が過不足無く指定できていることが分かるでしょう。

なお、インデックス名を省略してnullにするとインデックス名を自動的に決定させることもできますが、downのマイグレーションでインデックス名を指定してdropIndexメソッドを呼ぶ都合上、ここではインデックス作成時にも明示的にインデックス名を指定しています。

そして、マイグレーションを実行します。

$ php artisan migrate

これによって、postsテーブルのbodyカラムを対象とした全文検索用のインデックスが作成されます。既存のレコードに対するインデックスもこの時一緒に作成されますし、この後で作成されたレコードに対しても自動的にインデックスが作成されるようになります。

以上で、全文検索の準備が整いました。

PGroongaを使って検索するように問い合わせ部分を変更

最後に仕上げとして、全文検索にPGroongaを使うように検索処理を書き換えます。

app/Http/Controllers/PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostsController extends Controller
{
  public function index(Request $request)
  {
    $query = $request->get('query');
    if (!empty($query)) {
      // 変更前
      // $posts = \App\Models\Post::where('body', 'like', "%{$query}%")->orderBy('id', 'desc')->get();
      // 変更後
      $posts = \App\Models\Post::whereRaw('body @@ ?', $query)->orderBy('id', 'desc')->get();
    }
    else {
      $posts = \App\Models\Post::orderBy('id', 'desc')->get();
    }
    return \View::make('posts.index')
             ->with('posts', $posts)
             ->with('query', $query);
  }
}

PGroongaで全文検索をするためには、PGroonga専用の演算子を使います。whereメソッドではそれらの演算子を取り扱えないので、ここではwhereRawメソッドを使ってSQLの式を直接書いています。

今回使った@@という演算子(この演算子はPGroongaの現在のドキュメントでは&?で置き換えられていることになっていますが、&?PHPの実装上の都合で使えないため、非推奨のこちらを使用しています)は、与えられた検索クエリを一般的なWebの検索エンジンの検索クエリのように取り扱う物です。よって、Groonga リリース(Groongaとリリースの両方の語を含む)やGroonga OR PGroonga(GroongatoPGroongaのどちらか片方だけでも含む)や( Mroonga OR PGroonga ) リリース(MroongaかPGroongaのどちらか片方に加えて、リリースという語句を含む)のような複雑なクエリも、検索窓に入力するだけでそのまま使うことができます。

(複雑なクエリで検索した状態のスクリーンショット)

以上で、PGroongaによる全文検索への乗り換えが完了しました。実際に検索を実行して、期待通りの結果が返ってくるか確かめてみて下さい。

まとめ

以上、LaravelアプリケーションでPGroongaを使って全文検索を行う手順の語句最初のステップをご紹介しました。

この解説を見ると分かる通り、すでにPostgreSQLを使っている環境であれば、PGroongaを使い始めるのは非常に簡単です。また、アプリケーション内の変更はごく一部だけで済むため、LIKE検索との性能比較もやりやすいでしょう。全文検索を使ったことがない人は、これを機にぜひ一度試してみて下さい。

タグ: Groonga
2017-06-26

redmine.tokyo第12回勉強会:GroongaでRedmineを高速全文検索 #redmineT

須藤です。開発しているRedmineのプラグインはWiki Change NotifierJournal Change Notifierです。

2017年5月13日にredmine.tokyo第12回勉強会が開催されました。ここでGroongaを使ってRedmineを高速全文検索するプラグインを紹介しました。

redmine.tokyoのこれまでの勉強会の資料を見てもわかるとおり、Redmineはよく作られたプロダクトです。ただ、全文検索処理には速度面・制度面で課題があり、それを解決し、Redmineの弱点を克服するのがこのプラグインです。今回の発表では、現在のRedmineの弱点を克服するだけでなく、むしろ検索を強みにするにはどうすればよいかという話もしました。たとえば、Redmine内の情報から機械学習で有用な情報を抽出し、それを活かした検索をすることでこれまでより効率よくRedmineを使えるようにする、といった具合です。このあたりに取り組むためには検索技術・データ分析技術・分析対象のデータ・開発費用などが必要です。すでにRedmineを活用していて大量の情報を保存している方で、Redmineをさらに活用することに興味のある方はご連絡ください。一緒にRedmineのさらなる活用に取り組みましょう。

関連リンク:

内容

この発表では次のことを紹介しました。

  • Redmineの全文検索をマイナスから少しプラスへ
  • Redmineの全文検索を少しプラスからすごくプラスへ
  • Redmineの開発に参加しよう
Redmineの全文検索をマイナスから少しプラスへ

Redmineはプロジェクト管理に使われるため、Redmineにはプロジェクトの情報がたくさん入っています。Redmineを活用し続ければ続けるほど増えていきます。Redmine内の情報を有効活用できればさらに効率よくプロジェクトに取り組めます。たとえば、過去の類似のバグレポートを参照することで新規のバグをすぐに解決できる、といった具合です。Redmineの情報を有効活用するために重要なのが全文検索です。

たくさんの情報の中には、重要な情報もありますが、雑多な情報もあります。そのため、単に全文検索しただけで重要な情報が見つかるわけではありません。雑多な情報もヒットしてしまい、それが重要な情報を隠してしまうからです。現在のRedmineの全文検索は重要な情報も雑多な情報も一緒くたに扱っているため、重要な情報を見つけにくくなっています。これが課題の1つです。

重要な情報を見つけやすいかどうか以前にそもそも速く検索できるかどうかも重要です。重要な情報を見つけやすかったとしても検索結果を表示するまでに時間がかかっていれば(たとえば10秒とか)使いやすくありません。検索キーワードを試行錯誤することも難しいですし、同時に複数の人が検索することもままなりません。これが現在のRedmineの全文検索のもう1つの課題です。

Redmineを高速全文検索するプラグインを使うと、大量のデータが入っていても高速(1秒以内)に重要なものを見つけやすくなります。

速度面においては、200万チケットがあるRedmineでも380msで検索できます。(従来は1時間以上かかっていたケース。)

重要なものを見つけやすくするという観点では、ヒットした内容それぞれにどれだけキーワードにマッチしていそうかの度合いをつけて、それを使ってマッチしていそうなものから提示します。これにより最初の10件程度を確認するだけで重要なものを見つけることができます。

実は、このような全文検索機能は「全文検索システム」という文脈では普通のことです。そのため、これらを実現したのはRedmineの全文検索機能をマイナスから少しプラスにした、という程度のことです。しかし、これだけでもずいぶんRedmineの検索は使いやすくなります。検索が使い物にならなくて使っていなかったという方は、ぜひこのプラグインをインストールして検索してみてください。今度はもっと活用したくなるはずですよ。

Redmineの全文検索を少しプラスからすごくプラスへ

高速・高精度の全文検索を実現するために全文検索エンジンという専用のモジュールがあります。全文検索エンジンというと「キーワードを入力して検索する」ことだけを頑張っていると思っている人が多いかもしれません。しかし、実は、検索を軸にしてもっとたくさん便利にできます。

現在のプラグインは、まだ単に高速・高精度で全文検索できるようにしているだけですが、今後はもっとRedmineを活用できるように育てていきたいです。いくつかそのアイディアを紹介します。クリアコードだけでなく、もっとRedmineを活用したい人たちと協力しながら実現したいです。実現した成果はRedmineと同じくフリーソフトウェアとして多くのRedmineユーザーが利用できるようにします。実現案も簡単に説明するので、興味のある方(実装したい方、データを持っている方、開発費を払ってでも実現したい方)はぜひご連絡ください。

類似issue検索

1つめのアイディアはissue作成時・閲覧時に自動で類似issueを提示する機能です。新しい問題が発生したときに、プラグインが類似issueを提示することで既存のノウハウを活用して早期に問題を解決できます。

類似issue検索の実現案を説明します。issueのテキストを使った類似文書検索(全文検索エンジンGroongaの標準機能)を軸に、Redmine内のメタデータを活用することで精度をあげます。メタデータとは手動で設定した関連issue情報やWiki内のテキストから機械学習した類義語情報などです。

入力補完

2つめのアイディアは入力時に適切な値を随時ユーザーに提示する機能です。たとえば、検索ボックスでキーワードの一部を入力するだけでキーワード全体の補完候補を提示します。これにより、ユーザーの入力コストを下げるだけでなく、適切なキーワードに自然と誘導することになるので、より見つかりやすい検索を実行できます。Groongaは日本語に特化した機能を組み込みで提供しており、ローマ字から日本語を入力補完することもできます。これを使うと「tok」(日本語入力OFFの状態で入力)から「東京都」を補完候補に出すこともでき、よりユーザーの入力コストを下げることができます。

検索というと見つけるためだけに使うというイメージがあるかもしれませんが、入力時にも有用です。タイトルやバージョンなどの入力欄で入力候補を提示することにより、入力内容の表記揺れ・表現の揺れが自然と少なくなります。表記揺れ・表現の揺れが少ないと全文検索エンジンもうれしいですが、理解しやすくなるので読む人もうれしいです。より活用しやすいデータということです。

入力補完の実現案を説明します。Groongaに前方一致検索(ローマ字変換対応)があるので、それを活用します。単に候補を提示するだけでは使いやすいものになりません。候補の最初の方に必要なものが提示されている必要があります。精度も大事ということです。精度をあげるために、全文検索用のインデックスの統計情報を活用します。たとえば、あまりにもヒットしすぎるようなキーワード(たとえば「です」とか)は適切ではありません。統計情報を活用してそのような不要なキーワードを除去します。また、ログやメタデータも活用します。文脈(プロジェクトやトラッカーなど)毎に候補に提示するリストを調整し、より精度の高い候補を提示します。

同義語展開

3つめのアイディアは同義語管理を支援する機能です。日本語では同じものをいろんな呼び方で示すことができます。たとえば、「ネジ」も「ねじ」も「ボルト」も同じものを指します。検索精度を高めるにはこのような同義語に関する情報が必要です。しかし、同義語の管理は大変です。たくさんありますし、文脈が違えば同義語のリストも変わるため共有することが難しいからです。

同義語のリストがあればGroongaが組み込み機能で提供している同義語展開機能を利用できます。検索部分に問題はありません。同義語管理がネックなのです。

同義語管理支援の実現案を説明します。同義語を自動で完璧に整備するのは難しいですが、人の作業を大幅に削減する支援ならできます。そこを狙います。Redmine内には大量のテキストデータがあるはずなので、機械学習で同義語候補を自動で抽出します。また、同義語を管理するUIも実装し、より人の作業を減らします。

スマートナビ(仮)

4つめは「言わなくても欲しいものを提示する機能」です。駅の近くでスマートフォンを見ると、その駅の時刻表を「自動で」表示していませんか?そのように、現在のユーザーの状況から欲しそうなものを自動で検索して提示する機能です。

共同開発者募集

もっとRedmineを活用できるようなアイディアをいくつか紹介しました。クリアコードだけでなく、もっとRedmineを活用したい人たちと協力しながら実現したいです。実現した成果はRedmineと同じくフリーソフトウェアとして多くのRedmineユーザーが利用できるようにします。実現案も簡単に説明するので、興味のある方(実装したい方、データを持っている方、開発費を払ってでも実現したい方)はぜひご連絡ください。

Redmineの開発に参加しよう

Redmineの開発に参加したいとは思っているけどなかなか実現できていない、という方はいませんか?そんな方にオススメなのがOSS Gateが開催しているイベントです。OSS Gateは「OSSの開発に参加する人を継続的に増やす取り組み」です。OSS GateではOSSの開発に参加する人をサポートするイベントを開催しています。RedmineもOSSなのでこのイベントでサポートしてもらいながらRedmineの開発に参加できます。最初の一歩をなかなか踏み出せていない、という人は活用してください。

東京では5月は22日(月)と27日(土)にイベントが開催されます。

大阪と札幌でも開催しています。(redmine.tokyo第12回勉強会には日本各地から参加者がいたので東京以外の情報も紹介しました。)

まとめ

redmine.tokyo第12回勉強会で、Groongaを使ってRedmineの全文検索機能を高速化するプラグインを紹介しました。現時点でできることだけでなく、今後の野望とRedmineの開発に参加したい人向けの情報も紹介しました。

Redmineのデータをもっと活用してより効率的に仕事を進めたくて、検索技術・データ分析技術・分析対象のデータ・開発費用を持っている方はご連絡ください。一緒に実現しましょう。

つづき: 2017-08-27
タグ: Groonga
2017-05-15

Groonga Meatup 2017:Groonga族2016 #groonga

2017年2月9日(年に一度の肉の日!)にGroonga Meatup 2017が開催されました。ここでGroongaMroongaPGroongaの2016一年間での進化の様子を紹介しました。最近のGroonga・Mroonga・PGroongaの情報をざっと把握できるのでご活用ください。

関連リンク:

内容

2016年はGroonga・PGroongaの改良が多く、Mroongaの改良は少なめでした。ただ、MroongaはGroongaを使っているので、Groongaの改良(の多く)はそのままMroongaでも利用できます。そのため、Groonga・PGroongaだけでなくMroongaも進化しています。

Groongaの大きな改良はこのあたりです。

Mroongaの大きな改良はこのあたりです。

  • FOREIGN KEY制約をサポート
  • マルチカラムインデックスの更新性能劣化を解消
  • *SSプラグマを追加(MATCH AGAINSTないでGroongaの検索条件を使える。Groongaの検索条件では複数インデックスを使えるのでMySQLで検索するよりも圧倒的に速くなる。)

PGroongaの大きな改良はこのあたりです。

  • ストリーミングレプリケーションをサポート
  • 検索の高速化(PostgreSQLがより適切な実行計画を選べるように、PostgreSQLにより精度の高い情報を提供するようになった)
  • Zstandardによるカラム圧縮をサポート
  • 各種便利演算子を追加(類似文書検索演算子・前方一致検索演算子・前方一致RK検索演算子)

他にもいろいろあるのでぜひスライドも確認してください。

まとめ

Groonga Meatup 2017で2016年のGroonga族の様子を紹介しました。

なお、今回のGroonga Meatup 2017は東京で開催しましたが、今月、名古屋と大阪でも開催されるので近辺の方はぜひお越しください!

他の発表については以下を参照してください。

おまけみたいな書き方になってしまいますが、同日、初心者向けのMroongaの電子書籍Groongaではじめる全文検索がリリースされました!初心者の人がくじけずに始められるようにできるだけ短い内容(約30ページ!)で動くものが作れる、という内容になっています。具体的にはPHPでMroongaを使ってPDF検索システムを作っています。全文検索をしたいけどどこから始めればいいかピンときていない…という方はまずはこれを読んでみてください。

タグ: Groonga
2017-02-09

2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|
タグ: