PostgreSQLの機能には式に対するインデックスというものがあります。例えば、大文字を小文字に変換するlower関数を利用して、次に示す通りのインデックスを作成します。
# CREATE INDEX idx_lower ON test (lower(txt));
すると次の示す問い合わせでは、インデックスが使用されるようになります(この例のように関数の結果に対して適用されるインデックスを、関数インデックスと呼びます)。
# SELECT * FROM test WHERE lower(txt) = 'hello';
Ludiaの全文検索インデックスでもこの機能を利用することができます。Ludia 0.9.0には式に対するインデックスを利用する場合の例として、PDFからテキストを抽出するテキストフィルタを実行する関数がサンプルとして含まれています。ここでは、この関数の使い方を説明します。
今回利用するテキストフィルタはpdftotextというコマンドラインから実行できるツールで、XpdfというオープンソースのPDFビューアに付属しているものです。まずはXpdfを以下の要領でインストールする必要があります(XpdfはFedora Coreにも収録されているため、OSをインストールした際の設定よってはすでにインストールされているかもしれません)。
$ wget ftp://ftp.foolabs.com/pub/xpdf/xpdf-3.01.tar.gz
$ wget ftp://ftp.foolabs.com/pub/xpdf/xpdf-3.01pl2.patch
$ tar zxvf xpdf-3.01.tar.gz
$ patch -p0 < xpdf-3.01pl2.patch
$ cd xpdf-3.01
$ ./configure
$ make
$ sudo make install
上記のようにインストールを行うと、プログラムは「/usr/local/bin」にインストールされることになります。あとで必要になるので、PostgreSQLサーバ実行ユーザのPATHに、このディレクトリが含まれていることを確認しておいてください。インストールしたら設定ファイル(/usr/local/etc/xpdfrc)を編集します。さしあたって変更する必要があるのは、出力するテキストの文字コードと改行コードの設定の部分です。
textEncoding UTF-8
textEOL unix
設定を行ったら、適当なPDFファイルを利用してテストしてみます。以下のようにターミナルからpdftotextコマンドを実行し、標準出力にPDFファイル内のテキストが出力されれば成功です。
$ pdftotext /tmp/PostgresForest.pdf - | head
高性能・高信頼の並列分散データベース環境を低コストで実現 複数ノード上
でそれぞれ稼動しているPostgreSQLをシングルシステムイメージとしてユー
ザに提供 PostgreSQL と互換性があるため、アプリケーション開発時に新たな
トレーニン グが不要 オープンソースでのシステム構築可能性を向上
...(省略)
では、これをPostgreSQLから利用してみます。テキストフィルタを実行するための関数は以下の2種類があります。
- pgs2pdftotext1
- PDFファイルのpathをtex型のデータとして引数にとる。
- pgs2pdftotext2
- PDFファイルをbytea型のデータとして引数にとる。
表1:テキストフィルタの関数
まず、これらの関数を登録する必要があります。psqlから次のようなCREATE FUNCTION文を実行してください。
CREATE OR REPLACE FUNCTION
pgs2pdftotext1(TEXT) RETURNS TEXT
AS '$libdir/pgsenna2', 'pgs2_pdftotext1'
LANGUAGE 'C' STRICT IMMUTABLE;
CREATE OR REPLACE FUNCTION
pgs2pdftotext2(BYTEA) RETURNS TEXT
AS '$libdir/pgsenna2', 'pgs2_pdftotext2'
LANGUAGE 'C' STRICT IMMUTABLE;
関数を登録したら、pgs2pdftotext1関数を実行してみます。
# select pgs2pdftotext1('/tmp/PostgresForest.pdf');
pgs2pdftotext1
-----------------
高性能・高信頼の並列分散データベース環境を低コストで実現複数ノード上
でそれぞれ稼動しているPostgreSQLをシングルシステムイメージとしてユー
ザに提供PostgreSQLと互換性があるため、アプリケーション開発時に新たな
トレーニングが不要 オープンソースでのシステム構築可能性を向上
...(省略)
コマンドラインからpdftotextを実行した場合と同様に、PDFファイル内のテキストが取得できます。これを全文検索インデックスを組み合わせて利用してみます。以下のようなファイルのpathを格納する列をもつテスト用のテーブルを作成し、その列にpgs2pdftext1関数を適用した結果に対して関数インデックスを作成します。
# CREATE TABLE test1 (path text);
CREATE TABLE
# CREATE INDEX idx1 ON test1 USING fulltext (pgs2pdftotext1(path));
CREATE INDEX
# INSERT INTO test1 VALUES ('/tmp/PostgresForest.pdf');
INSERT 0 1
インデックス作成後にデータをINSERTしていますが、このINSERTの時点でpdftotext1関数が実行されてPDFファイルからテキストが取りだされ、全文検索インデックスの情報が更新されます。
では、検索を実行してみます。検索条件の左辺にはインデックスを定義するときと同様の式を、右辺にはこれまでの場合と同じように、検索キーワードを与えます。まずは、問い合わせのプランをEXPLAINで確認してから実行してみます。
# EXPLAIN SELECT path FROM test1
WHERE pgs2pdftotext1(path) @@ '並列分散データベース環境';
QUERY PLAN
-----------------------------------------------------------------------
Index Scan using idx1 on test1 (cost=0.00..0.01 rows=1 width=32)
Index Cond: (pgs2pdftotext1(path) @@ '並列分データベース環境'::text)
(2 rows)
# SELECT path FROM test1
WHERE pgs2pdftotext1(path) @@ '並列分散データベース環境';
path
-------------------------
/tmp/PostgresForest.pdf
(1 row)
これをみると、式に対するインデックスを利用した検索が行われ、指定した文字列を含むファイルのPATHが取得できていることがわかります。
ここでは説明しやすいため、pgs2pdftotext1を例として用いましたが、pgs2pdftotext2関数の場合も使い方はまったく同様です。pgs2pdftotext1の場合にtext型のデータとしてファイルのpathを与えていた部分(PDFファイルそれ自体)をbytea型のデータとして与えるように置き換えます。
|