PostgreSQLによるファイルサーバの全文検索システムで,複数カラムの情報をtsvectorに保持することでインデックス化対象を拡張する

PostgreSQLで全文検索〜インデックス化対象の追加

前提

PostgreSQL8.3の内蔵tsearch2でファイルサーバを全文検索しようという,これまでの 環境構築編アプリケーション編 の内容によって,全文検索ができるようになったとする.

ファイル名のインデックス化

これまでは,各ファイル(テキスト,PDF,Excel)の本文の内容をインデックス化していた. しかしファイルの属性には,他にも検索に使えるものがある.

ファイル名には,そのファイルの内容を表す重要なキーワードが含まれる場合が多いし, そのファイルの存在するディレクトリ名も,キーワードとして有効な場合が多い. ある事柄についてのディレクトリを作ってその配下に関連ファイルを置くという状況は, 容易に想像できる.

また,検索する場合のことを考えたときに,ファイル名のうろ覚えとかでファイル名や拡張子を検索条件に使えると便利という面もある.

そういうことを考えて,今までの本文の内容だけでなく,ファイル名やディレクトリ名の情報もインデックス化することにする.

設計

今までの本文の内容だけでなく,以下の属性を全てインデックス化することにする.

項目インデックス化時の重要度備考
本文の内容D-
ファイル名A今回追加する項目
1つ上のディレクトリ名C今回追加する項目

重要度は,Aが最高でDが最低.ファイル名が最重要なのは良いが, ディレクトリ名が重要度Cなのは特に根拠はない.Bでも良いのかも知れない.

今回のシステムでは,検索した結果を以下のようにts_rank_cd()を使ってランキング順にソートしているが, このときに重要度が効いてくるようだ.

 ORDER BY ts_rank_cd(contents_z, to_tsquery('pg_catalog.english', prepareKeyword(?))) desc

ts_rank_cd()の記述は,マニュアルでは以下に書かれている.
http://www.postgresql.org/docs/8.3/static/textsearch-controls.html#TEXTSEARCH-RANKING

実装

このような重要度の設定を実現するためには, tsvectorカラムを更新するトリガーファンクションを,以下のように変更すれば良い.

変更前のDDL

create or replace function fn_iudrow_file_item() returns trigger as $$
begin
	new.contents_z :=
		setweight(to_tsvector('pg_catalog.english', wakachi(zenkakuToHankaku(new.contents))), 'D');
	return new;
end
$$ language plpgsql;

変更後のDDL

create or replace function fn_iudrow_file_item() returns trigger as $$
declare
	dir	text;
	file	text;
begin
	dir := coalesce(substring(new.file_path, '/([^/]+)/[^/]+$'), '');
	file := coalesce(substring(new.file_path, '/([^/]+)$'), '');

	new.contents_z :=
		setweight(to_tsvector('pg_catalog.english', wakachi(zenkakuToHankaku(file))), 'A') ||
		setweight(to_tsvector('pg_catalog.english', wakachi(zenkakuToHankaku(dir))), 'C') ||
		setweight(to_tsvector('pg_catalog.english', wakachi(zenkakuToHankaku(new.contents))), 'D');
	return new;
end
$$ language plpgsql;

全文検索の実行に使用する1つのtsvectorカラム(contents_z)に,複数の情報を連結して設定している.

上記のトリガーファンクションは,以下のようにファイル情報格納テーブル (file_item)のbefore insert or updateトリガーとして呼び出されている.

上記Functionをの呼び出しているトリガーの定義.今回は変更無し

create trigger tr_iudrow_file_item before insert or update
	on file_item for each row execute procedure fn_iudrow_file_item();

変更後の対処

このように,contents_zに格納する内容を拡張したということは,当然ながらデータの作り直しになります...

インデックスの中身に影響するようなことが後から発生するような事態は避けたいのだが, 実際に使ってみないと利便性とかわからんので,仕方がないのでした.


© 2024 KMIソフトウェア