groonga、textsearch_groonga使い方めも

groonga、textsearch_groongaを使ったときのメモなど。
groongaはv1.1.0、textsearch_groongaはversion 0.1で確認。

参考サイト
groonga
textsearch_groonga

所感

versionもまだ0.1ですし、いろいろと思い違いをしているところなどあるとおもいますが、textsearch_groongaをtextsearch_sennaと比べると、結構いい感じに思います。

メリット
 自前のストレージを持っている
 マルチカラムインデックスが使える
 更新時の不整合解消、非同期処理性能向上(groongaサーバモードのときかも?)
 スコアリング対応
 groongaをHTTPモードで起動してインデックスサーバを併用できる

デメリット
 インデックス削除でごみが残る
 ストリーミングレプリケーション非対応
 like検索非対応

その他
 DBはUTF-8で構築するのがよい
 今のところ、%%ではなくgroonga.query()を使うこと
 マルチカラムインデックスがいい感じ(explain結果)
 HTTPで通信できるgroongaサーバがおもしろい。管理画面もある
 vacuum、vacuum full対策不明(要調査)
 groongaの設定をどこでするのか不明(要調査)

textsearch_groongaで検索

「一般的な比較演算子に加え、全文検索用の %% 演算子と、groonga クエリを直接記述できる @@ 演算子をサポートしています。
ただし、現在のバージョンでは textsearch_senna とは異なり、LIKE 演算子はサポートしていません。また、CREATE INDEX の際に WITH 句で指定できるインデックス・オプションはありません。 」
とのことです。

インデックス作成

using groongaを指定してインデックスを作成します。
また、マルチカラムインデックスを指定できます。

# インデックス
create index test_gidx_01 on test using groonga (name);
# 部分インデックス
create index test_gidx_02 on test using groonga (name) where gender = 1;
# マルチカラムインデックス
create index test_gidx_03 on test using groonga (name, introduction);
%% 演算子

OPERATOR %% (document text, query text)

# %%で検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where name %% 'test';
  uid   |     name     | score
--------+--------------+-------
 268278 | test001      |     2
 270929 | test002      |     1

# %%でのAND,OR検索は今のところ非対応の模様
=# select uid, name, groonga.score(tableoid, ctid)  from test where name %% 'test 01';
RROR:  unexpected result: NULL
CONTEXT:  query: select --table t232868095 --sortby _key --output_columns _key,_score --limit -1 --query "(name:@test\ 01)"
groonga.query()で検索

@@ の左辺の列名は、使用する groonga インデックスの列の任意のいずれか1つで構いません。検索条件として使う列は、groonga.query() で与えます。


groonga.query('検索ワード', '検索カラム')

# 検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test', 'name')
  uid   |     name     | score
--------+--------------+-------
 268278 | test001      |     2
 270929 | test002      |     1
# 複数のカラムを検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where introduction @@ groonga.query('test', 'name||introduction');
  uid   |     name     | score
--------+--------------+-------
 268278 | test001      |     2
 270929 | test002      |     1
 207821 | data003      |     1
# 複数のカラムを重み付け検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where introduction @@ groonga.query('test', 'name*10||introduction');
  uid   |     name     | score
--------+--------------+-------
 268278 | test001      |    20
 270929 | test002      |    10
 207821 | data003      |     1
# AND検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test 01', 'name');
# OR検索
=# select uid, name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test OR data', 'name');
%%とgroonga.query()の比較

expainのクエリプランを比較してみます。


・単純検索

### %%
=# explain select name, groonga.score(tableoid, ctid)  from test where name %% 'test';
                                        QUERY PLAN
-------------------------------------------------------------------------------------------
 Index Scan using test_gidx_03 on test (cost=0.25..164.10 rows=80 width=18)
   Index Cond: ((name)::text %% 'test'::text)

### groonga.query()
=# explain select name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test', 'name');
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=311.34..5825.59 rows=39883 width=22)
   Recheck Cond: (name @@ '--query "test" --match_columns "name"'::groonga.query)
   ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..301.37 rows=39883 width=0)
         Index Cond: (name @@ '--query "test" --match_columns "name"'::groonga.query)


・AND検索

### %%
=# explain select name, groonga.score(tableoid, ctid)  from test where name %% 'test' and name %% 'うら';
                                       QUERY PLAN
----------------------------------------------------------------------------------------
 Index Scan using test_gidx_03 on test  (cost=0.49..4.77 rows=1 width=22)
   Index Cond: (((name)::text %% 'test'::text) AND ((name)::text %% 'うら'::text))

### groonga.query()
=# explain select name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test うら'
, 'name');
                                        QUERY PLAN
-------------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=311.34..5825.59 rows=39883 width=22)
   Recheck Cond: (name @@ '--query "test\\ うら" --match_columns "name"'::groonga.query)
   ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..301.37 rows=39883 width=0)
         Index Cond: (name @@ '--query "test\\ うら" --match_columns "name"'::groonga.query)


・OR検索

### %%
=# explain select name, groonga.score(tableoid, ctid)  from test where name %% 'test' or name %% 'うら';
                                       QUERY PLAN
