PostgreSQLは各種プラットフォーム用のパッケージを提供しているため、簡単にインストールすることができます。PostgreSQL用の拡張機能のインストール方法も簡単です。拡張機能のバイナリーと設定ファイル*1を拡張機能用のディレクトリーに配置してCREATE EXTENSION
を実行するだけです。
GNU MakeがあるシステムではPGXS*2という拡張機能のビルドを支援する仕組みを使うことができます。PGXSを使えば数十行程度でGCCを使って拡張機能をビルドする仕組みができます*3。
しかし、公式のWindows版PostgreSQLパッケージ*4はVisual Studioでビルドされているため、GCCを使うPGXSでは公式のWindows版PostgreSQLパッケージ用の拡張機能をビルドできません。そこで、CMakeを使って公式のWindows版PostgreSQLパッケージ用のビルドシステムの作り方を紹介します。
なお、MinGWを使ってWindows版PostgreSQLをビルドする場合はPGXSを使えます*5。また、PostgreSQL本体と一緒に拡張機能をビルドする場合はPostgreSQL自体のビルドシステムを使えます*6。ここで紹介する方法は「公式のWindows版PostgreSQLパッケージ用に拡張機能だけをビルドする」ビルドシステムの作り方です。
ビルドシステムを作るためにはビルド方法を確立していなければいけません。Visual Studio用の拡張機能のビルド方法はPostgreSQLのWikiにまとまっています。ざっくり言うと次の設定をしたVisual Studioのソリューションファイルを作ってビルドします。
include\server\port\win32_msvc
include\server\port\win32
include\server
include
lib
postgres.lib
をリンクするWikiではこれらの設定をしたプロジェクトファイルを手動で作る前提になっているように見えますが、バージョン管理システムと相性が悪いですし、更新にはVisual Studioが必要になりメンテナンスしづらいのでやりたくありません。ということで、これらの設定をしたVisual Studioでのビルド用のファイルを生成することにします*7。
CMakeを使うとVisual Studioでのビルド用のファイルを生成することができます。また、CMakeはCPackというパッケージ作成用の仕組みも用意しているのでビルド済みの拡張機能のパッケージ作成までできます。
CMakeを使った場合は次のようにすればビルドできます。「%PostgreSQLをインストールしたフォルダー%
」と「%PostgreSQLのバージョン%
」は適切な値に置き換えます。例えば、「..\pgsql
」と「9.4.1-3
」といった具合です。
> cmake . -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=%PostgreSQLをインストールしたフォルダー% -DPOSTGRESQL_VERSION=%PostgreSQLのバージョン% > cmake --build . --config Release
ビルドした拡張機能をインストールする場合は次のようにします。
> cmake --build . --config Release --target install
パッケージを作成する場合は次のようにします。
> cmake --build . --config Release --target package
簡単ですね。
ではCMake用の設定ファイル(CMakeLists.txt
)を作ります。ベースは次のようになります。ここに前述のVisual Studioでの設定を追加していきます。
cmake_minimum_required(VERSION 3.0.0) set(PROJECT_NAME "拡張機能名") # 例: "PGroonga" set(PROJECT_ID "拡張機能のID") # 例: "pgroonga" set(VENDOR "拡張機能の開発者") # 例: "The PGroonga Project" set(VERSION_MAJOR "拡張機能のメジャーバージョン") # 例: "0" set(VERSION_MINOR "拡張機能のマイナーバージョン") # 例: "5" set(VERSION_PATCH "拡張機能のパッチバージョン") # 例: "0" # ↑は.controlから抽出することもできる # 方法は後述するPGroongaの例を参照すること set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") project("${PROJECT_ID}") # ↓はユーザーが指定した「%PostgreSQLをインストールしたフォルダー%」になる set(POSTGRESQL_DIR "${CMAKE_INSTALL_PREFIX}" CACHE PATH "PostgreSQL binary directory") # ↓はパッケージを作成するときだけ必要 set(POSTGRESQL_VERSION "unknown" CACHE STRING "PostgreSQL version") set(LIBRARY_NAME "lib${PROJECT_ID}") set(EXTENSION_DIR "lib") set(EXTENSION_DATA_DIR "share/extension") set(DOCUMENT_DIR "share/${PROJECT_ID}") set(SOURCES "ソースコード1.c" "ソースコード2.c" "...")
Visual Studioでの設定を再確認します。
include\server\port\win32_msvc
include\server\port\win32
include\server
include
lib
postgres.lib
をリンクする順に設定します。まずは「DLLを作成する」です。SHARED
とファイル名のベース名を拡張機能IDにすることがポイントです。
add_library("${LIBRARY_NAME}" SHARED ${SOURCES}) set_target_properties("${LIBRARY_NAME}" PROPERTIES OUTPUT_NAME "${PROJECT_ID}")
次は「素のCとしてコンパイルする」ですが、これは特になにもする必要はありません。
続いて「C++の例外を無効にする」は/EHsc
オプションを指定します。詳細はMSDNの/EH(例外処理モデル)のドキュメントを参考にしてください。
set_source_files_properties(${SOURCES} PROPERTIES COMPILE_FLAGS "/EHsc")
「includeの検索パスを追加する」は次のようにします。
include_directories( "${POSTGRESQL_DIR}/include/server/port/win32_msvc" "${POSTGRESQL_DIR}/include/server/port/win32" "${POSTGRESQL_DIR}/include/server" "${POSTGRESQL_DIR}/include")
「ライブラリーの検索パスを追加する」は次のようにします。
link_directories( "${POSTGRESQL_DIR}/lib")
「postgres.lib
をリンクする」は次のようにします。
target_link_libraries("${LIBRARY_NAME}" "postgres.lib")
これで必要な設定が完了しました。簡単ですね。後はインストール先の指定とパッケージ作成用の設定だけです。
インストール先の指定は次のようになります。
install(TARGETS "${LIBRARY_NAME}" DESTINATION "${EXTENSION_DIR}") install(FILES "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.control" DESTINATION "${EXTENSION_DATA_DIR}") install(FILES "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.sql" RENAME "${PGRN_PROJECT_ID}--${VERSION_FULL}.sql" DESTINATION "${PGRN_EXTENSION_DATA_DIR}")
パッケージ作成用の設定は次の通りです。すでに設定した値を使っているだけです。
set(CPACK_GENERATOR "ZIP") set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}") set(CPACK_PACKAGE_VENDOR "${VENDOR}") if(CMAKE_CL_64) set(PACKAGE_SYSTEM_NAME "x64") else() set(PACKAGE_SYSTEM_NAME "x86") endif() set(CPACK_PACKAGE_FILE_NAME "${PROJECT_ID}-${VERSION_FULL}-postgresql-${POSTGRESQL_VERSION}-${PACKAGE_SYSTEM_NAME}") include(CPack)
まとめると次の通りです。
cmake_minimum_required(VERSION 3.0.0) set(PROJECT_NAME "拡張機能名") # 例: "PGroonga" set(PROJECT_ID "拡張機能のID") # 例: "pgroonga" set(VENDOR "拡張機能の開発者") # 例: "The PGroonga Project" set(VERSION_MAJOR "拡張機能のメジャーバージョン") # 例: "0" set(VERSION_MINOR "拡張機能のマイナーバージョン") # 例: "5" set(VERSION_PATCH "拡張機能のパッチバージョン") # 例: "0" # ↑は.controlから抽出することもできる # 方法は後述するPGroongaの例を参照すること set(VERSION_FULL "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") project("${PROJECT_ID}") # ↓はユーザーが指定した「%PostgreSQLをインストールしたフォルダー%」になる set(POSTGRESQL_DIR "${CMAKE_INSTALL_PREFIX}" CACHE PATH "PostgreSQL binary directory") # ↓はパッケージを作成するときだけ必要 set(POSTGRESQL_VERSION "unknown" CACHE STRING "PostgreSQL version") set(LIBRARY_NAME "lib${PROJECT_ID}") set(EXTENSION_DIR "lib") set(EXTENSION_DATA_DIR "share/extension") set(DOCUMENT_DIR "share/${PROJECT_ID}") set(SOURCES "ソースコード1.c" "ソースコード2.c" "...") add_library("${LIBRARY_NAME}" SHARED ${SOURCES}) set_target_properties("${LIBRARY_NAME}" PROPERTIES OUTPUT_NAME "${PROJECT_ID}") set_source_files_properties(${SOURCES} PROPERTIES COMPILE_FLAGS "/EHsc") include_directories( "${POSTGRESQL_DIR}/include/server/port/win32_msvc" "${POSTGRESQL_DIR}/include/server/port/win32" "${POSTGRESQL_DIR}/include/server" "${POSTGRESQL_DIR}/include") link_directories( "${POSTGRESQL_DIR}/lib") target_link_libraries("${LIBRARY_NAME}" "postgres.lib") install(TARGETS "${LIBRARY_NAME}" DESTINATION "${EXTENSION_DIR}") install(FILES "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.control" DESTINATION "${EXTENSION_DATA_DIR}") install(FILES "${PROJECT_SOURCE_DIR}/${PROJECT_ID}.sql" RENAME "${PGRN_PROJECT_ID}--${VERSION_FULL}.sql" DESTINATION "${PGRN_EXTENSION_DATA_DIR}") set(CPACK_GENERATOR "ZIP") set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF) set(CPACK_PACKAGE_VERSION_MAJOR "${VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}") set(CPACK_PACKAGE_VENDOR "${VENDOR}") if(CMAKE_CL_64) set(PACKAGE_SYSTEM_NAME "x64") else() set(PACKAGE_SYSTEM_NAME "x86") endif() set(CPACK_PACKAGE_FILE_NAME "${PROJECT_ID}-${VERSION_FULL}-postgresql-${POSTGRESQL_VERSION}-${PACKAGE_SYSTEM_NAME}") include(CPack)
実際に使われているCMakeの設定ファイルはPGroongaのCMakeLists.txtを参考にするとよいでしょう。
また、実際に作成したパッケージはhttp://packages.groonga.org/windows/pgroonga/以下にあります。こちらもあわせて参考にしてください。
公式のWindows版PostgreSQLパッケージ用の拡張機能のビルドシステムの作り方を紹介しました。ここで紹介した方法はCMakeを使っています。Visual StudioでビルドしなければいけないときにCMakeは便利なので、そんなときはCMakeを思い出してみてください。
*1 拡張機能のメタデータを書いた.control
ファイルと拡張機能のインストール方法を書いた.sql
ファイル。
*2 なんの略かわかりませんが、PostgreSQL Extension Systemの略な気はします。
*3 ただし、.deb
や.rpm
などパッケージを作る仕組みは提供していません。それらは自分で作る必要があります。PGroongaが使っている仕組みが参考になるかもしれません。
*4 EnterpriseDBが提供していますが、これは公式のパッケージなんですよ…ね?
*5 PGXSの中身を見ると使えるように見えます。
*6 ソースを見ると使えるように見えます。
*7 PostgreSQL自体のビルドシステムもこのアプローチのように見えます。
要約:6月6日(土)に学生向けリーダブルコード勉強会を開催する予定なので、興味のある学生の人はイベントページから応募してください。興味のありそうな学生を知っている人は教えてあげてください。締め切りは6月1日(月)です。
去年も開催した学生向けリーダブルコード勉強会を今年も開催します。(去年は参加者多数につき2回開催しました。1回目の開催レポート、2回目の開催レポート。)今年も勉強会の講演者・トレーナーをリーダブルコードの解説を書いた須藤が務めます。
リーダブルコードはとても内容が評価されている本です。リーダブルコードが発売されたのは3年前ですが、今でも新しく読む人が増えています。例えば、2014年のジュンク堂書店池袋本店でのコンピュータ書売上冊数ランキングで1位*1になったり、Amazonのクラウドエンジニアが選ぶ技術書35選でも一番最初に紹介されていたりします。学生のうちからこの本に書かれていることを理解し、実践していると、今後、プログラミングをする上で大きな力になるでしょう。
内容は去年と同じくリーダブルコードの解説に書いていることの体験です。解説では、本文に書いているリーダブルコードを書くための方法をどうやって実践するか、その方法を説明しています。つまり、学生がリーダブルコードに書いていることを単なる知識ではなく、実際に自分の技術や考え方として身につけるきっかけとなる内容です。
リーダブルコードを書くには読む人の視点を持っていることが重要です。リーダブルかどうかは読む人の視点での基準だからです。読む人の視点を持たずに書いているうちは、単に「想像して」リーダブルだろうコードを書いているだけです。読む人の視点を持っていれば、「事実に裏付けされた」リーダブルコードを書けます。
しかし、学生で読む人の視点を持っている人は少ないです。仕事では複数の人が同じソフトウェアを開発することが多く、また、リリースしたあとに継続して開発を続けることも多いので、コードを読む機会が増え、読む人の視点が身につきやすいです。一方、学生は自分ひとりで開発し、作って動かして研究成果が得られたらコードに触れることはない、というケースがほとんどです。そうすると、自分が書いたにしろ他の人が書いたにしろ、コードを読む機会がほとんどなく、読む人の視点を身につけることができません。
今回の勉強会ではこの「読む人の視点」の体験を重視します。具体的には次の流れで勉強会を進めることで、「読む人の視点」を体験します。
「コードを読む」というと「コードレビュー」というイメージが根強いので、どうしても「悪いところはないか?」という視点で読んでしまいがちです。そうではなく、「コードから学ぶ」という視点で読めるようになると、コードの理解も速くなりますし、読んでいる人の成長スピードもあがります。日々新しい技術が生まれ、学ぶことが増えている昨今、コードから学べるようになると重宝されることでしょう。
参加する学生の人には「読む人の視点」、もっと言うと「悪いところはないか?」ではなく「コードから学ぶ」という「読む人の視点」を身につけ、コードを読み、よい書き方を身につけ、それを自分が書くコードにも活かす、という習慣を体験してもらいたいです。
去年はメンターとして企業で活躍中のトップエンジニアが学生をサポートしました。具体的には、クックパッドのまきもとさん、楽天の川原さん、DeNAのたなべさん、クリアコードの結城さん、沖元さんがサポートしました。学生でなくてもサポートして欲しいですよね。
今年は去年よりもたくさんのトップエンジニアが学生をサポートする予定です*3。現在スポンサーになることが決定している企業は次の通りです。調整中の企業もあるのでまだ増える見込みです。
これらの企業からトップエンジニアがメンターとして参加し、学生さんをサポートしてくれます。例えば、クラウドワークスからはCTOの大場さんがメンターとして参加します。他にもメンターが決まったら随時イベントページに載るはずです。
6月6日(土)に開催する学生向けリーダブルコード勉強会を紹介しました。リーダブルなコードを書くために大事な「読む人の視点をもつこと」を体験できる勉強会です。興味のある学生の人はイベントページから応募してください。興味のありそうな学生を知っている人はこの勉強会を教えてあげてください。あるいは、成長させたい学生を知っている人はこの勉強会への参加を勧めてください。
なお、締め切りは6月1日(月)です。
PostgreSQL 9.4.1の標準機能で日本語全文検索をする場合、LIKEを使うしかありません。LIKE
には次の問題があります。
日本語文字列の正規化機能には、例えば、半角カタカナ*2と通常のカタカナの違いを吸収する機能があります。違いを吸収すると、「パパ」(通常のカタカナ)で検索すると「パパ」(半角カタカナ)もマッチします。
正規化し過ぎると誤検出が増える可能性が増えるのでなんでも正規化すればよいというものではありません。しかし、半角カタカナと通常のカタカナの同一視のように多くの場合で有用な正規化はあります。
標準機能でなければ日本語全文検索には次の選択肢があります。
pg_bigmは高速に検索できますが、ヒット数が多いとき・検索対象の文字列が長いときに性能が落ちやすいです*3。また、日本語文字列の正規化機能はありません。
PGroongaはGroonga(ぐるんが)という全文検索エンジンをバックエンドに使っているため、高速に検索できますし日本語文字列の正規化機能もあります。また、bigram以外にもtrigramやMeCabを使ったトークナイズ方式を選べたり、pg_bigmよりも更新性能が高いという特徴があります*4。しかし、PostgreSQLのレプリケーション機能を使えないという欠点があります。
日本語全文検索機能だけで考えるとPGroongaの方が充実していますが、可用性という面ではpg_bigmの方が便利です。それは、pg_bigmはPostgreSQL標準のストリーミングレプリケーション機能を使ってレプリケーションできるからです。PGroongaはPostgreSQL標準のストリーミングレプリケーション機能を使えないため*5、サーバーが落ちたときにバックアップサーバーにすぐに切り替える、ということができません*6。
そこで、pg_shardを使ったPGroongaのレプリケーションシステムの作り方を紹介します。PGroongaを使いたいけどレプリケーションがネックなんだよな。。。という人は参考にしてください。
pg_shardはシャーディング機能(大きなデータを複数のノードに分散)とレプリケーション機能(同じデータを複数のノードでコピー)を提供する拡張機能です。
開発しているのはCitus Dataで、PostgreSQL用のカラム指向のデータストアであるcstore_fdwも開発しています。
pg_shardのレプリケーション機能を使うことでPostgreSQL標準のストリーミングレプリケーションと同等のことを実現できます。
pg_shardとPGroongaを使ったレプリケーション対応の高速日本語全文検索可能なPostgreSQLクラスターの構築方法を説明します。CentOS 6向けです。
クラスターには次のノードがあるとします。
役割 | ホスト名 | IPアドレス |
---|---|---|
マスターノード | master1 | 192.168.1.67 |
ワーカーノード1 | worker1 | 192.168.1.68 |
ワーカーノード2 | worker2 | 192.168.1.69 |
マスターノードが落ちた時のために、マスターノードはPostgreSQL標準のレプリケーション機能を使ってバックアップサーバーを構築しますが、それはPostgreSQLの標準的な方法なのでここでは省略します。
それでは、まずはワーカーノードをセットアップし、その後マスターノードをセットアップします。
ワーカーノードのセットアップ方法を説明します。ワーカーノードは2つありますが、どちらも同じ手順です。
PostgreSQLをパッケージでインストールします。
% 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 yum install -y postgresql94-server % sudo -H /sbin/service postgresql-9.4 initdb % sudo -H /sbin/chkconfig postgresql-9.4 on
外部からの接続を受けつけるようにします。
postgresql.confではlisten_address
に*
を設定します*7。
/var/lib/pgsql/9.4/data/postgresql.conf:
listen_addresses = '*'
pg_hba.confでは192.168.1.0/24
からの接続はすべて受けつけるようにします。そのため、このネットワークは信頼できるノードだけがいる状態にしてください*8。
/var/lib/pgsql/9.4/data/pg_hba.conf:
host all all 192.168.1.0/24 trust
PGroongaをパッケージでインストールします。
% sudo -H rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm % sudo -H yum install -y postgresql94-pgroonga
pg_shardはビルドします。
% wget https://github.com/citusdata/pg_shard/archive/v1.1.0.tar.gz % tar xvf v1.1.0 % cd pg_shard-1.1.0 % sudo -H yum install -y postgresql94-devel gcc % PATH=/usr/pgsql-9.4/bin:$PATH make % sudo -H PATH=/usr/pgsql-9.4/bin:$PATH make install
pg_shard用の設定をします。
postgresql.confではshared_preload_libraries
にpg_shard
を設定します。
/var/lib/pgsql/9.4/data/postgresql.conf:
shared_preload_libraries = 'pg_shard' # (change requires restart)
PostgreSQLを起動します。
% sudo -H /sbin/service postgresql-9.4 start
データベースを作成します。今回はpgroonga_replicationという名前のデータベースにします。
% sudo -u postgres -H createdb pgroonga_replication
PGroongaをインストールします。
% sudo -u postgres -H psql pgroonga_replication --command 'CREATE EXTENSION pgroonga'
これでワーカーノードのセットアップは完了です。CREATE EXTENSION pg_shard
はする必要はありません。自動で実行されます。
マスターノードのセットアップ方法を説明します。途中まではワーカーノードのセットアップ方法と同じです。
PostgreSQLをパッケージでインストールします。
% 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 yum install -y postgresql94-server % sudo -H /sbin/service postgresql-9.4 initdb % sudo -H /sbin/chkconfig postgresql-9.4 on
PGroongaをパッケージでインストールします。
% sudo -H rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm % sudo -H yum install -y postgresql94-pgroonga
pg_shardはビルドします。
% wget https://github.com/citusdata/pg_shard/archive/v1.1.0.tar.gz % tar xvf v1.1.0 % cd pg_shard-1.1.0 % sudo -H yum install -y postgresql94-devel gcc % PATH=/usr/pgsql-9.4/bin:$PATH make % sudo -H PATH=/usr/pgsql-9.4/bin:$PATH make install
pg_shard用の設定をします。
postgresql.confではshared_preload_libraries
にpg_shard
を設定します。
/var/lib/pgsql/9.4/data/postgresql.conf:
shared_preload_libraries = 'pg_shard' # (change requires restart)
ここまではワーカーノードのセットアップ手順と同じです。ここからがマスターノード固有の手順です。
pg_worker_list.confにはワーカーの情報を設定します。今はワーカーは192.168.1.68
と192.168.1.69
で動いている想定なので次のようにします。
/var/lib/pgsql/9.4/data/pg_worker_list.conf:
192.168.1.68 5432 192.168.1.69 5432
PostgreSQLを起動します。
% sudo -H /sbin/service postgresql-9.4 start
ここまではアプリケーションに関係ない共通の設定です。これからはアプリケーション毎の設定です。
ここではサンプルテーブル・データとしてPGroongaのドキュメントに載っている例を用います。
まず、データベースを作成し、PGroongaを初期化します。
% cd /tmp % sudo -u postgres -H createdb pgroonga_replication % sudo -u postgres -H psql pgroonga_replication pgroonga_replication=# CREATE EXTENSION pgroonga;
テーブルとインデックスを定義します。
pgroonga_replication=# CREATE TABLE memos ( id integer PRIMARY KEY, content text ); pgroonga_replication=# CREATE INDEX pgroonga_content_index ON memos USING pgroonga (content);
データを投入する前にpg_shardの設定をします。
まずpg_shardをインストールします。
pgroonga_replication=# CREATE EXTENSION pg_shard;
次にデータを分散するために使うキーを指定します。今回はプライマリーキーを指定しています。今回はレプリケーション機能だけ使うのであまり意味はありません。
pgroonga_replication=# SELECT master_create_distributed_table('memos', 'id');
続いてシャード数とレプリケーション数を指定します。今回はレプリケーション機能だけ使うので、シャード数1(データ分散なし)、レプリケーション数2にします。
pgroonga_replication=# SELECT master_create_worker_shards('memos', 1, 2);
これでマスターノードの設定は完了です。
ワーカーノードとマスターノードの設定が完了したので動作を確認します。
SQLはマスターノードに対してのみ実行します。ワーカーノードは直接触りません。以降のSQLはすべてマスターノードで実行します。
データを投入します。
1 2 3 4 |
INSERT INTO memos VALUES (1, 'PostgreSQLはリレーショナル・データベース管理システムです。'); INSERT INTO memos VALUES (2, 'Groongaは日本語対応の高速な全文検索エンジンです。'); INSERT INTO memos VALUES (3, 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。'); INSERT INTO memos VALUES (4, 'groongaコマンドがあります。'); |
日本語全文検索をします。%%
も@@
も動きます。
1 2 3 4 5 6 7 8 9 10 11 |
pgroonga_replication=# SELECT * FROM memos WHERE content %% '全文検索'; # id | content # ----+--------------------------------------------------- # 2 | Groongaは日本語対応の高速な全文検索エンジンです。 # (1 行) pgroonga_replication=# SELECT * FROM memos WHERE content @@ 'PGroonga OR PostgreSQL'; # id | content # ----+--------------------------------------------------------------------------- # 3 | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。 # 1 | PostgreSQLはリレーショナル・データベース管理システムです。 # (2 行) |
念のため、ワーカーノードにデータが入っているか直接Groongaを使って確認します。
以下はそれぞれのワーカーノードで実行して確認しています。
groonga
コマンドをインストールします。
% sudo -H yum install -y groonga
PGroongaで作ったデータベースをダンプします。
% database_oid=$(sudo -u postgres -H psql --command "SELECT datid FROM pg_stat_database WHERE datname = 'pgroonga_replication'" | head -3 | tail -1 | sed -e 's/ *//g') % sudo -u postgres -H groonga /var/lib/pgsql/9.4/data/base/${database_oid}/pgrn dump --dump_schema no --dump_indexes no load --table Sources16552 [ ["_key","content"], [1,"PostgreSQLはリレーショナル・データベース管理システムです。"], [2,"Groongaは日本語対応の高速な全文検索エンジンです。"], [3,"PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。"], [4,"groongaコマンドがあります。"] ]
データが入っています。もう1つのワーカーノードで実行してもデータが入っていることを確認できます。
PostgreSQL標準のストリーミングレプリケーションのようにレプリケーションできていることが確認できました。
PGroongaはPostgreSQLで使える高速な日本語全文検索機能を提供しますが、レプリケーションができないことがネックです。ここではpg_shardと組み合わせることでPGroongaでもレプリケーションする方法を紹介しました。
pg_shardにはALTER TABLE
ができない、複数のシャードにまたがるトランザクションをサポートしていない、などいくつか制限があります。詳細はpg_shardのREADMEとpg_shardのFAQを確認してください。
*1 LIKE
の問題というかPostgreSQLのcollation機能がそのような機能を提供していないからです。
*2 Unicodeの文字の名前でいうとHALFWIDTHとついているもの。
*3 Recheck機能のため。
*4 性能についてはPostgreSQLの日本語対応全文検索モジュールpg_bigmとPGroongaを検証してみた - CreateField Blogを参考にしてください。
*5 PostgreSQLの制限のため。
*6 データはレプリケーションされているので、そのデータのPGroonga用のインデックスを作成するとサービスを提供できるようになります。バックアップサーバーに切り替えるまでに「PGroonga用のインデックスを構築する時間」が必要になります。
*7 192.168.1.68
のように内部用のIPアドレスの方がベターです。
*8 pg_shardはパスワードでの認証をサポートしていません。Pull Requestを送ればサポートが追加されるかもしれません。
PostgreSQLアンカンファレンス@東京(2015/5/30)でPostgreSQLの日本語全文検索まわりについて紹介しようかとたくらんでいます。しかし、現時点(2015-05-25)でキャンセル待ちで、当日参加できないかもしれないので紹介しようと用意している内容をここにまとめます。
この資料の目的は、PostgreSQLで使える次の3つの方法の特性を紹介し、ユーザーが適切な方法を選択するための材料を提供することです。
LIKE
LIKE
のメリット・デメリットは次の通りです。
ユーザーがLIKE
を使うかどうかの判断基準は「十分速いかどうか」(= 「データが少ないかどうか」)です。では、どのくらいなら「十分速い」のでしょうか。
「十分速い」かどうかは「検索対象のデータでの計測結果」と「要件」で判断できます。どちらもケースバイケースですが、参考情報としての計測結果なら示すことができます。
参考情報としてpg_bigmでいろんなデータを日本語検索してみよう!のLIKE
の結果を使ってみましょう。この記事では次の3つのデータを検索しています。
それぞれみていきましょう。
まずは「青空文庫の書籍一覧データ」です。
このデータの特性と検索速度は次の通りです。
件数 | 1レコードあたりのバイト数 | 検索速度 |
---|---|---|
11,818件 | 17バイト | 6.673ms |
6msで結果が返ってくるのであれば多くの要件で「十分速い」と言えるでしょう。つまり、このデータでは日本語全文検索の方法としてLIKE
はアリということです。
次のデータは「住所データ」です。
このデータの特性と検索速度は次の通りです。
件数 | 1レコードあたりのバイト数 | 検索速度 |
---|---|---|
147,769件 | 14バイト | 70.684ms |
70msで結果が返ってくるのであれば多くの要件で「十分速い」と言えるでしょう。つまり、このデータでも日本語全文検索の方法としてLIKE
はアリということです。
最後のデータは「日本版Wikipediaのタイトル一覧データ」です。
このデータの特性と検索速度は次の通りです。
件数 | 1レコードあたりのバイト数 | 検索速度 |
---|---|---|
2,461,588件 | 20バイト | 943.450ms |
1秒くらいで結果が返ってくるのでは、「十分速い」というのは要件次第でしょう。つまり、この規模のデータでは日本語全文検索の方法としてLIKE
は使えるかもしれないし使えないかもしれない、といったところです。
これまでの結果をまとめると次の通りです。LIKE
で十分かどうかを判断する場合は、実際のデータの傾向と検索時間を材料として検討します。
件数 | 1レコードあたりのバイト数 | 検索速度 |
---|---|---|
11,818件 | 17バイト | 6.673ms |
147,769件 | 14バイト | 70.684ms |
2,461,588件 | 20バイト | 943.450ms |
では、LIKE
では十分速くない場合はどうしたらよいでしょうか。次のどちらかの方法を選びます。
pg_bigmのメリット・デメリットは次の通りです。
pg_bigmはデータ量が多くても高速ですが、ヒット数が多いほど遅くなる特性があります。pg_bigmが十分速いかどうかを判断するためにも、LIKE
と同様に「検索対象のデータでの計測結果」と「要件」が必要です。ただし、LIKE
とは注目するポイントが異なります。
それでは、検索結果例を見ながら注目するポイントを確認しましょう。なお、ここで紹介する検索結果例はPGroongaとpg_bigmのベンチマーク結果 · Issue #2 · groonga/wikipedia-searchにあります。手順もまとまっているので誰でも追試することができます。 ここで使うデータは日本語版Wikipediaの本文です。このデータの特性は次の通りです。
件数 | 1レコードあたりのバイト数 |
---|---|
1,846,514件 | 3777バイト |
注目するポイントの1つ目はインデックス作成時間です。元データのロード時間とインデックス作成時間は次の通りです。
元データのロード時間 | インデックス作成時間 |
---|---|
16分31秒 | 5時間56分15秒 |
約16分でロードできるデータのインデックス作成に約6時間かかるのは十分速いでしょうか。それとも遅いでしょうか。要件と照らしあわせて検討します。
なお、この時間はインデックス全体を1から作成する時間です。常に少量ずつ更新するという要件であればこの時間はあまり関係ありません。そのような要件の場合は、少量のデータの更新が滞らない(更新処理が溜まっていかない)くらいの速度がでていれば十分速いと判断できます。
注目するポイントの2つ目はヒット数と検索時間の関係です。
検索語 | ヒット数 | 検索時間 |
---|---|---|
「PostgreSQL」または「MySQL」 | 361 | 0.107s |
データベース | 17168 | 1.224s |
テレビアニメ | 22885 | 2.472s |
日本 | 625792 | 0.556s |
pg_bigmはヒット数が多くなるほど遅くなります。数百件ヒットのときは0.1秒ですが、1万7千件のときは1秒ちょい、2万2千件のときは約2.5秒となりました。なお、このデータではヒット数が増えるほど遅くなる傾向がよりわかりやすいデータになっています。というのは、このデータは1レコードあたりのデータが大きいからです。pg_bigmは1レコードあたりのデータが大きいと遅くなりやすい特性があります。
なお、検索語が2文字以下の場合はヒット数が多くても遅くなりにくいという特性があります。例では62万件ヒットしても0.5秒で結果を返しています。
このような特性があるpg_bigmなので、データによっては遅いと判断する場面も十分速いと判断する場面もあるでしょう。
LIKE
では遅い場合、pg_bigm以外の選択肢はPGroongaです。
PGroongaのメリット・デメリットは次の通りです。
PGroongaはデータ量が多くてもヒット数が多くても速度が落ちにくく、インデックス作成も高速ですが、PostgreSQLとの連携度合いはpg_bigmほどではありません。たとえば、pg_bigmはPostgreSQL標準のストリーミングレプリケーション機能を使えますが、PGroongaは使えません。これはPostgreSQL側が連携する機能を提供していないことが原因です。今後連携できる機能が提供される見込みですが、現時点で連携できないことは事実です。
PGroongaを選ぶかどうかの基準は他の方法では遅いケースがPGroongaだと速いかどうかです。そのためには同じデータでpg_bigmと比較する必要があります。
それでは、pg_bigmと同じデータを使った場合のPGroongaの速度を確認しましょう。
まずはインデックス作成時間です。
元データのロード時間 | 16分31秒 |
---|---|
PGroongaのインデックス作成時間 | 25分37秒 |
pg_bigmのインデックス作成時間 | 5時間56分15秒 |
参照しやすいようにpg_bigmのインデックス作成時間も再掲しています。
PGroongaは元データのロード時間の2倍いかないくらいの時間でインデックスを作成しています。pg_bigmと比べると1/14の時間でインデックスを構築できています。
ただし、インデックスのために使用するディスクサイズは大きいです。
元データロード直後のデータベースサイズ | 4.0GiB |
---|---|
PGroongaの使用ディスクサイズ | 14.0GiB | pg_bigmの使用ディスクサイズ | 3.6GiB |
ディスクサイズが小さい環境で動かす場合は問題になるかもしれません。
次は検索時間を確認しましょう。
検索語 | ヒット数 | PGroongaの検索時間 | pg_bigmの検索時間 |
---|---|---|---|
「PostgreSQL」または「MySQL」 | 368 | 0.030s | 0.107s |
データベース | 17172 | 0.121s | 1.224s |
テレビアニメ | 22885 | 0.179s | 2.472s |
日本 | 625792 | 0.646s | 0.556s |
PGroongaはpg_bigmほどヒット数の多さに影響をうけていません。62万件ヒットする場合でも0.6秒ちょいで結果を返しています。PGroongaは全体的に高速ですが、検索語が2文字以下の場合はpg_bigmの方が高速です。
PostgreSQLとの連携度合いよりも性能が大事な要件な場合で、pg_bigmでは性能が落ちやすい規模のデータではPGroongaが選択肢になるでしょう。
PostgreSQLで日本語全文検索の方法として次の3つの方法を紹介しました。
LIKE
データが少ないならLIKE
で十分です。要件次第ですが、1レコード数十バイトの小さなデータなら百万件くらいまでいけるかもしれません。
データが多いならpg_bigmかPGroongaを選びます。
次のような場合はpg_bigmがよいでしょう。
pg_bigmで次のような問題があるならPGroongaがよいでしょう。
ちなみに、PGroongaでもレプリケーションをする方法はあります。興味のある方はpg_shardとPGroongaを使ったレプリケーション対応の高速日本語全文検索可能なPostgreSQLクラスターの作り方を参考にしてください。
最後に、PostgreSQLの日本語全文検索に興味のある方にお願いです。この説明の中のpg_bigmとPGroongaの性能確認で参照したベンチマークをあなたの環境でも動かして結果を教えてもらえないでしょうか?同じ傾向があるか確認したいのです。ベンチマークの実行方法や必要な環境などの詳細は協力者募集:PGroongaとpg_bigmのベンチマークを実行を参照してください。