Supabase で 日本語 類似文書検索
Supabaseでは拡張機能としてPGroonga
(ぴーじーるんが)を利用することができます。
このPGroongaが提供する&@*
演算子を用いることで類似した文章を検索することができます。
PGroonga を有効にする
Database > Extensions よりpgroonga
の拡張機能を有効化します。
今後はextensions
スキーマでも利用出来るようになるそうです。
(PGroonga 作者の須藤さんのツイートより引用)
対象テーブルにインデックスを貼る
SQL Editorよりインデックスを作成します。
ここで使用しているテーブルスキーマ
CREATE TABLE books (
id integer not null,
title character varying not null,
content text not null
);
PGroongaで演算子を利用するには正しい演算子クラスでインデックスを張る必要があります。
演算子クラス
この演算子を使うには次のどれかの演算子クラスを指定する必要があります。
pgroonga_text_full_text_search_ops_v2
:text
型のデフォルト
pgroonga_text_array_full_text_search_ops_v2
:text[]
型のデフォルト
pgroonga_varchar_full_text_search_ops_v2
:varchar
用
今回のテーブル設計ではcontent
カラムはtext
型なのでデフォルトで指定されている演算子クラスで問題なく、以下のようなsqlでインデックスを張ることができます。
CREATE INDEX pgroonga_varchar_content_index ON books
USING pgroonga (content)
With (tokenizer = 'TokenMecab');
ですが、title
カラムはvarchar
なので、こちらで指定してインデックスを張る必要があります。
CREATE INDEX pgroonga_varchar_content_index ON books
USING pgroonga (title pgroonga_varchar_full_text_search_ops_v2)
With (tokenizer = 'TokenMecab');
(title pgroonga_varchar_full_text_search_ops_v2)
のようにtitle
カラムに適切な演算子クラスを指定しています。
ここで、tokenizer = 'TokenMecab'
としていますが、日本語の文書を類似文書検索する場合はデフォルトのTokenBigram
ではなくTokenMecab
を使う方がよいためです。
TokenMecabは対象の文書を(ほぼ)単語にトークナイズします。これにより類似文書検索の精度が上がります。
データ取得
サンプルデータ
INSERT INTO books VALUES (1, 'PostgreSQL', 'PostgreSQLはリレーショナル・データベース管理システムです。');
INSERT INTO books VALUES (2, 'Groonga', 'Groongaは日本語対応の高速な全文検索エンジンです。');
INSERT INTO books VALUES (3, 'PGroonga', 'PGroongaはインデックスとしてGroongaを使うためのPostgreSQLの拡張機能です。');
INSERT INTO books VALUES (4, 'groonga', 'groongaコマンドがあります。');
SELECT * FROM books WHERE content &@* 'MroongaはGroongaを使うMySQLの拡張機能です。';
無事類似文書検索ができるようになりました🎉
エラーが出る際は正しくインデックスが貼れているか、拡張機能が有効化されているかなどを確認してみてください。
Jsから取得
おそらく現状supabaseのjsクライアントライブラリから上記のようなクエリを投げることはできません。そのため、ストアドファンクションを定義して、それをjsからRPCで呼び出す必要があります。
以下のようなファンクションを定義し、
CREATE OR REPLACE FUNCTION get_similar_books(text varchar)
RETURNS RECORD AS
$$
DECLARE
rec books;
BEGIN
SELECT INTO rec * FROM books WHERE content &@* text;
RETURN rec;
END;
$$
LANGUAGE 'plpgsql';
jsからは以下の様にrpcで呼び出しましょう
const { data, error } = await createClient<Database>(url, key).rpc(
'get_similar_books',
{
text: 'MroongaはGroongaを使うMySQLの拡張機能です。',
}
)
間違いありましたらコメントにてお願いいたしますm(__)m
参考
Discussion