PostgreSQL 9.6 全文検索 演算子/tsquery()を使わず全文検索
ぬこは激怒した。
かのPostgreSQL 9.6 beta1文書 全文検索用演算子の <-> の使用例の記述を改善せねばと決意した。
<-> 演算子を使うとどうなるの?
tsquery_phrase()のsyntax suggerであるのは想像できるのだが、distanceをどう設定しているのか文書を読んでも今ひとつ良くわからぬ。
結局、動かすかソースを見るしかないのだろうか。
とりあえず、<-> 演算子を使ってみる。
tsearch=# SELECT to_tsquery('english', 'cat') <-> to_tsquery('english', 'dog'); ?column? ----------------- 'cat' <-> 'dog' (1 row)
はあ。という結果なんだけど・・・
tsquery <-> tsquery の演算子が適用された結果は、やっぱりtsquery型になる。
上の例は、TEXT型としての 'cat' <-> 'dog' ではなく、
tsquery型の外部表現である 'cat' <-> 'dog' であることに注意。
次にtsquery_phrase()だけを動かしてみた。
まず、tsquery_phrase の第3引数に10を設定して動かしてみる。
tsearch=# SELECT tsquery_phrase( to_tsquery('english', 'cat'), to_tsquery('english', 'dog'), 10); tsquery_phrase ------------------ 'cat' <10> 'dog' (1 row)
ふむ。それにしても、<10> というのは演算子なのか?
ただ、CREATE OPERATORを見るとわかるように、PostgreSQLの演算子として使用可能な文字は、
以下の文字に限定されているはず。
The operator name is a sequence of up to NAMEDATALEN-1 (63 by default) characters from the following list:
- - * / < > = ~ ! @ # % ^ & | ` ?
なので、<10> のように間に数字がはいるものは、「SQLの演算子」としては認められない。<10> のような演算子はあくまでも、tsquery_phrase() が生成した、tsquery型の記法として使われているだけだ。
次はdistanceに2を設定。
tsearch=# SELECT tsquery_phrase( to_tsquery('english', 'cat'), to_tsquery('english', 'dog'), 2); tsquery_phrase ----------------- 'cat' <2> 'dog' (1 row)
うむ。じゃあ、distanceに1を設定したら・・・?
tsearch=# SELECT tsquery_phrase( to_tsquery('english', 'cat'), to_tsquery('english', 'dog'), 1); tsquery_phrase ----------------- 'cat' <-> 'dog' (1 row)
!!!
なんと、1を設定したときには、 <1> ではなく <-> と解釈された。
つまり、
tsquery <-> tsquery
というのは、
tsquery_phrase(tsquery, tsquery, 1);
と同じ意味になる。
tsquery_phraseのdistanceが1のときには、実質上引数1に指定したキーワードと引数2に指定したキーワードが連続したという意味になる。
なので、<-> 演算子を使うとこーなる。
tsearch=# SELECT to_tsvector('Lion is a big cat. Cat is a small lion.') @@ (to_tsquery('cat') <-> to_tsquery('lion')); ?column? ---------- f (1 row)
cat と lion の間に別の語(small)が入っているために、一致しない(f)とみなされる。
tsearch=# SELECT to_tsvector('Lion is a big cat. Cat is a small lion.') @@ (to_tsquery('small') <-> to_tsquery('lion')); ?column? ---------- t (1 row)
この場合、small と lion は間に別の語が入らず連結しているので一致する(t)とみなされる。
to_tsquery()を使わずに全文検索する。
で、この検証をやってるときに
tsearch=# SELECT tsquery_phrase( to_tsquery('english', 'cat'), to_tsquery('english', 'dog'), 2); tsquery_phrase ----------------- 'cat' <2> 'dog' (1 row)
の結果を見て、ふと思った。
これ、tsqueryの外部表現を文字列として渡したら、to_tsquery()を使わなくても全文検索できるってことか?
やってみた。
tsearch=# SELECT to_tsvector('I like cats and dogs.') @@ '''cat'' <2> ''dog'''; ?column? ---------- t (1 row)
お、想定どおりの結果が返ってきたw
実際右辺の文字列は暗黙のキャストによって、tsquery型に変換されているはず。
まあ、面倒くさいだけなので、フツーに to_tsquery() や tsquery_phrase() を使ったほうがいいとは思うけど。