これはPGroonga 2.0.0以降用のドキュメントです。PGroonga 1.Xを使っているならPGroonga 1.Xのドキュメントを見てください。
pgroonga_condition() 関数3.1.6で追加。
pgroonga_condition()関数はpgroonga_condition型の値を返します。
関数名と型名が同じですが別物です。
pgroonga_condition型はpgroonga_full_text_search_condition型やpgroonga_full_text_search_condition_with_scorers型のように複雑な条件式を表現します。
pgroonga_condition()関数はpgroonga_condition型の値を作るための便利関数です。
特定の属性値のみを指定してpgroonga_condition型の値を作れます。
pgroonga_full_text_search_condition型やpgroonga_full_text_search_condition_with_scorers型では、このような便利関数がなかったため必ず全ての属性値を指定して値を作る必要がありました。
したがって、不要な属性値があっても、pgroonga_full_text_search_condition型やpgroonga_full_text_search_condition_with_scorers型では、次のように不要な属性値にはNULLを指定する必要がありました。
title &@~ ('keyword', NULL, 'index_name')::pgroonga_full_text_search_condition
title &@~ ('keyword', ARRAY[1,1,1,5,0], NULL, 'index_name')::pgroonga_full_text_search_condition_with_scorers
型を指定して直接値を作る従来の方法では後方互換性を維持したまま新しい属性を作ることができませんでした。
そのため、新しい属性を追加するたびにpgroonga_full_text_search_condition_with_XXXというような新しい型を追加する必要がありました。
たとえば、pgroogna_full_text_search_condition_with_scorers型はそのために追加された型です。
pgroonga_full_text_search_condition型とpgroonga_full_text_search_condition_with_scorers型の違いはscorersが存在するかどうかですが、pgroonga_full_text_search_condition型にscorersを追加してしまうと、scorersを使わないユーザーも新たにNULLを挿入してpgroonga_full_text_search_condition型の値を作らなければなりません。
しかし、pgroonga_condition型の値を作るための便利関数pgroonga_condition()関数を導入することにより後方互換性を維持したままpgroonga_condition型に新しい属性を追加できます。
pgroonga_condition()関数が非互換を吸収してくれるからです。
次のように、pgroonga_condition()関数は不要な属性値を省略できるため、新たに属性値が追加されても既存の書き方を維持できます。
(次の例では、weights、scorers、schema_name、column_nameを省略しています。属性値の詳細については、後述の「構文」で記載します。ここでは、不要な属性値が省略できることに注目してください。)
title &@~ pgroonga_condition('keyword', index_name => 'index_name')
pgroonga_condition()関数では、上のように属性値を省略できますが、代わりに、「index_name => 'index name'」のようにキーワード引数のような記載が必要になることに注意してください。
上の例では、キーワード引数のような書き方をしている属性値とそうでない属性値があります。 どのように書き分けるかについては、後述の「構文」で記載します。 ここでは、従来とは異なる書き方が必要になることがあるという点に注目してください。
この関数の構文は次の通りです。
pgroonga_condition pgroonga_condition(keyword,
weights,
scorers,
schema_name,
index_name,
column_name,
fuzzy_max_distance_ratio)
keywordは全文検索で使うキーワードです。text型です。
weightsは、検索対象のカラムの重要度です。int[]型です。
scorersは、検索対象のカラムのスコアーを計算するスコアラーです。text[]型です。
schema_nameは、シーケンシャルサーチ実行時に参照するインデックスが属するスキーマの名前です。text型です。
index_nameは、シーケンシャルサーチ実行時に参照するインデックスの名前です。text型です。
column_nameは、シーケンシャルサーチ実行時に参照するインデックス内のカラムの名前です。text型です
fuzzy_max_distance_ratioは編集距離の割合です。float4型です。(3.2.1で追加。)
詳しくはGroongaのfuzzy_max_distance_ratioオプションをご覧ください。
pgroonga_condition()の引数はすべて省略可能です。引数の位置に依らずに、特定の引数を指定したい場合は引数名 => 値という名前付き表記が使えます。たとえば、引数にindex_nameだけ指定する場合はpgroonga_condition(index_name => 'index1')となります。
一般的なユースケースでは次の3種類の書き方を覚えておけば十分です。
pgroonga_condition('keyword', index_name => 'pgroonga_index')
pgroonga_condition('keyword', ARRAY[weight1, weight2, ...])
pgroonga_condition('keyword', ARRAY[weight1, weight2, ...], index_name => 'pgroonga_index')
上の例以外の使い方をする場合のために、引数名 => 値で記述する必要がある引数とそうでない引数の違いについては、関数呼び出しを参照してください。
index_nameを指定するシーケンシャルサーチ実行時でも、インデックスに指定したノーマライザーやトークナイザーのオプションを使って検索する方法を紹介します。
pgroonga_condition('keyword', index_name => 'pgroonga_index')を使います。
index_nameにノーマライザーやトークナイザーを指定したインデックスの名前を指定します。
サンプルスキーマとデータは次の通りです。
CREATE TABLE tags (
name text PRIMARY KEY
);
CREATE INDEX pgroonga_tag_name_index ON tags
USING pgroonga (name pgroonga_text_term_search_ops_v2)
WITH (normalizers='NormalizerNFKC150("remove_symbol", true)');
INSERT INTO tags VALUES ('PostgreSQL');
INSERT INTO tags VALUES ('Groonga');
INSERT INTO tags VALUES ('PGroonga');
INSERT INTO tags VALUES ('pglogical');
インデックスサーチ時はインデックスに指定したオプションを使ってインデックスサーチ時の挙動をカスタマイズできます。
上のサンプルでは、normalizers='...'の部分でオプションを指定しています。
一方、インデックスサーチではなくシーケンシャルサーチが実行されると、インデックスに指定されているオプションは参照できません。 シーケンシャルサーチ時はどのインデックスを参照すればよいかという情報がないからです。
そのためシーケンシャルサーチ実行時は、インデックスサーチ実行時と検索結果が異なる可能性があります。
この問題を回避するためにシーケンシャルサーチ時に参照するインデックスを明示的に指定します。
pgroonga_condition()のindex_name => '...'がそのための引数です。
次の例は、「_p_G」というキーワードで前方一致検索をしており、インデックスにはNormalizerNFKC150("remove_symbol", true)が設定されています。
remove_symbolは記号を無視するオプションなので、「_p_G」は「pg」にノーマライズされます。
(大文字が小文字になっているのは、remove_symbolオプションの挙動ではなく、NormalizerNFKC150のデフォルトの挙動によるものです。)
そのため、このオプションが有効であれば、「PGroonga」と「pglogical」がヒットします。
次の例は、シーケンシャルサーチですが、「PGroonga」と「pglogical」がヒットしていることが確認できます。
このことから、シーケンシャルサーチ実行時でもインデックスに設定されているNormalizerNFKC150("remove_symbol", true)が参照できていることが確認できます。
EXPLAIN ANALYZE
SELECT *
FROM tags
WHERE name &^ pgroonga_condition('_p_G',
index_name => 'pgroonga_tag_name_index');
QUERY PLAN
--------------------------------------------------------------------------------------------------
Seq Scan on tags (cost=0.00..1043.60 rows=1 width=32) (actual time=2.267..2.336 rows=2 loops=1)
Filter: (name &^ '(_p_G,,,,pgroonga_tag_name_index,)'::pgroonga_condition)
Rows Removed by Filter: 2
Planning Time: 0.871 ms
Execution Time: 2.352 ms
(5 rows)
SELECT *
FROM tags
WHERE name &^ pgroonga_condition('_p_G',
index_name => 'pgroonga_tag_name_index');
name
-----------
PGroonga
pglogical
(2 rows)
index_nameを指定しない場合(つまり、NormalizerNFKC150("remove_symbol", true)が参照できない場合)は、次のように「PGroonga」と「pglogical」はヒットしません。
EXPLAIN ANALYZE
SELECT *
FROM tags
WHERE name &^ pgroonga_condition('_p_G');
QUERY PLAN
--------------------------------------------------------------------------------------------------
Seq Scan on tags (cost=0.00..1043.60 rows=1 width=32) (actual time=0.032..0.032 rows=0 loops=1)
Filter: (name &^ '(_p_G,,,,,)'::pgroonga_condition)
Rows Removed by Filter: 4
Planning Time: 0.910 ms
Execution Time: 0.053 ms
(5 rows)
SELECT *
FROM tags
WHERE name &^ pgroonga_condition('_p_G');
name
------
(0 rows)
このように、index_nameを指定することで、シーケンシャルサーチ実行時でもインデックスサーチ実行時でも検索結果が変わらないようにできます。
weightsを指定するカラム毎に異なるweight(重要度)を設定する方法を紹介します。 これにより、「タイトルを本文よりも重要視する」を実現できます。
pgroonga_condition('keyword', ARRAY[weight1, weight2, ...]) を使います。
weight1、 weight2でカラム毎の重要度を指定します。
サンプルスキーマとデータは次の通りです。
DROP TABLE IF EXISTS memos;
CREATE TABLE memos (
title text,
content text
);
CREATE INDEX pgroonga_memos_index
ON memos
USING pgroonga ((ARRAY[title, content]));
INSERT INTO memos VALUES ('PostgreSQL', 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO memos VALUES ('Groonga', 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO memos VALUES ('PGroonga', 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO memos VALUES ('コマンドライン', 'groongaコマンドがあります。');
指定したクエリーによりマッチしたレコードを探すためにはpgroonga_score functionを使えます。
SELECT *, pgroonga_score(tableoid, ctid) AS score
FROM memos
WHERE ARRAY[title, content] &@~
pgroonga_condition('Groonga OR PostgreSQL', ARRAY[5, 1])
ORDER BY score DESC;
title | content | score
----------------+---------------------------------------------------------------------------+-------
Groonga | Groongaは日本語対応の高速な全文検索エンジンです。 | 6
PostgreSQL | PostgreSQLはリレーショナル・データベース管理システムです。 | 6
PGroonga | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。 | 2
コマンドライン | groongaコマンドがあります。 | 1
(4 rows)
上の例では、ARRAY[title, content] &@~ pgroonga_condition('Groonga OR PostgreSQL', ARRAY[5, 1])と指定しているので、タイトルが本文より5倍重要としています。
titleカラムに「Groonga」または「PostgreSQL」があるレコードの方がcontentカラムに「Groonga」または「PostgreSQL」がある方よりスコアーが高いことを確認できます。
特定のカラムを検索対象から除外して検索する方法を紹介します。
pgroonga_condition('keyword', ARRAY[weight1, weight2, ...])を使います。
検索対象から除外したいカラムに対応するweightに0を指定します。
サンプルスキーマとデータは次の通りです。
DROP TABLE IF EXISTS memos;
CREATE TABLE memos (
title text,
content text
);
CREATE INDEX pgroonga_memos_index
ON memos
USING pgroonga ((ARRAY[title, content]));
INSERT INTO memos VALUES ('PostgreSQL', 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO memos VALUES ('Groonga', 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO memos VALUES ('PGroonga', 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO memos VALUES ('コマンドライン', 'groongaコマンドがあります。');
次の例では、contentカラムを検索対象から除外しています。
「拡張」というキーワードで全文検索しているので、contentカラムを検索対象としていれば、'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。'がヒットするはずですが、このレコードはヒットしていません。
このことから、contentカラムが検索対象から除外されていることを確認できます。
SELECT *
FROM memos
WHERE ARRAY[title, content] &@~
pgroonga_condition('拡張', ARRAY[1, 0]);
title | content
-------+---------
(0 rows)
次のように、contentカラムを検索対象にすると'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。'がヒットします。
SELECT *
FROM memos
WHERE ARRAY[title, content] &@~
pgroonga_condition('拡張', ARRAY[1, 1]);
title | content
----------+---------------------------------------------------------------------------
PGroonga | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。
(1 row)
タイプミスを許容した検索方法を紹介します。 ユーザはしばしばタイプミスをします。タイプミスを許容した検索を行うことで、よりよい検索体験を提供することができます。
pgroonga_condition('keyword', fuzzy_max_distance_ratio => ratio)を使います。
許容するタイプミスの文字数はratioによって変わります。許容するタイプミスの文字数の計算についてはGroongaのドキュメントに解説があるのでそちらをご覧ください。通常はratioに0.34を設定しておけば良いです。
サンプルスキーマとデータは次の通りです。
DROP TABLE IF EXISTS memos;
CREATE TABLE memos (
title text,
content text
);
CREATE INDEX pgroonga_memos_index
ON memos
USING pgroonga ((ARRAY[title, content]));
INSERT INTO memos VALUES ('PostgreSQL', 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO memos VALUES ('Groonga', 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO memos VALUES ('PGroonga', 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO memos VALUES ('コマンドライン', 'groongaコマンドがあります。');
以下はMoronga(2文字のタイプミス)でGroongaを検索する例です。もちろん、そのまま検索してもヒットしません。
SELECT *
FROM memos
WHERE ARRAY[title, content] &@~
pgroonga_condition('Moronga');
title | content
-------+---------
(0 rows)
fuzzy_max_distance_ratioオプションを使うことでGroongaを含むレコードがヒットします。
SELECT *
FROM memos
WHERE ARRAY[title, content] &@~
pgroonga_condition(
'Moronga',
fuzzy_max_distance_ratio => 0.34
);
title | content
----------------+---------------------------------------------------------------------------
Groonga | Groongaは日本語対応の高速な全文検索エンジンです。
PGroonga | PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。
コマンドライン | groongaコマンドがあります。
(3 rows)
Groongaを検索するときに0.34が設定されているとタイプミスは2文字まで許容されるため、このような結果になります。0.2を設定するとタイプミスは1文字までになるためヒットしなくなります。