PostgreSQLは標準機能では日本語のテキストを全文検索することはできません。PostgreSQLにPGroonga(ぴーじーるんが)という拡張機能を導入することで日本語のテキストを全文検索できるようになります。しかもPGroongaは高速です。Wikipedia日本語版のテキスト(約185万件・平均約4KB)から約2万件ヒットするような全文検索をしても0.2秒かかりません。
PostgreSQLと全文検索エンジンサーバーを組み合わせて日本語全文検索を実現することもできますが、管理するサーバーが増える・SQL以外に全文検索エンジンサーバーのことを覚える必要があるなど開発・運用時のコストが高くなります。PostgreSQLだけで完結できた方が開発時も運用時も楽になります。
この記事ではRuby on Railsで作ったアプリケーションからPGroongaを使って日本語全文検索機能を実現する方法を説明します。実際にドキュメント検索システムを開発する手順を示すことで説明します。ここではCentOS 7を用いますが、他の環境でも同様の手順で実現できます。
まずPostgreSQLとPGroongaをインストールします。CentOS 7以外の場合にどうすればよいかはPGroongaのインストールドキュメントを参照してください。
% sudo -H rpm -ivh http://yum.postgresql.org/9.4/redhat/rhel-$(rpm -qf --queryformat="%{VERSION}" /etc/redhat-release)-$(rpm -qf --queryformat="%{ARCH}" /etc/redhat-release)/pgdg-centos94-9.4-1.noarch.rpm
% sudo -H rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
% sudo -H yum install -y postgresql94-pgroonga
% sudo -H /usr/pgsql-9.4/bin/postgresql94-setup initdb
% sudo -H systemctl enable postgresql-9.4
% sudo -H systemctl start postgresql-9.4
CentOS 7にはRuby 2.0のパッケージがありますが、Ruby on Rails 4.2.4はRuby 2.2が必要なのでrbenvとruby-buildでRuby 2.2をインストールします。
% sudo -H yum install -y git
% git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
% git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
% echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
% echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
% exec ${SHELL} --login
% sudo -H yum install -y gcc make patch openssl-devel readline-devel zlib-devel
% rbenv install 2.2.3
% rbenv global 2.2.3
Ruby on Railsをインストールします。
% gem install rails
いよいよ日本語全文検索機能を持ったドキュメント検索システムを開発します。
まずはrails new
で雛形を作ります。PostgreSQLのクライアントライブラリー(pg gem)をビルドするためにpg_config
コマンドがインストールされているパスをPATH
環境変数に指定しています。指定しなくてもpg_config
コマンドが見つかるなら指定する必要はありません。
% sudo -H yum install -y postgresql94-devel
% PATH=/usr/pgsql-9.4/bin:$PATH rails new document_search --database=postgresql
% cd document_search
therubyracer gemを有効にします。
# gem 'therubyracer', platforms: :ruby
% sudo -H yum install -y gcc-c++
% bundle install
PostgreSQLに接続するユーザーを作成します。スーパーユーザー権限をつけているのはCREATE EXTENSION
を実行するにはスーパーユーザー権限が必要だからです。CREATE EXTENSION
はPGroongaを有効にするときに使います。
% sudo -u postgres -H createuser ${USER} --superuser
ユーザーを作成しPostgreSQLにデータベースを作成できるようになったのでデータベースを作成します。
% bin/rake db:create
ここまでは(ほぼ)PGroongaと関係ない手順です。アプリケーションがPostgreSQLを使う場合にはよくある手順です。
ここからはPGroongaを使う場合に特有の手順になります。
まず、データベースでPGroongaを使えるようにします。
マイグレーションファイルを作成します。
% bin/rails generate migration EnablePGroonga
invoke active_record
create db/migrate/20151109091221_enable_p_groonga.rb
db/migrate/20151109091221_enable_p_groonga.rb
を次のような内容にします。search_path
を設定しているのはPGroongaが提供している演算子をpg_catalog
にある組み込みの演算子よりも優先的に使うためです。
class EnablePGroonga < ActiveRecord::Migration
def change
reversible do |r|
current_database = select_value("SELECT current_database()")
r.up do
enable_extension("pgroonga")
execute("ALTER DATABASE #{current_database} " +
"SET search_path = '$user',public,pgroonga,pg_catalog;")
end
r.down do
execute("ALTER DATABASE #{current_database} RESET search_path;")
disable_extensioin("pgroonga")
end
end
end
end
これでPGroongaを使う準備が整いました。
続いて検索対象のドキュメントを格納するテーブルを作成します。
% bin/rails generate scaffold document title:text content:text
% bin/rake db:migrate
全文検索用のインデックスを作成します。
まずマイグレーションファイルを作成します。
% bin/rails generate migration AddFullTextSearchIndexToDocuments
invoke active_record
create db/migrate/20151109092724_add_full_text_search_index_to_documents.rb
db/migrate/20151109092724_add_full_text_search_index_to_documents.rb
は次のような内容にします。ここでusing: "pgroonga"
を指定してインデックスを追加することがポイントです。
class AddFullTextSearchIndexToDocuments < ActiveRecord::Migration
def change
add_index(:documents, :content, using: "pgroonga")
end
end
このマイグレーションファイルを反映します。
% bin/rake db:migrate
PostgreSQL側の準備はできたのでアプリケーション側に全文検索機能を実装します。
モデルに全文検索用のスコープを定義します。PGroongaでは@@
演算子で全文検索をします。この演算子を使うと「キーワード1 OR キーワード2
」のようにORを使ったクエリーを指定できます。
class Document < ActiveRecord::Base
scope :full_text_search, -> (query) {
where("content @@ ?", query)
}
end
ビューにヒット件数表示機能と検索フォームをつけます。検索フォームではquery
というパラメーターに検索クエリーを指定することにします。
app/views/documents/index.html.erb
:
@@ -2,6 +2,13 @@
<h1>Listing Documents</h1>
+<p><%= @documents.count %> records</p>
+
+<%= form_tag(documents_path, method: "get") do %>
+ <%= search_field_tag "query", params["query"] %>
+ <%= submit_tag "Search" %>
+<% end %>
+
<table>
<thead>
<tr>
@@ -5,6 +5,10 @@ class DocumentsController < ApplicationController
# GET /documents.json
def index
@documents = Document.all
+ query = params[:query]
+ if query.present?
+ @documents = @documents.full_text_search(query)
+ end
end
# GET /documents/1
これで日本語全文検索機能は実現できました。簡単ですね。
動作を確認するためにQiitaから検索対象のドキュメントを取得するRakeタスクを作ります。
lib/tasks/data.rake
:
require "open-uri"
require "json"
namespace :data do
namespace :load do
desc "Load data from Qiita"
task :qiita => :environment do
tag = "groonga"
url = "https://qiita.com/api/v2/items?page=1&per_page=100&query=tag:#{tag}"
open(url) do |entries_json|
entries = JSON.parse(entries_json.read)
entries.each do |entry|
Document.create(title: entry["title"],
content: entry["body"])
end
end
end
end
end
実行して検索対象のドキュメントを作成します。
% bin/rake data:load:qiita
http://localhost:3000/documents
にアクセスし、フォームに「オブジェクト」と日本語のクエリーを入力します。元のドキュメントは100件あり、「オブジェクト」で絞り込んで16件になっています。日本語で全文検索できていますね。
次のようにOR検索もできます。「オブジェクト」単体で検索したときの16件よりも件数が増えているのでORが効いていることがわかります。
PostgreSQLとPGroonga(ぴーじーるんが)を使ってRuby on Railsアプリケーションで日本語全文検索機能を実現する方法を説明しました。
ポイントは次の通りです。
enable_extension("pgroonga")
ALTER DATABASE SET search_path
add_index(using: "pgroonga")
where("content @@ ?", query)
開発時・運用時のことを考えてPostgreSQLベースの日本語全文検索機能の実現を検討してみてはいかがでしょうか。
今月の29日(11月29日)にPGroongaのイベントがあります。PGroongaに興味がでてきた方は↓のイベントページからお申し込みください。発表内容から有益な情報を得られますし、開発者に直接質問することもできます。
Groonga Meatup 2015 - Groonga | Doorkeeper
MySQLは先日リリースされたMySQL 5.7から標準機能で日本語のテキストを全文検索できるようになりました。逆に言うと、現在広く使われているMySQL 5.6以前では日本語のテキストを全文検索できません。MySQLにMroonga(むるんが)というストレージエンジンを導入することで日本語のテキストを全文検索できるようになります。しかもMroongaは高速です。MySQL 5.7で導入された日本語全文検索機能よりも高速です。
MySQLと全文検索エンジンサーバーを組み合わせて日本語全文検索を実現することもできますが、管理するサーバーが増える・SQL以外に全文検索エンジンサーバーのことを覚える必要があるなど開発・運用時のコストが高くなります。MySQLだけで完結できた方が開発時も運用時も楽になります。
この記事ではRuby on Railsで作ったアプリケーションからMroongaを使って日本語全文検索機能を実現する方法を説明します。実際にドキュメント検索システムを開発する手順を示すことで説明します。ここではCentOS 7を用いますが、他の環境でも同様の手順で実現できます。
まずMySQLとMroongaをインストールします。CentOS 7以外の場合にどうすればよいかはMroongaのインストールドキュメントを参照してください。
% sudo -H yum install -y http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
% sudo -H yum install -y http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
% sudo -H yum install -y mysql-community-server
% sudo -H systemctl start mysqld
% sudo -H yum install -y mysql-community-mroonga
CentOS 7にはRuby 2.0のパッケージがありますが、Ruby on Rails 4.2.4はRuby 2.2が必要なのでrbenvとruby-buildでRuby 2.2をインストールします。
% sudo -H yum install -y git
% git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
% git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
% echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
% echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
% exec ${SHELL} --login
% sudo -H yum install -y gcc make patch openssl-devel readline-devel zlib-devel
% rbenv install 2.2.3
% rbenv global 2.2.3
Ruby on Railsをインストールします。
% gem install rails
いよいよ日本語全文検索機能を持ったドキュメント検索システムを開発します。
まずはrails new
で雛形を作ります。
% sudo -H yum install -y mysql-community-devel
% rails new document_search --database=mysql
% cd document_search
Active Record 4.2.4ではmysql2 gemは0.3系でなければいけないのでGemfileでバージョンを指定します。
Gemfile
:
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.4'
# Use mysql as the database for Active Record
-gem 'mysql2'
+gem 'mysql2', '~> 0.3.20'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
バージョンを更新します。
% bundle install
therubyracer gemを有効にします。
# gem 'therubyracer', platforms: :ruby
% sudo -H yum install -y gcc-c++
% bundle install
データベースを作成します。
% bin/rake db:create
ここまでは(ほぼ)Mroongaと関係ない手順です。アプリケーションがMySQLを使う場合にはよくある手順です。
ここからはMroongaを使う場合に特有の手順になります。
まず検索対象のドキュメントを格納するテーブルを作成します。
% bin/rails generate scaffold document title:text content:text
rake db:migration
する前にマイグレーションファイルを編集してストレージエンジンをMroongaに変更します。
@@ -1,6 +1,6 @@
class CreateDocuments < ActiveRecord::Migration
def change
- create_table :documents do |t|
+ create_table :documents, options: "ENGINE=Mroonga" do |t|
t.text :title
t.text :content
このマイグレーションファイルを反映します。
% bin/rake db:migrate
全文検索用のインデックスを作成します。
まずマイグレーションファイルを作成します。
% bin/rails generate migration AddFullTextSearchIndexToDocuments
invoke active_record
create db/migrate/20151109143515_add_full_text_search_index_to_documents.rb
db/migrate/20151109143515_add_full_text_search_index_to_documents.rb
は次のような内容にします。ここでtype: :fulltext
を指定してインデックスを追加することがポイントです。
class AddFullTextSearchIndexToDocuments < ActiveRecord::Migration
def change
add_index :documents, :content, type: :fulltext
end
end
このマイグレーションファイルを反映します。
% bin/rake db:migrate
MySQL側の準備はできたのでアプリケーション側に全文検索機能を実装します。
モデルに全文検索用のスコープを定義します。MySQLで全文検索を実行するときはMATCH(...) AGAINST('...')
を使います。Web検索エンジンのように「キーワード1 OR キーワード2
」とORを使ったクエリーを指定できるMATCH(...) AGAINST('*D+ ...' IN BOOLEAN MODE')
がオススメです。
class Document < ActiveRecord::Base
scope :full_text_search, -> (query) {
where("MATCH(content) AGAINST(? IN BOOLEAN MODE)", "*D+ #{query}")
}
end
ビューにヒット件数表示機能と検索フォームをつけます。検索フォームではquery
というパラメーターに検索クエリーを指定することにします。
app/views/documents/index.html.erb
:
@@ -2,6 +2,13 @@
<h1>Listing Documents</h1>
+<p><%= @documents.count %> records</p>
+
+<%= form_tag(documents_path, method: "get") do %>
+ <%= search_field_tag "query", params["query"] %>
+ <%= submit_tag "Search" %>
+<% end %>
+
<table>
<thead>
<tr>
@@ -5,6 +5,10 @@ class DocumentsController < ApplicationController
# GET /documents.json
def index
@documents = Document.all
+ query = params[:query]
+ if query.present?
+ @documents = @documents.full_text_search(query)
+ end
end
# GET /documents/1
これで日本語全文検索機能は実現できました。簡単ですね。
動作を確認するためにQiitaから検索対象のドキュメントを取得するRakeタスクを作ります。
lib/tasks/data.rake
:
require "open-uri"
require "json"
namespace :data do
namespace :load do
desc "Load data from Qiita"
task :qiita => :environment do
tag = "groonga"
url = "https://qiita.com/api/v2/items?page=1&per_page=100&query=tag:#{tag}"
open(url) do |entries_json|
entries = JSON.parse(entries_json.read)
entries.each do |entry|
Document.create(title: entry["title"],
content: entry["body"])
end
end
end
end
end
実行して検索対象のドキュメントを作成します。
% bin/rake data:load:qiita
http://localhost:3000/documents
にアクセスし、フォームに「オブジェクト」と日本語のクエリーを入力します。元のドキュメントは100件あり、「オブジェクト」で絞り込んで16件になっています。日本語で全文検索できていますね。
次のようにOR検索もできます。「オブジェクト」単体で検索したときの16件よりも件数が増えているのでORが効いていることがわかります。
MySQLとMroonga(むるんが)を使ってRuby on Railsアプリケーションで日本語全文検索機能を実現する方法を説明しました。
ポイントは次の通りです。
create_table(options: "ENGINE=Mroonga")
add_index(type: :fulltext)
where("MATCH(content) AGAINST(? IN BOOLEAN MODE)", "*D+ #{query}")
開発時・運用時のことを考えてMySQLベースの日本語全文検索機能の実現を検討してみてはいかがでしょうか。
今月の29日(11月29日)にMroongaのイベントがあります。Mroongaに興味がでてきた方は↓のイベントページからお申し込みください。発表内容から有益な情報を得られますし、開発者に直接質問することもできます。
Groonga Meatup 2015 - Groonga | Doorkeeper
関連:Ruby on RailsでPostgreSQLとPGroongaを使って日本語全文検索を実現する方法
以前、Fedoraプロジェクトでパッケージをリリースするための方法について書きました。
そして、次のような共同メンテナ(co-maintainer)を募集する記事も書きました。
その後、実際に共同メンテナとしてパッケージメンテナを新たに追加する機会があったので、そのときのことを紹介します。 おそらく、パッケージメンテナになる場合の最速のパターンです。
既存パッケージの共同メンテナになるには、次のような段取りを踏みます。
ざっくり説明すると、共同メンテナになりたい人がすることと、既存パッケージのメンテナがすることの2つがあります。
共同メンテナになりたい人がすること
ここまでが、共同メンテナになりたい人がすることです。 公開鍵等のところまでについては、冒頭で紹介した過去の記事を参照してください。
Proxy sponsorshipのチケットを作成をお願いするところまでできたら、あとはじっと待つだけです。
既存パッケージのメンテナがすることは上記の2つです。Proxy sponsorshipについては、後述します。
Proxy sponsorshipとは、共同メンテナを追加するときに(packagerグループでsponsor権限をもっている人に)スポンサーになってもらうことを指します。 新規パッケージを追加するときには自身のスポンサーを探しましたが、Proxy sponsorshipの場合には「Proxy」とあるように、共同メンテナのために代理申請するところが違います。
例えば、Groongaに対するProxy sponsorshipのリクエストは次のようなチケットを作成しました。
チケットを作成するときは、コンポーネントとして「Comaintainership request」を選択して、共同メンテナに関するチケットであることを明示します。
あとは、スポンサーがつくのを待ちます。上記のチケットの場合、1日でスポンサーがついて、無事myokoymさんはpackagerグループのメンバーになりました。
共同メンテナの対象者がpackagerグループに入ったら、次はCommit Accessを付与する必要があります。 packagerグループに入っただけでは、パッケージを管理しているリポジトリにコミットすることはできません。
そのため、パッケージの管理者が、共同メンテナにしたい人のFedoraアカウントに対してコミット権を付与する操作が必要です。
Fedoraプロジェクトでは、Fedora Package Databaseというのがあって、管理画面から共同メンテナに対するコミット権を管理できるようになっています。*1
コミット権を与えたら、次のアップデートを共同メンテナに出してもらいましょう。
Fedoraプロジェクトにてみんなでパッケージをメンテナンスする方法として、既存のパッケージの共同メンテナになるというのを紹介しました。
自分の使っているパッケージでメンテナが1人しかいなかったり、新規リリースへの追従が滞っているような場合には、共同メンテナになって一緒に良くしていくのはどうでしょうか。
*1 ブランチごとに付与できるので、特定のブランチのみのメンテナを任命するという運用にすることもできる
全文検索エンジンGroongaは毎年いい肉の日(11月29日)にイベントを開催しています。今年も「Groonga Meatup 2015」という名前で開催予定です。
Groonga Meatup 2015の発表内容を紹介するのでおもしろそうなのがあった人はぜひお越しください。おもしろそうな内容があるけど会場まで来れないという方はインターネット配信をご利用ください。YouTubeのGroongaチャンネルでライブ配信する予定です。
なお、今回、はじめてイベントTシャツを作成しました。(オリジナルTシャツ作成サービスTMIXを提供しているspice lifeさんがスポンサーしてくれました。)
次のデザインが前面にプリントされたTシャツになります。肉々しいですね。
それでは内容を紹介します。
Groonga Meatup 2015は2部構成になっています。第1部は開発者がGroongaとその関連プロダクトについて次のことを紹介します。
関連プロダクトは次の通りです。
第1部では次の2つの発表があります。
「Groonga族2015」ではGroonga・Mroonga・PGroonga・Rroonga・Droongaについて、特徴・最新情報・今後を紹介します。現時点でGroonga族2015の資料は185ページもあります。30分の枠なのに、です。すべてを細かく説明する時間はないはずなので、30分の中では駆け足で紹介し、懇親会の時間に肉でも食べながら、参加者とやりとりしながら、細かいところを紹介する予定です。
Groongaとその関連プロダクトをキャッチアップしたい方にオススメの内容です。
「Turbo Selector (grn_ts) の紹介」では開発を進めているGroongaの次期クエリー実行エンジン「grn_ts(ぐるんたす)」について紹介します。grn_tsはGroongaのカラムストアの特性をより活かしたクエリー実行エンジンになるように実装されていて、現在のクエリー実行エンジンよりも10倍速くなることもあります。
Groongaの高速化に興味のある方にオススメの内容です。なお、grn_tsについてはgrn_ts (ぐるんたす)の紹介も参照してください。
第2部はユーザーがGroongaと関連プロダクトについて「自分がよいと思っていること」を紹介します。ユーザーがどうしてGroongaあるいは関連プロダクトを使っているかを知ることができます。自分がどのプロダクトを使うか選ぶときに参考になりそうですね。
第2部では次の8つの発表があります。
(たぶん)ヒトメディアさんでMroongaを使ってよかったことを話してくれるはずです。(たぶん)Ruby on RailsからMroongaを使っているので、Ruby on RailsでMroongaを使ってよかったことが聞けるかもしれません。
MySQLで日本語全文検索したい人は楽しみにしてください。
北市さんはEPUB SearcherでDroongaを使っているので、それで得られた知見をもとに話してくれるのでしょう。
Groongaを使って実装されている分散全文検索エンジンDroongaについて興味のある方は楽しみにしてください。
高橋さんはownCloudというオープンソースのオンラインストレージ製品にMroongaを使ってファイルの中身で全文検索できるようにする機能を追加しました。この事例はMroongaのサイトでも紹介しています。ownCloudはPHPで実装されているのでPHPからMroongaを利用することについての話も既けるかもしれません。
ownCloudに興味がある方、PHPからMroongaを使おうかと思っている方は楽しみにしてください。
村山さんはALog ConVerterというアクセスログを収集する商用のセキュリティ製品に関わっています。ALog ConVerterの最新バージョン(v7)からバックエンドのデータベースにGroongaを使っているのですが、それに関する話をしてくれるはずです。ALog ConVerterはWindows上で動く製品で、もちろんGroongaもWindows上で動いています。
WindowsでGroongaを動かすことに興味がある方は楽しみにしてください。
村上さんはかなりGroongaを使い込んでいる方です。最近、Groonga term similar pluginとGroonga output utility pluginを開発していました。これらを使ってGroongaでタグ検索を実装する話をしてくれるのでしょう。
Groongaでタグ検索をしようと考えている方は楽しみにしてください。
なお、村上さんのブログ・サイトは有益な情報がたくさんあるので、一読をオススメします。
瀬戸さんはピタジョブでどのようにDroongaを使っているかを紹介してくれます。Droongaの事例の2件目です。
Droongaに興味のある方はこちらも楽しみにしていてください。
佐藤さんはデータ転送ツールEnbulkのGroongaプラグインを開発しています。それに関する話をしてくれるのかもしれません。(違う話かもしれません。)
Groongaにどうやってデータを入れるかに興味がある方は楽しみにしてください。(違う話だったらすみません。)
おんがえしさんはMilkodeやHonyomiなどRroongaを使ったアプリケーションをいくつも開発しています。最近は公式のRroonga用のDockerイメージを作成してくれました。それに関して話をしてくれるはずです。
Dockerに興味がある、簡単にRroongaを使いたいという方は楽しみにしてください。
11月29日(今週の日曜日)開催予定のGroonga Meatup 2015の内容を紹介しました。まだ空きがあるので、興味がある話題があった方はぜひ参加してみてください。
なお、無料で懇親会に参加できます。会場提供のぐるなびさんが懇親会用の飲食物も提供してくれるからです。この機会にGroonga関連情報をゲットしてください。
PostgreSQLカンファレンス2015のPGroongaの実装というセッションでPGroongaについて自慢しました。PGroongaはPostgreSQLに超高速日本語全文検索機能を追加する拡張機能です。
関連リンク:
内容は基本的にPGroongaの自慢です。(amindexを実装する人向けのヒントも要所要所で入っています。)
自慢なのでPGroongaのよいところを中心に紹介しています。もちろん苦手なところもあるのですが、それはまた別の機会にしました。このセッションに参加した人の半分くらいは全文検索を使っていなかったので、どうして苦手なのかという踏み込んだ説明をすると伝わりにくくなっていたかもしれません。そういう意味で、今回はこの配分でよかったです。
今回紹介したよいところは大きくわけて次の2つです。詳細は前述のスライドを参照してください。
セッション前には「PGroongaをインストールしたことがある人」・「PGroongaを使ったことがある人」はほとんどいなかったのですが、セッション後にはほとんどの人が「PGroongaを使ってみよう!」という気になっていたので発表してよかったです。(セッション前後に質問をして手を挙げて回答してもらいました。)
PostgreSQLカンファレンス2015には他にもいろいろセッションがありました。その中でもPivotal Greenplumのセッションは参加してよかったセッションでした。
Pivotal Greenplumは外部の全文検索サーバーを使った全文検索の仕組みを独自に実現しているようだったので、セッションが終わった後に「PGroongaというPostgreSQLと親和性の高い全文検索拡張があるよ!使いませんか!?」とアピールしました。よさそうだね!という反応をもらったので、近いうちにPivotal GreenplumでもPGroongaを使った高速な全文検索機能が実装されるかもしれません。
参考:Pivotal GreenplumはPostgreSQLベースの(forkして実装した)データベースです。最近OSSになりました。(リポジトリー)
PostgreSQLカンファレンス2015でPGroongaを自慢してきました。PostgreSQLユーザーの人に知ってもらう機会ができてよかったです。主催の日本PostgreSQLユーザ会さん、ありがとうございます。
2015-11-29にPGroongaが使っている全文検索エンジンであるGroongaのイベント「Groonga Meatup 2015」があります。PGroongaの話題もあるのでPGroonga・Groongaに興味ある方はぜひお越しください。
Sylpheedという「軽快で使いやすいオープンソースのメールソフト」があります。 以前、Sylpheed向けにプラグインを作る方法をWindows版を前提に紹介しました。
もう2年以上前の記事となり、内容の一部が若干古くなっていることから、改めてソースコードに添付されているプラグインを作る手順を紹介します。*1
Sylpheedには、バージョン3.0から正式に導入されたプラグインの仕組みがあります。 このプラグインの仕組みはしばしば改訂*2されています。 そのため、本記事で対象とするSylpheedのバージョンは現在リリースされている最新の安定版である3.4.3 Windows版とします。*3 もう間もなく3.5.0が正式リリースされますが、本記事の内容はそのまま使えるはずです。
Sylpheedのプラグインの仕様はプラグイン仕様として文書化されています。 基本的に以下の2つのライブラリが提供するAPIを利用して、Sylpheedと連携して動作させる仕組みになっています。
具体的に利用できるAPI一覧については、ソースアーカイブに含まれている libsylph/libsylph-0.def
と src/libsylpheed-plugin-0.def
でエクスポートされている内容で知る事ができます。
LibSylphメールライブラリ(libsylph)では、ネットワークやメールに関する機能を利用するためのAPIが数多く提供されています。
プラグインインターフェースライブラリ(libsylpheed-plugin)では、プラグインからユーザインタフェースを制御するためのAPIが多数提供されています。
プレフィクスが syl_plugin_
とついているものが該当します。
つまり、この2つのライブラリが提供しているAPIと組み合わせてできることなら、プラグインの実装次第で何でもできるというわけです。
プラグインでは、シグナルと呼ばれるイベントに対応したコールバックを登録することで、ユーザの操作に応じた処理を行なわせることができます。 プラグインから利用できるシグナルは以下の通りです。
シグナル | シグナルの発行タイミング |
---|---|
folderview-menu-popup | メールの振り分けフォルダツリー表示で右クリックしたときに発行されます。 |
summaryview-menu-popup | サマリビュー(件名等の一覧表示)で右クリックしたときに発行されます。 |
compose-send | メール送信を実行したときに発行されます。 |
compose-created | メール作成画面を表示したときに発行されます。 |
compose-destroy | メール作成画面を閉じたときに発行されます。 |
textview-menu-popup | メッセージビュー(メール本文を表示)で右クリックしたときに発行されます。 |
messageview-show | メッセージビューにメールを表示したときに発行されます。 |
inc-mail-start | メール受信開始時に発行されます。 |
inc-mail-finished | メール受信終了時に発行されます。 |
prefs-common-open | 全般の設定画面を表示したときに発行されます。 |
prefs-account-open | アカウント編集画面を表示したときに発行されます。 |
prefs-filter-open | 振り分けの設定画面を表示したときに発行されます。 |
prefs-filter-edit-open | フィルタルール編集画面を表示したときに発行されます。 |
prefs-template-open | テンプレート設定画面を表示したときに発行されます。 |
plugin-manager-open | プラグイン管理画面を表示したときに発行されます。 |
Sylpheedで公式に提供されているプラグインには以下の2つがあります。
attachment_tool
test
ソースパッケージsylpheed-3.4.3.tar.gzもしくはsylpheed-3.4.3.tar.bz2の plugin/attachment_tool
ディレクトリおよび plugin/test
ディレクトリにプラグインのソース一式が含まれています。
*4
公開中のSylpheedのプラグインについては、プラグインページにいくつか有志によるプラグインが紹介されています。
attachment_tool
プラグインとはattachment_tool
プラグインは Sylpheedのプラグイン紹介ページにて紹介されていますが、添付ファイルを削除するためのプラグインです。
任意のメールを選択した状態で、メニューから [ツール] - [添付ファイルを削除]
を選択することで添付ファイルの削除を行うことができます。
対象がローカルフォルダである必要があるため、IMAPアカウントでは使えません。
MIMEの構造はそのまま残っているので、どんなファイルが添付されていたかという情報は失われません。 *5
test
プラグインとはtest
プラグインはプラグインの基本的な構造を実装したものです。test
プラグインは開発者向けのため、Sylpheedのプラグイン紹介ページでは言及されていません。
Windows版ではdllとして提供されていないので、試してみるには自分でビルドする必要があります。
このプラグインは、プラグインを実装しようとするときに非常に参考になります。 プラグインが実装すべき関数やシグナルがシンプルにまとまっているからです。プラグインを作るときの雛形として使うことができます。
test
プラグインの具体的な内容はソースパッケージの PLUGIN.ja.txt
に記載されています。
では、Windowsでこのtestプラグインを作ってみましょう。 まずは、Sylpheedのプラグインをビルドするための環境構築をします。
環境構築手順についてはSylpheed Win32を元に記述しています。
ここまでできると、公式で配布されているインストーラ版もしくはzipアーカイブ版で使えるプラグインが作れます。
SylpheedのプラグインをビルドするためのツールはMinGWのものを利用します。ここではネットワーク経由でのインストールを行うことのできるインストーラーmingw-get-setup.exeを使ってインストールします。
インストールの途中にインストールするコンポーネントを選択する箇所があります。そこでは以下を選択します。
以降の説明では c:\MinGW
へインストールしたものとして説明します。
正しくインストールできていれば、c:\MinGW\msys\1.0\msys.bat
がインストールされています。msys.bat
を実行するとウィンドウが表示されます。
これ以降の説明では、msys.bat
を実行して起動したシェルでの操作はプロンプトに$をつけて説明します。
コマンドラインで作業できるように、パスを通しておきましょう。
$ export PATH=/c/MinGW/bin:/bin:$PATH
パッケージのダウンロードを行うのに必要なので、msys-wgetパッケージをインストールします。
$ mingw-get install msys-wget
正しくインストールできていれば、wget --versionを実行するとバージョンが表示されます。
$ wget --version
GNU Wget 1.12 built on msys.
...以下省略...
後でzipアーカイブの展開に使うのでunzipコマンドをインストールします。 インストールには以下のコマンドを実行します。
$ mingw-get install msys-unzip
正しくインストールできていれば、unzipを引数なしで実行するとヘルプが表示されます。
$ unzip
UnZip 6.00 of 20 April 2009, by Cygwin. Original by Info-ZIP.
..以下省略...
後述するインポートライブラリの作成で使うので、mingw32-pexportsパッケージをインストールします。
$ mingw-get install mingw32-pexports
正しくインストールできていれば、pexportsを引数なしで実行するとヘルプが表示されます。
$ pexports
PExports 0.44 Copyright 1988, Anders Norlander
...以下省略...
GTK+に関しては、Sylpheed向けにSDKが用意されているので、それを使います。 以降のシェルでの作業は$HOME/sylpheedディレクトリを作業ディレクトリとします。
$ mkdir -p sylpheed
$ cd sylpheed
$ wget 'http://sylpheed.sraoss.jp/sylpheed/win32/MinGW/GTK-MinGW-SDK_20140603.zip'
$ unzip GTK-MinGW-SDK_20140603.zip
シェル上で以下のコマンドを実行します。GTK+のデモアプリケーションが起動したら正常にインストールできています。
$ $HOME/sylpheed/GTK/bin/gtk-demo.exe
以前の記事を書いていた当時には、SDKがありませんでした。 GTK+をインストールした後に、ライブラリの個別更新が必要だったので、楽になりました。
ここまでで、GTK+の環境が用意できました。 プラグインのビルドには、冒頭で説明した以下の2つのライブラリが必要です。
Sylpheedをソースからビルドするというのも良いですが、MinGWだとビルドには時間もかかります。*6
そこで、Sylpheed公式サイトで配布されているzipアーカイブ版を利用してこれらライブラリのインポートライブラリを作成し、シンボルの解決はそのインポートライブラリをリンクすることによって行います。 *7
$ cd $HOME
$ wget 'http://sylpheed.sraoss.jp/sylpheed/win32/sylpheed-3.4.3-win32.zip'
$ unzip sylpheed-3.4.3-win32.zip
$ cd Sylpheed-3.4.3
$ pexports libsylph-0-1.dll > libsylph-0-1.def
$ dlltool --dllname libsylph-0-1.dll --input-def libsylph-0-1.def --output-lib libsylph-0-1.a
$ pexports libsylpheed-plugin-0-1.dll > libsylpheed-plugin-0-1.def
$ dlltool --dllname libsylpheed-plugin-0-1.dll --input-def libsylpheed-plugin-0-1.def --output-lib libsylpheed-plugin-0-1.a
上記コマンドを実行して、インポートライブラリが2つ作成できていることを確認します。
プラグインのビルドに必要なヘッダが含まれているソースパッケージをダウンロード/展開します。
$ cd $HOME/sylpheed
$ wget 'http://sylpheed.sraoss.jp/sylpheed/v3.4/sylpheed-3.4.3.tar.gz'
$ tar xvf sylpheed-3.4.3.tar.gz
GTK+関連で必要な環境変数の設定を行います。
$ export PATH=$PATH:$HOME/sylpheed/GTK/bin
$ export PKG_CONFIG_PATH=$HOME/sylpheed/GTK/lib/pkgconfig
pkg-configコマンドが実行できることを確認します。*8
$ pkg-config --version
0.20
以上でプラグインのビルドに必要なすべての環境が整いました。
次に、展開したソースコードのtestプラグインのディレクトリへと移動し、以下のようにしてプラグインをビルドします。
$ cd $HOME/sylpheed/sylpheed-3.4.3/plugin/test
$ gcc -shared -o test.dll test.c -I../../libsylph -I../../src `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` $HOME/Sylpheed-3.4.3/libsylph-0-1.a $HOME/Sylpheed-3.4.3/libsylpheed-plugin-0-1.a
test.dllがビルドできたら、以下のようにしてプラグインをインストールします。 *9
$ cp test.dll /c/Users/(ユーザー名)/AppData/Roaming/Sylpheed/plugins
あるいは、zipアーカイブ版の plugins
ディレクトリにコピーするのでもよいです。
Sylpheed.exeを実行し、アプリケーションを起動します。
メニューにある [設定] - [プラグインの管理]
から test
プラグインがリスト登録されているはずです。
SylpheedのWindows版のzipをもとに、Linux上でプラグインをクロスコンパイルすることもできます。
Linuxの場合、pexportsの代替としてgendefというmingw-w64-toolsパッケージ *10に含まれているツールをつかってインポートライブラリを作成します。
% gendef libsylph-0-1.dll
これでインポートライブラリができたら、コンパイルしましょう。SDKに含まれる.pcファイルはプレフィクスとして/targetを前提としているのでシンボリックリンクを張っておくとよいでしょう。*11
ここまで準備できたら、あとは次の手順でビルドするだけです。
% i686-w64-mingw32-gcc -c test.c -I../../libsylph -I../../src `pkg-config --cflags glib-2.0` `pkg-config --cflags gtk+-2.0`
% i686-w64-mingw32-gcc -shared -o test.dll test.c -I../../libsylph -I../../src `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` $HOME/work/sylpheed/mingw/Sylpheed-3.4.3/libsylph-0-1.dll.a $HOME/work/sylpheed/mingw/Sylpheed-3.4.3/libsylpheed-plugin-0-1.dll.a
test.dllをWindowsのプラグインディレクトリへとコピーしてあげれば、動作します。
Windows版のSylpheed 3.4.3向けにプラグインを作る方法を紹介しました。 Windows版は長らくバンドルしているGTK+のバージョンが古く、公式版に合わせたプラグインを開発しようとすると新しめの便利なGLib/GTK+のAPIがことごとく使えないという問題がありましたが、現在ではそれも解消されています。
一度プラグインを作る環境さえ整えてしまえば、Windowsであっても*12プラグインを作るのはそれほど難しいことではありません。
test
プラグインよりも、もう少しだけ複雑なものについては、Sylpheedのプラグインの作り方で紹介しています。
「メール送信時に本文のプレビューと、送信可否の問い合わせを行うプラグイン」として、サンプルコードをまじえて解説しています。
これからはじめる人は参考にしてみてください。
*1 この記事を書くきっかけは、IMAP IDLE/NOTIFYに対応したsylpheed-imap-notifyというプラグインで、Windows版が欲しいと言っている人がいたため。実際にはプラグインが非公開のAPIを使っていたため、Windows版の提供は難しいことがわかった。
*2 インタフェースバージョンのことを指す。
*3 Windows版特有の内容を除いては、Linuxなどでもその知識を生かしてプラグインを開発することができます。
*4 インストーラ版およびzipアーカイブ版にはソースは含まれていません。
*5 アイコン等が変わらないので、添付ファイルが削除されていることは添付ファイルのサイズ等から判断します。
*6 プラグインを作りたいだけなら、ソースからビルドする必要はない。独自ビルドする必要があるのは、エクスポートされていないシンボルをプラグインからどうしても使いたいときに限られる。
*7 すでにお使いのzipアーカイブ版もしくはインストール版のバイナリがあれば、改めてダウンロードしなくても既存のものを使うのでも構いません。その場合は適宜読み替えてください。
*8 pkg-configはGTK+に含まれています。
*9 ユーザー名は各自読み替えてください。
*10 Debianの場合。他のディストリビューションの場合は適宜読みかえてください。
*11 atk.pcだけ/devel以下を前提としているので、その場合修正する必要があります。
*12 GTK+の知識さえあればという条件がつく