include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
+
+installcheck-bigm:
+ $(pg_regress_installcheck) $(REGRESS_OPTS) pg_bigm
--- /dev/null
+ホーム ダウンロード ドキュメント\r
+ コミュニティ 開発 ドキュメント\r
+1.概要 2.動作確認環境 3.インストール\r
+4.アンインストール 5.提供関数 6.パラメータ\r
+概要 Ludia functionsは、文字列の正規化関数とスニペット作成関数を提供するモジュールです。それらの関数は全文検索モジュールLudiaが提供していたものと同じです。 Ludia functionsは、それらの関数をPostgreSQL9.1以降で利用可能にしています。 Ludia functionsプロジェクトでは以下2つのモジュールを提供します。\r
+モジュール名 概要 ソースアーカイブファイル名\r
+Ludia functions 文字列の正規化関数とスニペット作成関数を提供するモジュール ludia_funcs-YYYYMMDD.tar.gz senna-1.1.2-fast 組み込み型全文検索エンジンSennaの性能改善版 senna-1.1.2-fast-YYYYMMDD.tar.gz ソースアーカイブファイル名のYYYYMMDDの部分は、実際にはそのファイルがリリースされた年月日になります。例えば、2013年4月5日リリースのファイルでは、YYYYMMDDは20130405です。\r
+各提供モジュールのライセンスはLGPLv2.1です。 Ludia functionsは、提供モジュールの一つである性能改善版のSennaと組み合わせて使いうことで、Ludia同様に文字列の正規化やスニペット作成を行います。 "Ludia functionsは、様々な形式のファイルからテキストを抽出する関数も提供します。この関数を利用するには、商用ソフトウェアのTextPorterを別途購入する必要があります。 (TextPorter Ver.5 Copyright(c) 1999- Antenna House, Inc.)"\r
+動作確認環境 Ludia functionsは、以下の環境で動作確認しています。 カテゴリ\r
+モジュール名 OS Red Hat Enterprise Linux 6.1 x86_64 DMBMS PostgresSQL9.1 \r
+Senna senna-1.1.2-fast Ludia functionsは、PostgreSQL9.1のみに対応しています。 9.0以前には未対応です。 9.2以降には対応していると思われますが、動作確認していません。 Ludia functionsは、オリジナルのSenna1.1.2以降とも組み合わせ可能だと思われますが、動作確認していません。 senna-1.1.2-fastを使う場合、Ludia functionsの登録先のデータベースでは、エンコーディングはUTF-8でなければなりません。\r
+インストール PostgreSQLのインストール PostgreSQLのオフィシャルサイトからバージョン9.1.X(バージョン番号の下一桁Xは、実際の数字に置き換えてください)のソースアーカイブファイル(postgresql-9.1.X.tar.gz)をダウンロードし、ビルドとインストールを行います。\r
+$ tar zxf postgresql-9.1.X.tar.gz $ cd postgresql-9.1.X $ ./configure --prefix=/opt/pgsql-9.1.X\r
+$ make $ su # make install\r
+# exit ?--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/local/pgsqlです。このオプション指定は必須ではありません。 上記手順ではソースコードからPostgreSQLをインストールしています。しかし、RPMなどの他の手順でPostgreSQLをインストールしてもLudia functionsは利用可能です。 RPMインストールのPostgreSQLでLudia functionsを利用するには、postgresql-develパッケージをインストールしなければならないことに注意してください。\r
+Sennaのインストール ここからsenna-1.1.2-fastのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 Sennaのmakeには長時間かかることに注意してください。 $ tar zxf senna-1.1.2-fast-YYYYMMDD.tar.gz\r
+$ cd senna-1.1.2-fast-YYYYMMDD $ ./configure --prefix=/opt/senna-1.1.2-fast --without-mecab $ make\r
+$ su # make install # exit\r
+?--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/localです。このオプション指定は必須ではありません。 ?--without-mecab : mecabモジュールを使用しないことを指定します。このオプション指定は必須です。 Ludia functionsのインストール\r
+ここからLudia functionsのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 $ tar zxf ludia_funcs-YYYYMMDD.tar.gz $ cd ludia_funcs-YYYYMMDD\r
+$ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg $ su # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg install\r
+# exit ?USE_PGXS : PostgreSQL関連モジュールをコンパイルするときのオマジナイです。1の指定が必須です。 ?PG_CONFIG : pg_configコマンド(PostgreSQLインストール先のbinディレクトリに存在)のパスを指定します。pg_configにPATHが通っているのであれば、このオプション指定は不要です。\r
+?SENNA_CFG : senna-cfgコマンド(Sennaインストール先のbinディレクトリに存在)のパスを指定します。senna-cfgにPATHが通っているのであれば、このオプション指定は不要です。 Ludia functionsの登録 データベースクラスタの作成後、postgresql.confを編集、PostgreSQLを起動し、Ludia functionsをデータベースに登録します。\r
+$ initdb -D $PGDATA --locale=C --encoding=UTF8 $ vi $PGDATA/postgresql.conf shared_preload_libraries = 'ludia_funcs'\r
+custom_variable_classes = 'ludia_funcs' $ pg_ctl -D $PGDATA start $ psql -d <データベース名>\r
+=# CREATE EXTENSION ludia_funcs; =# \dx ludia_funcs List of installed extensions\r
+ Name | Version | Schema | Description -------------+---------+--------+----------------- ludia_funcs | 1.0 | public | ludia functions\r
+(1 row) ?$PGDATAは、データベースクラスタのパスを決めて、そのパスで置き換えてください。 ?senna-1.1.2-fastを使う場合、Ludia functionsの登録先のデータベースでは、エンコーディングはUTF-8でなければなりません。\r
+?postgresql.confで、shared_preload_librariesとcustom_variable_classesにludia_funcsを設定するのは必須です。 ?PostgreSQL9.2以降ではcustom_variable_classesは存在しません。設定が必要なのはshared_preload_librariesだけです。 ?Ludia functionsの登録には、CREATE EXTENSIONを使います。 CREATE EXTENSIONはデータベース単位でモジュールを登録するため、Ludia functionsを利用したいデータベースすべてにおいて登録が必要です。 Ludia functionsのインストールは以上で終わりです。\r
+アンインストール Ludia functionsの削除 Ludia functionsについて、データベースからの登録解除とアンインストールを行います。\r
+$ psql -d <データベース名> =# DROP EXTENSION ludia_funcs CASCADE; =# \q\r
+$ pg_ctl -D $PGDATA stop $ su # cd <ludia_funcsのソースディレクトリ>\r
+# make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg uninstall # exit ?Ludia functionsを登録したすべてのデータベースで登録解除する必要があります。\r
+?Ludia functionsに依存するDBオブジェクトを削除する必要があるため、DROP EXTENSIONにはCASCADEを指定します。 postgresql.confの設定削除 postgresql.confの以下の設定を削除します。\r
+?shared_preload_libraries ?custom_variable_classes ?ludia_funcs.* (ludia_funcs.から名前が始まるパラメータ)\r
+Sennaのアンインストール senna-1.1.2-fastのソースディレクトリでアンインストールを行います。 $ su\r
+# cd <senna-1.1.2-fastのソースディレクトリ> # make uninstall # exit\r
+提供関数 pgs2norm pgs2normは、文字列正規化ルール(NFKCの正規化形式)に則って、文字列(引数1)を正規化する関数です。\r
+?引数1(text) - 正規化する文字列 ?戻り値(text) - 引数1を正規化した文字列 引数1がNULLの場合、戻り値はNULLです。\r
+NFKCの正規化では、例えば、以下のように文字列を変換します。 ?半角カタカナを全角カタカナに変換 ?アイウエオ → アイウエオ ?大文字英字を小文字英字に変換 ?ABCDE → abcde\r
+?全角英数字を半角英数字に変換 ?AbCdE123 → abcde123 ?環境依存文字を変換 ?㌢㍻㊨⑤Ⅷ㈲ → センチ平成右5viii(有) 実行例\r
+=# SELECT pgs2norm('いロハAbCd12③Ⅳ㈱'); pgs2norm いロハabcd123iv(株)\r
+pgs2normは、引数と戻り値の文字列をメモリ上にキャッシュします。そして、pgs2normの次回実行時に引数の文字列がキャッシュされているものと同じであれば、正規化処理を行わず、 キャッシュされている戻り値を直接返却することで、処理を高速化します。 pgs2normは、引数と戻り値をキャッシュする際、前回までのキャッシュを破棄します。つまり、キャッシュできる引数と戻り値は直前実行分の一組だけです。\r
+キャッシュはセッション単位で行われます。他セッションのキャッシュを、別セッションから実行されたpgs2normで使うことはできません。 pgs2normのキャッシュサイズの上限は、パラメータludia_funcs.norm_cache_limitで指定できます。 pgs2snippet1\r
+pgs2snippet1は、文字列(引数8)からキーワード(引数7)のスニペット(KWIC)を作成する関数です。 ?引数1(integer) - スニペット作成時に正規化するかどうか(する: 1、しない: 0) ?引数2(integer) - 作成するスニペットの最大長(バイト単位で指定)\r
+?引数3(integer) - 作成するスニペットの数の上限 ?引数4(text) - スニペット作成時にキーワードの前に付ける文字列 ?引数5(text) - スニペット作成時にキーワードの後ろに付ける文字列\r
+?引数6(integer) - HTMLの特殊文字をエスケープするかどうか(する: -1、しない: 0) ?引数7(text) - スニペット作成に使うキーワード ?引数8(text) - スニペットの作成元となる文字列\r
+?戻り値(text) - キーワード(引数7)を使って文字列(引数8)から作成したスニペット文字列 NULLの引数がある場合、戻り値はNULLです。 実行例\r
+"=# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'PostgreSQL', '最近、PostgreSQLの利用者が増えています。');" pgs2snippet1 最近、★PostgreSQL★の利用者\r
+(1 row) "pgs2snippet1では、キーワード(引数7)に複数の文字列を指定できます。複数指定するには、各文字列を""(半角ダブルクォート)で囲み、それらを+(半角プラス)でつなげます。" 実行例\r
+"=# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '""PostgreSQL""+""HINT""', 'pg_hint_planは、PostgreSQLでHINT句を使えるようにするツールです。');" pgs2snippet1 ★hint★_planは、★PostgreSQL★で★HINT★\r
+(1 row) ?この実行例では、正規化を行う指定(引数1が1)になっているため、キーワードHINTは、小文字のhintにもマッチします。 "キーワード内の""と\は、pgs2snippet1ではメタ文字(""は検索文字列の区切り文字、\はエスケープ文字)として解釈されます。 ""と\を文字そのものとして解釈させるには、それらを\でエスケープしなければなりません。"\r
+実行例 "=# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '""\""2-gram\""""', 'pg_bigmは、PostgreSQLで""2-gram""の全文検索を使えるようにするツールです。');" pgs2snippet1\r
+" ostgreSQLで★""2-gram""★の全文検" (1 row) このエスケープ処理は、ludia_funcs.escape_snippet_keywordを有効にすることでpgs2snippet1に任せることもできます。\r
+pgs2seninfo pgs2seninfoは、Ludia functionsが利用しているSennaのバージョン情報を表示する関数です。 ?戻り値1(text) - 利用しているSennaのバージョン番号\r
+?戻り値2(text) - 利用しているSennaのconfigureオプション 実行例 =# SELECT * FROM pgs2seninfo();\r
+ version | configure_options ---------------------------------+------------------------------------------------- 1.1.2 (last update: 2013.04.05) | '--without-mecab' '--prefix=/senna-1.1.2-fast/'\r
+パラメータ ludia_funcs.lastupdate ludia_funcs.last_updateは、Ludia functionsモジュールの最終更新日付を報告するパラメータです。このパラメータは読み取り専用です。 postgresql.confやSET文で設定値を変更することはできません。\r
+実行例 =# SHOW ludia_funcs.last_update ; ludia_funcs.last_update\r
+ 2013.04.05 (1 row) ludia_funcs.norm_cache_limit\r
+ludia_funcs.norm_cache_limitは、pgs2normが確保するキャッシュの上限サイズを指定するパラメータです。設定値はkB単位で指定します。設定値の範囲は -1 ~ 2TB-1B です。 設定値-1(デフォルト値)は、キャッシュサイズ上限としてパラメータwork_memの設定値を使うことを意味します。 設定値0は、キャッシュサイズの上限がない(常にキャッシュする)ことを意味します。\r
+このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。 ludia_funcs.escape_snippet_keyword "ludia_funcs.escape_snippet_keywordは、pgs2snippet1のキーワード(引数7)内の""(半角ダブルクォート)と\(半角バックスラッシュ)をエスケープするかどうか指定するパラメータです。デフォルト値はoffで、エスケープしません。"\r
+"キーワード内の""と\は、pgs2snippet1ではメタ文字(""は検索文字列の区切り文字、\はエスケープ文字)として解釈されます。 ""と\を文字そのものとして解釈させるには、それらを\でエスケープしなければなりません。このパラメータを有効にすると、pgs2snippet1は、文字として解釈させたい""と\を自動的にエスケープします。このようなエスケープ処理をクライアントアプリケーション側で実装済の場合は、このパラメータは無効で構いません。" このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。 pgs2snippet1に記述されている最後の実行例のSQLは、escape_snippet_keywordを使うことで、以下のように書き換えられます。\r
+実行例 =# SHOW ludia_funcs.escape_snippet_keyword ; ludia_funcs.escape_snippet_keyword\r
+ off (1 row) "=# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '""""2-gram""""', 'pg_bigmは、PostgreSQLで""2-gram""の全文検索を使えるようにするツールです。');"\r
+ pgs2snippet1 (null) (1 row)\r
+=# SET ludia_funcs.escape_snippet_keyword TO on; "=# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '""""2-gram""""', 'pg_bigmは、PostgreSQLで""2-gram""の全文検索を使えるようにするツールです。');" pgs2snippet1\r
+" ostgreSQLで★""2-gram""★の全文検" (1 row) "?キーワード内の先頭と末尾の""は必ずメタ文字(検索文字列の区切り文字)として解釈されます。"\r
--- /dev/null
+ホーム コミュニティ 1.概要 4.アンインストール 概要 モジュール名 Ludia functions 文字列の正規化関数とスニペット作成関数を提供するモジュール ludia_funcs-YYYYMMDD.tar.gz 各提供モジュールのライセンスはLGPLv2.1です。 動作確認環境 モジュール名 Senna senna-1.1.2-fast インストール $ tar zxf postgresql-9.1.X.tar.gz $ make # exit Sennaのインストール $ cd senna-1.1.2-fast-YYYYMMDD $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/localです。このオプション指定は必須ではありません。 ここからLudia functionsのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 $ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg # exit •SENNA_CFG : senna-cfgコマンド(Sennaインストール先のbinディレクトリに存在)のパスを指定します。senna-cfgにPATHが通っているのであれば、このオプション指定は不要です。 $ initdb -D $PGDATA --locale=C --encoding=UTF8 custom_variable_classes = 'ludia_funcs' =# CREATE EXTENSION ludia_funcs; Name | Version | Schema | Description (1 row) •postgresql.confで、shared_preload_librariesとcustom_variable_classesにludia_funcsを設定するのは必須です。 ◦PostgreSQL9.2以降ではcustom_variable_classesは存在しません。設定が必要なのはshared_preload_librariesだけです。 アンインストール $ psql -d <データベース名>\r
+ ダウンロード 開発 2.動作確認環境 5.提供関数 Ludia functionsは、文字列の正規化関数とスニペット作成関数を提供するモジュールです。それらの関数は全文検索モジュールLudiaが提供していたものと同じです。 Ludia functionsは、それらの関数をPostgreSQL9.1以降で利用可能にしています。 概要 senna-1.1.2-fast 組み込み型全文検索エンジンSennaの性能改善版 senna-1.1.2-fast-YYYYMMDD.tar.gz Ludia functionsは、提供モジュールの一つである性能改善版のSennaと組み合わせて使いうことで、Ludia同様に文字列の正規化やスニペット作成を行います。 Ludia functionsは、以下の環境で動作確認しています。 OS Red Hat Enterprise Linux 6.1 x86_64 Ludia functionsは、PostgreSQL9.1のみに対応しています。 9.0以前には未対応です。 9.2以降には対応していると思われますが、動作確認していません。 PostgreSQLのインストール $ cd postgresql-9.1.X $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/local/pgsqlです。このオプション指定は必須ではありません。 ここからsenna-1.1.2-fastのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 Sennaのmakeには長時間かかることに注意してください。 $ ./configure --prefix=/opt/senna-1.1.2-fast --without-mecab # make install •--without-mecab : mecabモジュールを使用しないことを指定します。このオプション指定は必須です。 $ tar zxf ludia_funcs-YYYYMMDD.tar.gz $ su •USE_PGXS : PostgreSQL関連モジュールをコンパイルするときのオマジナイです。1の指定が必須です。 Ludia functionsの登録 $ vi $PGDATA/postgresql.conf $ pg_ctl -D $PGDATA start =# \dx ludia_funcs -------------+---------+--------+----------------- •$PGDATAは、データベースクラスタのパスを決めて、そのパスで置き換えてください。 •Ludia functionsの登録には、CREATE EXTENSIONを使います。 CREATE EXTENSIONはデータベース単位でモジュールを登録するため、Ludia functionsを利用したいデータベースすべてにおいて登録が必要です。 Ludia functionsの削除 =# DROP EXTENSION ludia_funcs CASCADE;\r
+$ pg_ctl -D $PGDATA stop # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg uninstall •Ludia functionsに依存するDBオブジェクトを削除する必要があるため、DROP EXTENSIONにはCASCADEを指定します。 •shared_preload_libraries Sennaのアンインストール # cd <senna-1.1.2-fastのソースディレクトリ> 提供関数 •引数1(text) - 正規化する文字列 NFKCの正規化では、例えば、以下のように文字列を変換します。 •全角英数字を半角英数字に変換 ◦AbCdE123 → abcde123 =# SELECT pgs2norm('いロハAbCd12③Ⅳ㈱'); (1 row) pgs2snippet1は、文字列(引数8)からキーワード(引数7)のスニペット(KWIC)を作成する関数です。 •引数3(integer) - 作成するスニペットの数の上限 •引数6(integer) - HTMLの特殊文字をエスケープするかどうか(する: -1、しない: 0) •戻り値(text) - キーワード(引数7)を使って文字列(引数8)から作成したスニペット文字列 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'PostgreSQL', '最近、PostgreSQLの利用者が増えています。'); (1 row) =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"PostgreSQL"+"HINT"', 'pg_hint_planは、PostgreSQLでHINT句を使えるようにするツールです。'); (1 row) 実行例 ostgreSQLで★"2-gram"★の全文検 pgs2seninfo •戻り値2(text) - 利用しているSennaのconfigureオプション version | configure_options パラメータ 実行例 2013.04.05 ludia_funcs.norm_cache_limitは、pgs2normが確保するキャッシュの上限サイズを指定するパラメータです。設定値はkB単位で指定します。設定値の範囲は -1 ~ 2TB-1B です。設定値-1(デフォルト値)は、キャッシュサイズ上限としてパラメータwork_memの設定値を使うことを意味します。 キーワード内の"と\は、pgs2snippet1ではメタ文字("は検索文字列の区切り文字、\はエスケープ文字)として解釈されます。 "と\を文字そのものとして解釈させるには、それらを\でエスケープしなければなりません。 実行例\r
+$ su # exit postgresql.confの設定削除 •custom_variable_classes senna-1.1.2-fastのソースディレクトリでアンインストールを行います。 # make uninstall pgs2norm •戻り値(text) - 引数1を正規化した文字列 •半角カタカナを全角カタカナに変換 ◦アイウエオ → アイウエオ •環境依存文字を変換 ◦㌢㍻㊨⑤Ⅷ㈲ → センチ平成右5viii(有) pgs2norm pgs2normは、引数と戻り値の文字列をメモリ上にキャッシュします。そして、pgs2normの次回実行時に引数の文字列がキャッシュされているものと同じであれば、正規化処理を行わず、キャッシュされている戻り値を直接返却することで、処理を高速化します •引数1(integer) - スニペット作成時に正規化するかどうか(する: 1、しない: 0) •引数4(text) - スニペット作成時にキーワードの前に付ける文字列 •引数7(text) - スニペット作成に使うキーワード NULLの引数がある場合、戻り値はNULLです。 pgs2snippet1 pgs2snippet1では、キーワード(引数7)に複数の文字列を指定できます。複数指定するには、各文字列を"(半角ダブルクォート)で囲み、それらを+(半角プラス)でつなげます。 pgs2snippet1 •この実行例では、正規化を行う指定(引数1が1)になっているため、キーワードHINTは、小文字のhintにもマッチします。 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"\"2-gram\""', 'pg_bigmは、PostgreSQLで"2-gram"の全文検索を使えるようにするツールです。'); (1 row) pgs2seninfoは、Ludia functionsが利用しているSennaのバージョン情報を表示する関数です。 実行例 ---------------------------------+------------------------------------------------- ludia_funcs.lastupdate =# SHOW ludia_funcs.last_update ; (1 row) ludia_funcs.escape_snippet_keyword このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。 =# SHOW ludia_funcs.escape_snippet_keyword ;\r
+$ psql -d <データベース名> ホーム コミュニティ 1.概要 4.アンインストール 概要 モジュール名 Ludia functions 文字列の正規化関数とスニペット作成関数を提供するモジュール ludia_funcs-YYYYMMDD.tar.gz 各提供モジュールのライセンスはLGPLv2.1です。 動作確認環境 モジュール名 Senna senna-1.1.2-fast インストール $ tar zxf postgresql-9.1.X.tar.gz $ make # exit Sennaのインストール $ cd senna-1.1.2-fast-YYYYMMDD $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/localです。このオプション指定は必須ではありません。 ここからLudia functionsのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 $ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg # exit •SENNA_CFG : senna-cfgコマンド(Sennaインストール先のbinディレクトリに存在)のパスを指定します。senna-cfgにPATHが通っているのであれば、このオプション指定は不要です。 $ initdb -D $PGDATA --locale=C --encoding=UTF8 custom_variable_classes = 'ludia_funcs' =# CREATE EXTENSION ludia_funcs; Name | Version | Schema | Description (1 row) •postgresql.confで、shared_preload_librariesとcustom_variable_classesにludia_funcsを設定するのは必須です。 ◦PostgreSQL9.2以降ではcustom_variable_classesは存在しません。設定が必要なのはshared_preload_librariesだけです。 アンインストール\r
+=# DROP EXTENSION ludia_funcs CASCADE; ダウンロード 開発 2.動作確認環境 5.提供関数 Ludia functionsは、文字列の正規化関数とスニペット作成関数を提供するモジュールです。それらの関数は全文検索モジュールLudiaが提供していたものと同じです。 Ludia functionsは、それらの関数をPostgreSQL9.1以降で利用可能にしています。 概要 senna-1.1.2-fast 組み込み型全文検索エンジンSennaの性能改善版 senna-1.1.2-fast-YYYYMMDD.tar.gz Ludia functionsは、提供モジュールの一つである性能改善版のSennaと組み合わせて使いうことで、Ludia同様に文字列の正規化やスニペット作成を行います。 Ludia functionsは、以下の環境で動作確認しています。 OS Red Hat Enterprise Linux 6.1 x86_64 Ludia functionsは、PostgreSQL9.1のみに対応しています。 9.0以前には未対応です。 9.2以降には対応していると思われますが、動作確認していません。 PostgreSQLのインストール $ cd postgresql-9.1.X $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/local/pgsqlです。このオプション指定は必須ではありません。 ここからsenna-1.1.2-fastのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 Sennaのmakeには長時間かかることに注意してください。 $ ./configure --prefix=/opt/senna-1.1.2-fast --without-mecab # make install •--without-mecab : mecabモジュールを使用しないことを指定します。このオプション指定は必須です。 $ tar zxf ludia_funcs-YYYYMMDD.tar.gz $ su •USE_PGXS : PostgreSQL関連モジュールをコンパイルするときのオマジナイです。1の指定が必須です。 Ludia functionsの登録 $ vi $PGDATA/postgresql.conf $ pg_ctl -D $PGDATA start =# \dx ludia_funcs -------------+---------+--------+----------------- •$PGDATAは、データベースクラスタのパスを決めて、そのパスで置き換えてください。 •Ludia functionsの登録には、CREATE EXTENSIONを使います。 CREATE EXTENSIONはデータベース単位でモジュールを登録するため、Ludia functionsを利用したいデータベースすべてにおいて登録が必要です。 Ludia functionsの削除\r
+実行例 # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg uninstall •Ludia functionsに依存するDBオブジェクトを削除する必要があるため、DROP EXTENSIONにはCASCADEを指定します。 •shared_preload_libraries Sennaのアンインストール # cd <senna-1.1.2-fastのソースディレクトリ> 提供関数 •引数1(text) - 正規化する文字列 NFKCの正規化では、例えば、以下のように文字列を変換します。 •全角英数字を半角英数字に変換 ◦AbCdE123 → abcde123 =# SELECT pgs2norm('いロハAbCd12③Ⅳ㈱'); (1 row) pgs2snippet1は、文字列(引数8)からキーワード(引数7)のスニペット(KWIC)を作成する関数です。 •引数3(integer) - 作成するスニペットの数の上限 •引数6(integer) - HTMLの特殊文字をエスケープするかどうか(する: -1、しない: 0) •戻り値(text) - キーワード(引数7)を使って文字列(引数8)から作成したスニペット文字列 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'PostgreSQL', '最近、PostgreSQLの利用者が増えています。'); (1 row) =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"PostgreSQL"+"HINT"', 'pg_hint_planは、PostgreSQLでHINT句を使えるようにするツールです。'); (1 row) 実行例 ostgreSQLで★"2-gram"★の全文検 pgs2seninfo •戻り値2(text) - 利用しているSennaのconfigureオプション version | configure_options パラメータ 実行例 2013.04.05 ludia_funcs.norm_cache_limitは、pgs2normが確保するキャッシュの上限サイズを指定するパラメータです。設定値はkB単位で指定します。設定値の範囲は -1 ~ 2TB-1B です。設定値-1(デフォルト値)は、キャッシュサイズ上限としてパラメータwork_memの設定値を使うことを意味します キーワード内の"と\は、pgs2snippet1ではメタ文字("は検索文字列の区切り文字、\はエスケープ文字)として解釈されます。 "と\を文字そのものとして解釈させるには、それらを\でエスケープしなければなりません。\r
+=# SHOW ludia_funcs.escape_snippet_keyword ; # exit postgresql.confの設定削除 •custom_variable_classes senna-1.1.2-fastのソースディレクトリでアンインストールを行います。 # make uninstall pgs2norm •戻り値(text) - 引数1を正規化した文字列 •半角カタカナを全角カタカナに変換 ◦アイウエオ → アイウエオ •環境依存文字を変換 ◦㌢㍻㊨⑤Ⅷ㈲ → センチ平成右5viii(有) pgs2norm pgs2normは、引数と戻り値の文字列をメモリ上にキャッシュします。そして、pgs2normの次回実行時に引数の文字列がキャッシュされているものと同じであれば、正規化処理を行わず、キャッシュされている戻り値を直接返却することで、処理を高速化します •引数1(integer) - スニペット作成時に正規化するかどうか(する: 1、しない: 0) •引数4(text) - スニペット作成時にキーワードの前に付ける文字列 •引数7(text) - スニペット作成に使うキーワード NULLの引数がある場合、戻り値はNULLです。 pgs2snippet1 pgs2snippet1では、キーワード(引数7)に複数の文字列を指定できます。複数指定するには、各文字列を"(半角ダブルクォート)で囲み、それらを+(半角プラス)でつなげます。 pgs2snippet1 •この実行例では、正規化を行う指定(引数1が1)になっているため、キーワードHINTは、小文字のhintにもマッチします。 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"\"2-gram\""', 'pg_bigmは、PostgreSQLで"2-gram"の全文検索を使えるようにするツールです。'); (1 row) pgs2seninfoは、Ludia functionsが利用しているSennaのバージョン情報を表示する関数です。 実行例 ---------------------------------+------------------------------------------------- ludia_funcs.lastupdate =# SHOW ludia_funcs.last_update ; (1 row) ludia_funcs.escape_snippet_keyword このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。\r
+アンインストール $ psql -d <データベース名> ホーム コミュニティ 1.概要 4.アンインストール 概要 モジュール名 Ludia functions 文字列の正規化関数とスニペット作成関数を提供するモジュール ludia_funcs-YYYYMMDD.tar.gz 各提供モジュールのライセンスはLGPLv2.1です。 動作確認環境 モジュール名 Senna senna-1.1.2-fast インストール $ tar zxf postgresql-9.1.X.tar.gz $ make # exit Sennaのインストール $ cd senna-1.1.2-fast-YYYYMMDD $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/localです。このオプション指定は必須ではありません。 ここからLudia functionsのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 $ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg # exit •SENNA_CFG : senna-cfgコマンド(Sennaインストール先のbinディレクトリに存在)のパスを指定します。senna-cfgにPATHが通っているのであれば、このオプション指定は不要です。 $ initdb -D $PGDATA --locale=C --encoding=UTF8 custom_variable_classes = 'ludia_funcs' =# CREATE EXTENSION ludia_funcs; Name | Version | Schema | Description (1 row) •postgresql.confで、shared_preload_librariesとcustom_variable_classesにludia_funcsを設定するのは必須です。 ◦PostgreSQL9.2以降ではcustom_variable_classesは存在しません。設定が必要なのはshared_preload_librariesだけです。\r
+Ludia functionsの削除 =# DROP EXTENSION ludia_funcs CASCADE; ダウンロード 開発 2.動作確認環境 5.提供関数 Ludia functionsは、文字列の正規化関数とスニペット作成関数を提供するモジュールです。それらの関数は全文検索モジュールLudiaが提供していたものと同じです。 Ludia functionsは、それらの関数をPostgreSQL9.1以降で利用可能にしています。 概要 senna-1.1.2-fast 組み込み型全文検索エンジンSennaの性能改善版 senna-1.1.2-fast-YYYYMMDD.tar.gz Ludia functionsは、提供モジュールの一つである性能改善版のSennaと組み合わせて使いうことで、Ludia同様に文字列の正規化やスニペット作成を行います。 Ludia functionsは、以下の環境で動作確認しています。 OS Red Hat Enterprise Linux 6.1 x86_64 Ludia functionsは、PostgreSQL9.1のみに対応しています。 9.0以前には未対応です。 9.2以降には対応していると思われますが、動作確認していません。 PostgreSQLのインストール $ cd postgresql-9.1.X $ su •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/local/pgsqlです。このオプション指定は必須ではありません。 ここからsenna-1.1.2-fastのソースアーカイブファイルをダウンロードし、ビルドとインストールを行います。 Sennaのmakeには長時間かかることに注意してください。 $ ./configure --prefix=/opt/senna-1.1.2-fast --without-mecab # make install •--without-mecab : mecabモジュールを使用しないことを指定します。このオプション指定は必須です。 $ tar zxf ludia_funcs-YYYYMMDD.tar.gz $ su •USE_PGXS : PostgreSQL関連モジュールをコンパイルするときのオマジナイです。1の指定が必須です。 Ludia functionsの登録 $ vi $PGDATA/postgresql.conf $ pg_ctl -D $PGDATA start =# \dx ludia_funcs -------------+---------+--------+----------------- •$PGDATAは、データベースクラスタのパスを決めて、そのパスで置き換えてください。 •Ludia functionsの登録には、CREATE EXTENSIONを使います。 CREATE EXTENSIONはデータベース単位でモジュールを登録するため、Ludia functionsを利用したいデータベースすべてにおいて登録が必要です。\r
+キーワード内の"と\は、pgs2snippet1ではメタ文字("は検索文字列の区切り文字、\はエスケープ文字)として解釈されます。 "と\を文字そのものとして解釈させるには、それらを\でエスケープしなければなりません。 実行例 $ pg_ctl -D $PGDATA stop # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-9.1.X/bin/pg_config SENNA_CFG=/opt/senna-1.1.2-fast/bin/senna-cfg uninstall •Ludia functionsに依存するDBオブジェクトを削除する必要があるため、DROP EXTENSIONにはCASCADEを指定します。 •shared_preload_libraries Sennaのアンインストール # cd <senna-1.1.2-fastのソースディレクトリ> 提供関数 •引数1(text) - 正規化する文字列 NFKCの正規化では、例えば、以下のように文字列を変換します。 •全角英数字を半角英数字に変換 ◦AbCdE123 → abcde123 =# SELECT pgs2norm('いロハAbCd12③Ⅳ㈱'); (1 row) pgs2snippet1は、文字列(引数8)からキーワード(引数7)のスニペット(KWIC)を作成する関数です。 •引数3(integer) - 作成するスニペットの数の上限 •引数6(integer) - HTMLの特殊文字をエスケープするかどうか(する: -1、しない: 0) •戻り値(text) - キーワード(引数7)を使って文字列(引数8)から作成したスニペット文字列 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'PostgreSQL', '最近、PostgreSQLの利用者が増えています。'); (1 row) =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"PostgreSQL"+"HINT"', 'pg_hint_planは、PostgreSQLでHINT句を使えるようにするツールです。'); (1 row) 実行例 ostgreSQLで★"2-gram"★の全文検 pgs2seninfo •戻り値2(text) - 利用しているSennaのconfigureオプション version | configure_options パラメータ 実行例 2013.04.05 ludia_funcs.norm_cache_limitは、pgs2normが確保するキャッシュの上限サイズを指定するパラメータです。設定値はkB単位で指定します。設定値の範囲は -1 ~ 2TB-1B です。設定値-1(デフォルト値)は、キャッシュサイズ上限としてパラメータwork_memの設定値を使うことを意味します。\r
+このパラメータは、postgresql.confとSET文(スーパーユーザに限らずどのユーザからでも)で設定値を変更できます。 =# SHOW ludia_funcs.escape_snippet_keyword ; $ su # exit postgresql.confの設定削除 •custom_variable_classes senna-1.1.2-fastのソースディレクトリでアンインストールを行います。 # make uninstall pgs2norm •戻り値(text) - 引数1を正規化した文字列 •半角カタカナを全角カタカナに変換 ◦アイウエオ → アイウエオ •環境依存文字を変換 ◦㌢㍻㊨⑤Ⅷ㈲ → センチ平成右5viii(有) pgs2norm pgs2normは、引数と戻り値の文字列をメモリ上にキャッシュします。そして、pgs2normの次回実行時に引数の文字列がキャッシュされているものと同じであれば、正規化処理を行わず、キャッシュされている戻り値を直接返却することで、処理を高速化します •引数1(integer) - スニペット作成時に正規化するかどうか(する: 1、しない: 0) •引数4(text) - スニペット作成時にキーワードの前に付ける文字列 •引数7(text) - スニペット作成に使うキーワード NULLの引数がある場合、戻り値はNULLです。 pgs2snippet1 pgs2snippet1では、キーワード(引数7)に複数の文字列を指定できます。複数指定するには、各文字列を"(半角ダブルクォート)で囲み、それらを+(半角プラス)でつなげます。 pgs2snippet1 •この実行例では、正規化を行う指定(引数1が1)になっているため、キーワードHINTは、小文字のhintにもマッチします。 =# SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '"\"2-gram\""', 'pg_bigmは、PostgreSQLで"2-gram"の全文検索を使えるようにするツールです。'); (1 row) pgs2seninfoは、Ludia functionsが利用しているSennaのバージョン情報を表示する関数です。 実行例 ---------------------------------+------------------------------------------------- ludia_funcs.lastupdate =# SHOW ludia_funcs.last_update ; (1 row) ludia_funcs.escape_snippet_keyword\r
--- /dev/null
+\pset null '(null)'
+-- Load pg_bigm and ludia_funcs
+CREATE EXTENSION pg_bigm;
+CREATE EXTENSION ludia_funcs;
+-- Set parameters for the tests
+SET standard_conforming_strings TO off;
+SET escape_string_warning TO off;
+SET work_mem = '4MB';
+SET enable_seqscan TO off;
+SET enable_bitmapscan TO on;
+-- Test the case where the columns with CHAR data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE char_tbl (col1 char(256), col2 char(256), col3 char(256));
+\copy char_tbl from data/test_tbl.txt
+CREATE INDEX char_tbl_idx ON char_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+ pgs2snippet1
+-----------------------
+ ロハAbCd12③★Ⅳ㈱★');
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+ pgs2snippet1
+---------------
+ ★ 20★13.04.05
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+ pgs2snippet1
+------------------------
+ ト★アプリケーション★側
+(1 row)
+
+-- Test the case where the columns with VARCHAR data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE varchar_tbl (col1 varchar(256), col2 varchar(256), col3 varchar(256));
+\copy varchar_tbl from data/test_tbl.txt
+CREATE INDEX varchar_tbl_idx ON varchar_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+ pgs2snippet1
+-----------------------
+ ロハAbCd12③★Ⅳ㈱★');
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+ pgs2snippet1
+---------------
+ ★ 20★13.04.05
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+ pgs2snippet1
+------------------------
+ ト★アプリケーション★側
+(1 row)
+
+-- Test the case where the columns with TEXT data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE text_tbl (col1 text, col2 text, col3 text);
+\copy text_tbl from data/test_tbl.txt
+CREATE INDEX text_tbl_idx ON text_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+ pgs2snippet1
+-----------------------
+ ロハAbCd12③★Ⅳ㈱★');
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+ pgs2snippet1
+---------------
+ ★ 20★13.04.05
+(1 row)
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+ pgs2snippet1
+------------------------
+ ト★アプリケーション★側
+(1 row)
+
+-- Test the case where a multi-column index is created on many columns
+CREATE TABLE mc31_tbl (col1 text, col2 char(256), col3 varchar(256), col4 text,
+ col5 char(256), col6 varchar(256), col7 text, col8 char(256),
+ col9 varchar(256), col10 text, col11 char(256), col12 varchar(256),
+ col13 text, col14 char(256), col15 varchar(256), col16 text,
+ col17 char(256), col18 varchar(256), col19 text, col20 char(256),
+ col21 varchar(256), col22 text, col23 char(256), col24 varchar(256),
+ col25 text, col26 char(256), col27 varchar(256), col28 text,
+ col29 char(256), col30 varchar(256), col31 text);
+CREATE INDEX mc31_tbl_idx ON mc31_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops, pgs2norm(col3) gin_bigm_ops,
+ pgs2norm(col4) gin_bigm_ops, pgs2norm(col5) gin_bigm_ops,
+ pgs2norm(col6) gin_bigm_ops, pgs2norm(col7) gin_bigm_ops,
+ pgs2norm(col8) gin_bigm_ops, pgs2norm(col9) gin_bigm_ops,
+ pgs2norm(col10) gin_bigm_ops, pgs2norm(col11) gin_bigm_ops,
+ pgs2norm(col12) gin_bigm_ops, pgs2norm(col13) gin_bigm_ops,
+ pgs2norm(col14) gin_bigm_ops, pgs2norm(col15) gin_bigm_ops,
+ pgs2norm(col16) gin_bigm_ops, pgs2norm(col17) gin_bigm_ops,
+ pgs2norm(col18) gin_bigm_ops, pgs2norm(col19) gin_bigm_ops,
+ pgs2norm(col20) gin_bigm_ops, pgs2norm(col21) gin_bigm_ops,
+ pgs2norm(col22) gin_bigm_ops, pgs2norm(col23) gin_bigm_ops,
+ pgs2norm(col24) gin_bigm_ops, pgs2norm(col25) gin_bigm_ops,
+ pgs2norm(col26) gin_bigm_ops, pgs2norm(col27) gin_bigm_ops,
+ pgs2norm(col28) gin_bigm_ops, pgs2norm(col29) gin_bigm_ops,
+ pgs2norm(col30) gin_bigm_ops, pgs2norm(col31) gin_bigm_ops);
+\copy mc31_tbl from 'data/test_tbl_31.txt'
+SELECT col1 FROM mc31_tbl WHERE pgs2norm(col1) like likequery(pgs2norm('_S'));
+ col1
+----------------------------------------------
+ =# SHOW ludia_funcs.escape_snippet_keyword ;
+(1 row)
+
+EXPLAIN (costs off ) SELECT col1 FROM mc31_tbl WHERE pgs2norm(col1) like likequery(pgs2norm('_S'));
+ QUERY PLAN
+--------------------------------------------------------
+ Bitmap Heap Scan on mc31_tbl
+ Recheck Cond: (pgs2norm(col1) ~~ '%\\_s%'::text)
+ -> Bitmap Index Scan on mc31_tbl_idx
+ Index Cond: (pgs2norm(col1) ~~ '%\\_s%'::text)
+(4 rows)
+
+select col15 from mc31_tbl where pgs2norm(col15) like likequery(pgs2norm('テ゛ィ'));
+ col15
+----------------------------------------------------------------------------------------------------------------------------------------------
+ •--prefix : インストール先ディレクトリを指定します。未指定時のインストール先は/usr/local/pgsqlです。このオプション指定は必須ではありません。
+(1 row)
+
+EXPLAIN (costs off ) select col15 from mc31_tbl where pgs2norm(col15) like likequery(pgs2norm('テ゛ィ'));
+ QUERY PLAN
+-----------------------------------------------------------------
+ Bitmap Heap Scan on mc31_tbl
+ Recheck Cond: (pgs2norm((col15)::text) ~~ '%ディ%'::text)
+ -> Bitmap Index Scan on mc31_tbl_idx
+ Index Cond: (pgs2norm((col15)::text) ~~ '%ディ%'::text)
+(4 rows)
+
+select col31 from mc31_tbl where pgs2norm(col31) like likequery(pgs2norm('㊔'));
+ col31
+----------------------------
+ $ psql -d <データベース名>
+(1 row)
+
+EXPLAIN (costs off) select col31 from mc31_tbl where pgs2norm(col31) like likequery(pgs2norm('㊔'));
+ QUERY PLAN
+-------------------------------------------------------
+ Bitmap Heap Scan on mc31_tbl
+ Recheck Cond: (pgs2norm(col31) ~~ '%名%'::text)
+ -> Bitmap Index Scan on mc31_tbl_idx
+ Index Cond: (pgs2norm(col31) ~~ '%名%'::text)
+(4 rows)
+
+-- Test the case where data has a special character like "\t"
+CREATE TABLE snp_tbl (col1 text);
+CREATE INDEX snp_tbl_idx ON snp_tbl USING gin (pgs2norm(col1) gin_bigm_ops);
+INSERT INTO snp_tbl VALUES ('東京都山田太郎');
+INSERT INTO snp_tbl VALUES ('東京都 山田太郎');
+INSERT INTO snp_tbl VALUES ('東京都山田 太郎');
+INSERT INTO snp_tbl VALUES ('東京都 山田 太郎');
+INSERT INTO snp_tbl VALUES (E'東京都\t山田太郎');
+-- Test whether both seq and bitmap scans return the same results
+SET enable_seqscan to on;
+SET enable_bitmapscan to off;
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+ col1
+------------------
+ 東京都山田太郎
+ 東京都 山田太郎
+(2 rows)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+ col1
+-----------------
+ 東京都 山田太郎
+(1 row)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+ col1
+------------------
+ 東京都 山田 太郎
+(1 row)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+ col1
+------------------
+ 東京都山田太郎
+ 東京都 山田太郎
+(2 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+ QUERY PLAN
+--------------------------------------------------------
+ Seq Scan on snp_tbl
+ Filter: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+(2 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+ QUERY PLAN
+---------------------------------------------------------
+ Seq Scan on snp_tbl
+ Filter: (pgs2norm(col1) ~~ '%東京都 山田太郎%'::text)
+(2 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+ QUERY PLAN
+----------------------------------------------------------
+ Seq Scan on snp_tbl
+ Filter: (pgs2norm(col1) ~~ '%東京都 山田 太郎%'::text)
+(2 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+ QUERY PLAN
+--------------------------------------------------------
+ Seq Scan on snp_tbl
+ Filter: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+(2 rows)
+
+SET enable_seqscan to off;
+SET enable_bitmapscan to on;
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+ col1
+------------------
+ 東京都山田太郎
+ 東京都 山田太郎
+(2 rows)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+ col1
+-----------------
+ 東京都 山田太郎
+(1 row)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+ col1
+------------------
+ 東京都 山田 太郎
+(1 row)
+
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+ col1
+------------------
+ 東京都山田太郎
+ 東京都 山田太郎
+(2 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+ QUERY PLAN
+------------------------------------------------------------------
+ Bitmap Heap Scan on snp_tbl
+ Recheck Cond: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+ -> Bitmap Index Scan on snp_tbl_idx
+ Index Cond: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+(4 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+ QUERY PLAN
+-------------------------------------------------------------------
+ Bitmap Heap Scan on snp_tbl
+ Recheck Cond: (pgs2norm(col1) ~~ '%東京都 山田太郎%'::text)
+ -> Bitmap Index Scan on snp_tbl_idx
+ Index Cond: (pgs2norm(col1) ~~ '%東京都 山田太郎%'::text)
+(4 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+ QUERY PLAN
+--------------------------------------------------------------------
+ Bitmap Heap Scan on snp_tbl
+ Recheck Cond: (pgs2norm(col1) ~~ '%東京都 山田 太郎%'::text)
+ -> Bitmap Index Scan on snp_tbl_idx
+ Index Cond: (pgs2norm(col1) ~~ '%東京都 山田 太郎%'::text)
+(4 rows)
+
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+ QUERY PLAN
+------------------------------------------------------------------
+ Bitmap Heap Scan on snp_tbl
+ Recheck Cond: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+ -> Bitmap Index Scan on snp_tbl_idx
+ Index Cond: (pgs2norm(col1) ~~ '%東京都山田太郎%'::text)
+(4 rows)
+
--- /dev/null
+\pset null '(null)'
+
+-- Load pg_bigm and ludia_funcs
+CREATE EXTENSION pg_bigm;
+CREATE EXTENSION ludia_funcs;
+
+-- Set parameters for the tests
+SET standard_conforming_strings TO off;
+SET escape_string_warning TO off;
+SET work_mem = '4MB';
+SET enable_seqscan TO off;
+SET enable_bitmapscan TO on;
+
+-- Test the case where the columns with CHAR data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE char_tbl (col1 char(256), col2 char(256), col3 char(256));
+\copy char_tbl from data/test_tbl.txt
+CREATE INDEX char_tbl_idx ON char_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM char_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+
+-- Test the case where the columns with VARCHAR data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE varchar_tbl (col1 varchar(256), col2 varchar(256), col3 varchar(256));
+\copy varchar_tbl from data/test_tbl.txt
+CREATE INDEX varchar_tbl_idx ON varchar_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM varchar_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+
+-- Test the case where the columns with TEXT data type were indexed
+-- with pg_bigm and pgs2norm function.
+CREATE TABLE text_tbl (col1 text, col2 text, col3 text);
+\copy text_tbl from data/test_tbl.txt
+CREATE INDEX text_tbl_idx ON text_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops,
+ pgs2norm(col3) gin_bigm_ops);
+
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'v(株)', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('v(株)'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, '②⓪', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('②⓪'));
+SELECT pgs2snippet1(1, 32, 1, '★', '★', 0, 'アプリケーション', col1) FROM text_tbl
+ WHERE pgs2norm(col1) LIKE likequery(pgs2norm('アプリケーション'));
+
+-- Test the case where a multi-column index is created on many columns
+CREATE TABLE mc31_tbl (col1 text, col2 char(256), col3 varchar(256), col4 text,
+ col5 char(256), col6 varchar(256), col7 text, col8 char(256),
+ col9 varchar(256), col10 text, col11 char(256), col12 varchar(256),
+ col13 text, col14 char(256), col15 varchar(256), col16 text,
+ col17 char(256), col18 varchar(256), col19 text, col20 char(256),
+ col21 varchar(256), col22 text, col23 char(256), col24 varchar(256),
+ col25 text, col26 char(256), col27 varchar(256), col28 text,
+ col29 char(256), col30 varchar(256), col31 text);
+CREATE INDEX mc31_tbl_idx ON mc31_tbl USING gin (pgs2norm(col1) gin_bigm_ops,
+ pgs2norm(col2) gin_bigm_ops, pgs2norm(col3) gin_bigm_ops,
+ pgs2norm(col4) gin_bigm_ops, pgs2norm(col5) gin_bigm_ops,
+ pgs2norm(col6) gin_bigm_ops, pgs2norm(col7) gin_bigm_ops,
+ pgs2norm(col8) gin_bigm_ops, pgs2norm(col9) gin_bigm_ops,
+ pgs2norm(col10) gin_bigm_ops, pgs2norm(col11) gin_bigm_ops,
+ pgs2norm(col12) gin_bigm_ops, pgs2norm(col13) gin_bigm_ops,
+ pgs2norm(col14) gin_bigm_ops, pgs2norm(col15) gin_bigm_ops,
+ pgs2norm(col16) gin_bigm_ops, pgs2norm(col17) gin_bigm_ops,
+ pgs2norm(col18) gin_bigm_ops, pgs2norm(col19) gin_bigm_ops,
+ pgs2norm(col20) gin_bigm_ops, pgs2norm(col21) gin_bigm_ops,
+ pgs2norm(col22) gin_bigm_ops, pgs2norm(col23) gin_bigm_ops,
+ pgs2norm(col24) gin_bigm_ops, pgs2norm(col25) gin_bigm_ops,
+ pgs2norm(col26) gin_bigm_ops, pgs2norm(col27) gin_bigm_ops,
+ pgs2norm(col28) gin_bigm_ops, pgs2norm(col29) gin_bigm_ops,
+ pgs2norm(col30) gin_bigm_ops, pgs2norm(col31) gin_bigm_ops);
+\copy mc31_tbl from 'data/test_tbl_31.txt'
+
+SELECT col1 FROM mc31_tbl WHERE pgs2norm(col1) like likequery(pgs2norm('_S'));
+EXPLAIN (costs off ) SELECT col1 FROM mc31_tbl WHERE pgs2norm(col1) like likequery(pgs2norm('_S'));
+
+select col15 from mc31_tbl where pgs2norm(col15) like likequery(pgs2norm('テ゛ィ'));
+EXPLAIN (costs off ) select col15 from mc31_tbl where pgs2norm(col15) like likequery(pgs2norm('テ゛ィ'));
+
+select col31 from mc31_tbl where pgs2norm(col31) like likequery(pgs2norm('㊔'));
+EXPLAIN (costs off) select col31 from mc31_tbl where pgs2norm(col31) like likequery(pgs2norm('㊔'));
+
+-- Test the case where data has a special character like "\t"
+CREATE TABLE snp_tbl (col1 text);
+CREATE INDEX snp_tbl_idx ON snp_tbl USING gin (pgs2norm(col1) gin_bigm_ops);
+INSERT INTO snp_tbl VALUES ('東京都山田太郎');
+INSERT INTO snp_tbl VALUES ('東京都 山田太郎');
+INSERT INTO snp_tbl VALUES ('東京都山田 太郎');
+INSERT INTO snp_tbl VALUES ('東京都 山田 太郎');
+INSERT INTO snp_tbl VALUES (E'東京都\t山田太郎');
+
+-- Test whether both seq and bitmap scans return the same results
+SET enable_seqscan to on;
+SET enable_bitmapscan to off;
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+
+SET enable_seqscan to off;
+SET enable_bitmapscan to on;
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm('東京都 山田 太郎'));
+EXPLAIN (costs off) SELECT * FROM snp_tbl WHERE pgs2norm(col1) LIKE likequery(pgs2norm(E'東京都\t山田太郎'));