-----------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=6.27..375.95 rows=159 width=22)
   Recheck Cond: (((name)::text %% 'test'::text) OR ((name)::text %% 'うら'::text))
   ->  BitmapOr  (cost=6.27..6.27 rows=160 width=0)
         ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..3.10 rows=80 width=0)
               Index Cond: ((name)::text %% 'test'::text)
         ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..3.10 rows=80 width=0)
               Index Cond: ((name)::text %% 'うら'::text)

### groonga.query()
=# explain select name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test OR
うら', 'name');
                                           QUERY PLAN
------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=311.34..5825.59 rows=39883 width=22)
   Recheck Cond: (name @@ '--query "test\\ OR\\ うら" --match_columns "name"'::groonga.query)
   ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..301.37 rows=39883 width=0)
         Index Cond: (name @@ '--query "test\\ OR\\ うら" --match_columns "name"'::groonga.query)


・マルチカラム検索

### %%
=# explain select name, groonga.score(tableoid, ctid)  from test where name %% 'test' or introduction %% 'test';
                                       QUERY PLAN
-----------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=6.27..375.95 rows=159 width=22)
   Recheck Cond: (((name)::text %% 'test'::text) OR (introduction %% 'test'::text))
   ->  BitmapOr  (cost=6.27..6.27 rows=160 width=0)
         ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..3.10 rows=80 width=0)
               Index Cond: ((name)::text %% 'test'::text)
         ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..3.10 rows=80 width=0)
               Index Cond: (introduction %% 'test'::text)

### groonga.query()
=# explain select name, groonga.score(tableoid, ctid)  from test where name @@ groonga.query('test', '
name||introduction');
                                             QUERY PLAN
----------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on test  (cost=311.34..5825.59 rows=39883 width=22)
   Recheck Cond: (name @@ '--query "test" --match_columns "name||introduction"'::groonga.query)
   ->  Bitmap Index Scan on test_gidx_03  (cost=0.00..301.37 rows=39883 width=0)
         Index Cond: (name @@ '--query "test" --match_columns "name||introduction"'::groonga.query)

groonga(コマンドモード)で検索

PostgreSQL全文検索インデックスで作成したストレージファイルにgroonga(コマンドモード)でアクセスすることができます。
PostgreSQLでgroonga使用時のストレージファイルは、{PostgreSQLデータディレクトリ}/base/データベースのOID/grnとなっています。パスなどの設定が{PostgreSQLデータディレクトリ}を基準に設定してあるため、{PostgreSQLデータディレクトリ}でgroongaコマンドを実行する必要があります。

groongaオープン

cd /usr/local/pgsql/data
groonga base/16414/grn

groongaコマンドモード

# --queryで検索カラム指定
> select --table t232867959 --query "name:@\"test\""
[[0,1301479281.22904,0.000446],[[[2],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[28049425,1,"testおうか"],[254607369,1,"testうらばん"]]]]

# --match_columnsで検索カラム指定
> select --table t232867959 --match_columns name --query "test"
[[0,1301479323.02256,0.000414],[[[2],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[28049425,1,"testおうか"],[254607369,1,"testうらばん"]]]]

# --match_columns複数指定
> select --table t232868095 --match_columns "name||introduction" --query "testう"
[[0,1301479702.79753,0.002362],[[[1],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[254607369,2,"testうらばん"]]]]

# 絞込み検索
> select --table t232868095 --match_columns "name" --query "test\ うら"
[[0,1301479769.08768,0.002223],[[[1],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[254607369,2,"testうらばん"]]]]

# OR検索
> select --table t232868095 --match_columns "name" --query "test\ OR\ うら"
[[0,1301479836.42993,0.002367],[[[12],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[28049425,1,"testおうか"],[43515908,1,"うらわざ"],[105775113,1,"うらら(p_q)"],[111214612,1,"うらら"],[114360329,1,"ゆうら"],[175439873,1,"うらのり"],[189333515,1,"たまうら"],[196018181,1,"うらら"],[225050635,1,"うららん"],[232980494,1,"ゆうら☆"],[254607369,2,"testうらばん"],[271187970,1,"つうら"]]]]

groonga(HTTPプロトコルモード)で検索

参考サイト
http://groonga.org/docs/tutorial/tutorial02.html

MySQLプロトコルでデータの更新を行い、HTTPでデータの参照を行うことができます」との記述があったので、PostgreSQLでも試してみました。

PostgreSQL全文検索インデックスで作成したストレージファイルにgroonga(HTTPプロトコルモード)でアクセスする。

サーバ起動

・起動
書式
 groonga [-p ポート番号] -d --protocol http DBパス名


groonga(コマンドモード)のときと同様、{PostgreSQLデータディレクトリ}で起動する必要があります。

cd /usr/local/pgsql/data
groonga -p 8080 -d --protocol http base/16414/grn


・管理画面
http://[IP]:[ポート]/

検索

http://[IPまたはホスト名]:[ポート番号]/d/status

http://172.30.0.160:8080/d/status


http://[IPまたはホスト名]:[ポート番号]/d/select?table=[テーブル]&query=[クエリ]
テーブルIDは管理画面から確認してください。

こんな感じで

#
http://92.168.0.1:8080/d/select?table=t232867959&output_columns=_key,_score,name&limit=-1&query=name:@test

# 出力
[[0,1301480525.33205,0.000413],[[[2],[["_key","Int64"],["_score","Int32"],["name","ShortText"]],[28049425,1,"testおうか"],[254607369,1,"testうらばん"]]]]