TOP業務システム> PDFファイルの全文検索
Ludia
高性能なオープンソース全文検索システム「Ludia」

第6回:柔軟に対応できるLudiaの検索機能

著者:NTTデータ  岩崎 正剛   2007/2/28
前のページ  1  2  3
PDFファイルの全文検索

   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型のデータとして与えるように置き換えます。


関数インデックスの応用

   コードを見てみるとわかるのですが、pgs2pdftotext関数の中身はpdftotextコマンドを呼びだして実行するという単純なものです。他のコマンドを呼びだすように少しだけ書き換えれば、PDF以外の文書に対応することもできるでしょう。例えば、Microsoft Word形式のファイルに対しては、wvWareというオープンソースのツールが存在します。

   またテキストフィルタ以外にも、テキストを出力する関数と全文検索インデックスを組み合わせて有効に利用できるケースを考えてみるのも面白いかもしれません。

   例えば、前回の記事で解説した「全文検索インデックスの構成オプション」の中には、「形態素解析ではなく、空白区切りで単語を区切るフラグ(SEN_INDEX_DELIMITED (0x0020))」がありましたが、単語を空白で区切る関数を用意し、上記のフラグを有効にして関数インデックスを作成することで、独自の形態素解析を使えるようにする(MeCab以外)といったこともできるでしょう。

# SET ludia.sen_index_flags = 33;
SET

# CREATE INDEX idxu ON test USING fulltextu(pgkakasi(txt));
CREATE INDEX

   このように、DBMSに組み込まれているLudiaの場合、他のパーツといろいろ組み合わせて使ってみることで、有効活用できる場面が広がるのではないかと思います。

   次回は、Ludiaの機能を拡張するPostgresForest Suiteを紹介します。

前のページ  1  2  3


株式会社NTTデータ 岩崎 正剛
著者プロフィール
株式会社NTTデータ  岩崎 正剛
基盤システム事業本部 オープンソース開発センタ
2002年よりNTTデータにてPCグリッドの研究開発などに従事。2006年よりOSS分野に参画し、現在はLudiaの開発、技術支援を行っている。


INDEX
第6回:柔軟に対応できるLudiaの検索機能
  Ludiaの高度な検索機能
  検索ヒット件数を高速に取得
PDFファイルの全文検索