はのはtsvector
タイプの新しい列を追加してみましょう:
alter table sites add column tsvector tsvector;
は、今度は、lexemsを収集し、それらを整理し、私たちのtsvectorに置くトリガーを作成してみましょう。私たちは4つのグループ(A、B、C、D)を使用します - これは後で検索時にレクセルを区別できる特別なtsvectorの機能です(マニュアルhttps://www.postgresql.org/docs/current/static/textsearch-controls.htmlの例を参照してください;残念ながらこの機能は最大4つのグループのみをサポートします)開発者)は、そのための唯一の2ビットを予約し、私たちはここにラッキーです、我々は唯一の4つのグループが必要になります。
create or replace function t_sites_tsvector() returns trigger as $$
declare
dic regconfig;
part_a text;
part_b text;
part_c text;
part_d text;
begin
dic := 'simple'; -- change if you need more advanced word processing (stemming, etc)
part_a := coalesce(new.doc->>'identification', '') || ' ' || coalesce(new.doc->>'title', '') || ' ' || coalesce(new.doc->>'address', '');
select into part_b string_agg(coalesce(a, ''), ' ') || ' ' || string_agg(coalesce(b, ''), ' ')
from (
select
jsonb_array_elements((new.doc->'buildings'))->>'identification',
jsonb_array_elements((new.doc->'buildings'))->>'name'
) _(a, b);
select into part_c string_agg(coalesce(c, ''), ' ')
from (
select jsonb_array_elements(b)->>'identification' from (
select jsonb_array_elements((new.doc->'buildings'))->'deposits'
) _(b)
) __(c);
select into part_d string_agg(coalesce(d, ''), ' ')
from (
select jsonb_array_elements(c)->>'sample_id'
from (
select jsonb_array_elements(b)->'audits' from (
select jsonb_array_elements((new.doc->'buildings'))->'deposits'
) _(b)
) __(c)
) ___(d);
new.tsvector := setweight(to_tsvector(dic, part_a), 'A')
|| setweight(to_tsvector(dic, part_b), 'B')
|| setweight(to_tsvector(dic, part_c), 'C')
|| setweight(to_tsvector(dic, part_d), 'D')
;
return new;
end;
$$ language plpgsql immutable;
create trigger t_sites_tsvector
before insert or update on sites for each row execute procedure t_sites_tsvector();
^^ - このスニペットは、それがのw/MacOSのを持っている(特にあなたの見た目よりも大きいですが、それをスクロールします
:)数百または数千以上、言う - Oスクロールバー...)
今(あなたは多くの行を持っている場合は理にかなっているのは、検索クエリを高速化するためにGINインデックスを作成してみましょう
create index i_sites_fulltext on sites using gin(tsvector);
そして今、私たちは何かを確認するために挿入します。
insert into sites select 1, '{
"_id": "123",
"type": "Site",
"identification": "Custom ID",
"title": "SITE 1",
"address": "UK, London, Mr Tom''s street, 2",
"buildings": [
{
"uuid": "12312",
"identification": "Custom ID",
"name": "BUILDING 1",
"deposits": [
{
"uuid": "12312",
"identification": "Custom ID",
"audits": [
{
"uuid": "12312",
"sample_id": "SAMPLE ID"
}
]
}
]
}
]
}'::jsonb;
チェックselect * from sites;
で - あなたはtsvector
列は、いくつかのデータで満たされていることを確認しなければなりません。
今度はそれを照会してみましょう:
select * from sites where tsvector @@ to_tsquery('simple', 'sample');
- それが私たちのレコードを返す必要があります。この場合、'sample'
という単語が検索され、検索されるグループはわかりません。
のは、それを変更し、グループのみA(「SITE(識別、タイトル、アドレス)」あなたはそれを説明するように)で検索してみましょう:
select * from sites where tsvector @@ to_tsquery('simple', 'sample:A');
- 単語'sample'
だけで座っているので、これは何も返さない必要がありますグループD(「AUDIT(sample_id)」)。確かに:
- 私たちの記録は再び私たちに返されます。
4グループをアドレス指定できるようにするには、to_tsquery(..)
ではなく、plainto_tsquery(..)
を使用する必要があることに注意してください。したがって、入力内容を自分で消毒する必要があります(&
と|
のような特殊文字を使用または削除しないでください。特別な意味はtsquery
の値なので)。
そして、良いニュースは、あなたがこのように、単一のクエリで異なるグループを組み合わせることができるということです。(あなたが4つの以上のグループで作業する必要がある場合など)に行くために
select * from sites where tsvector @@ to_tsquery('simple', 'sample:D & london:A');
他の方法を持っていますそれぞれ別々の列に置かれた複数のtsベクトルは、単一のクエリを使用して構築し、インデックスを作成します(複数のtsvector
列に単一のインデックスを作成できます)。それは私が上で説明したものと似ていますが、おそらくそれほど効率が悪いでしょう。
これが役に立ちます。
最初のショットはストレージを「非正規化」します。簡潔にするために保存場所を犠牲にします。必要なフィールドの純粋な文字列の連結を含む、サイト、ビルディング、デポジット、監査、別々のフィールドで必要なデータを抽出する: 'building.identification || ';' || building.title || ';'|| building.address'これはpostgresの関数をデフォルト値として使用するか、データが変更された場合はトリガベースで行うことができます。これらのフィールドにGINインデックスを作成してから、それらのフィールドに対応するフルテキストクエリを作成してください。 –
ありがとう@IlyaDyoshin。私はあなたの考えが好きです - それを実験しようとします。 – rusllonrails
または10.0リリースまで待つことができます - json/jsonb FTSはファーストクラスの市民になりますhttps://www.postgresql.org/docs/10/static/release-10.html –