[pgsql-jp: 37954] Re: インデックスGIN利用時tsearch2 でのNOT検索エラー(PostgreSQL v8.2.1)

Tatsuo Ishii ishii @ sraoss.co.jp
2007年 1月 19日 (金) 00:15:13 JST


石井です.

> コサカと申します。
> 
> ITProの新しいインデックスGINとtsearch2を組み合わせた全文検索の記事を読み
> 面白そうだと思い、実際に動作検証を行ってみました。
>http://itpro.nikkeibp.co.jp/article/COLUMN/20061122/254458/)
> 
> ■テスト環境
> OS CentOS4.4
> DB PostgreSQL-8.2.1 + tsearch2
> tsearch2はPostgreSQLのcontribからインストール
> 
> ■PostgreSQLの初期化
> #initdb --no-locale --encoding=EUC_JP
> 
> ■テーブルの作成とデータ登録
> #createdb test
> #psql -l
>   Name     | Owner     | Encoding
> -----------+-----------+----------
>  postgres  | postgres  | EUC_JP
>  template0 | postgres  | EUC_JP
>  template1 | postgres  | EUC_JP
>  test      | postgres  | EUC_JP
> 
> #psql -f /usr/local/pgsql/share/contrib/tsearch2.sql -d test
> 
> #psql test
> 
> #CREATE TABLE sample(message TEXT,
>                      idxfti TSVECTOR);
> 
> #CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON sample
>  FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxfti, message);
> 
> #CREATE INDEX idxfti_idx ON sample USING gin(idxfti);
> 
> #INSERT INTO sample(message) VALUES('test message');
> 
> ■データの確認とNOT検索の実行
> データは1件しかなく、NOT検索すれば1件もマッチしないという結果になるだろうと予測していたのですが・・・。
> 
> #SELECT * FROM sample;
>    message    |       idxfti
> --------------+---------------------
>  test message | 'test':1 'messag':2
> 
> #SELECT * FROM sample WHERE idxfti @@ to_tsquery('!test');
> ERROR:  Query requires full scan, GIN doesn't support it
> #
> 
> クエリープランでは「full scan」が選択されたが、GINはサポートしていないよ?
> というような内容のエラーが帰ってきました。
> full scanをサポートしない?という意味がよくわからなかったのですがとりあえず
> 以下を実行し(デフォルトONと認識していますので意味がないと思いますが)
> 
> #SET enable_indexscan TO on;
> #SET enable_bitmapscan TO on;
> 
> 再度同じコマンドを実行してみたところ
> #SELECT * FROM sample WHERE idxfti @@ to_tsquery('!test');
> ERROR:  Query requires full scan, GIN doesn't support it

このケースでは,すべてのデータをGINインデックス経由で持ってこなければ
なりませんが,そのようなアクセス方法をGINはサポートしていない,という
ことです.

> やはりエラーとなりました。
> 選択したプランがおかしいのかはよくわかりませんが、ANALYZEを実行してみたところ
> #ANALYZE;
> #SELECT * FROM sample WHERE idxfti @@ to_tsquery('!test');
>  message | idxfti
> ---------+--------
> (0 rows)
> 
> 思っていた回答をしました。

ANAYZEによって統計情報が正しくセットされ,順スキャンが選択された結果
GINインデックスが使われなくなってエラーが回避されたということでしょう.

> ちなみにインデックスをGiSTで作成した場合は
> とくにANALYZEを実行しなくてもエラーは発生しません。
> #CREATE INDEX idxfti_idx ON sample USING gist(idxfti);
> 
> #SELECT * FROM sample;
>    message    |       idxfti
> --------------+---------------------
>  test message | 'test':1 'messag':2
> 
> #SELECT * FROM sample WHERE idxfti @@ to_tsquery('!test');
>  message | idxfti
> ---------+--------
> (0 rows)
> 
> エラー内容がどこに起因するのか調べていたところ、tsearch2のソースの以下でエラーになることがわかったのですが、ここでどういった処理をしているかがわからずに足踏み状態となってしまいました。
> 
> ginidx.c 73行目〜
> 	item = clean_NOT_v2(GETQUERY(query), &len);
> 	if(!item)
> 	 elog(ERROR, "Query requires full scan, GIN doesn't support it")
> 
> query_cleanup.c 169行目〜
> 	ITEM *
> 	clean_NOT_v2(ITEM * ptr, int4 *len)
> 	{
> 	  NODE *root = maketree(ptr);
> 	  return plaintree(clean_NOT_intree(root), len);
> 	}
> 
> さらに調べていけば原因がわかるような気もするのですが、そもそもソースの問題ではなく
> tsearch2の使い方が悪いんでしょうか?
> でも特に難しいクエリーは発行していないのですが・・・。

!testのような検索はGINインデックスの「全スキャン」になり,実行できない
ので,弾いているようです.つまり,tsearch2+GINの仕様のような気がします.
--
Tatsuo Ishii
SRA OSS, Inc. Japan



pgsql-jp メーリングリストの案内