wir neue Spalte von tsvector
Typ hinzufügen:
alter table sites add column tsvector tsvector;
Lassen Sie uns nun einen Trigger erstellen, die Lexeme sammeln, organisieren sie und unsere tsvector setzen. Wir werden 4 Gruppen (A, B, C, D) verwenden - dies ist eine spezielle Tsvector-Funktion, mit der Sie Lexems später bei der Suche unterscheiden können (siehe Beispiele in Handbuch https://www.postgresql.org/docs/current/static/textsearch-controls.html; leider unterstützt diese Funktion nur bis zu 4 Gruppen becase für die Entwickler nur 2 Bits reserviert, aber wir sind hier glücklich, brauchen wir nur 4 Gruppen):
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();
^^ - navigieren Sie dieser Ausschnitt ist größer, als es aussieht (vor allem von Ihnen MacOS haben w/o Bildlaufleisten ...)
lassen Sie uns jetzt GIN Index erstellen Suchanfragen Speedup (macht Sinn, wenn Sie viele Zeilen haben - sagen wir, mehr als hundert oder tausend):
create index i_sites_fulltext on sites using gin(tsvector);
Und jetzt legen wir etwas zu überprüfen:
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;
prüfen mit select * from sites;
- Sie müssen sehen, dass tsvector
Spalte mit einigen Daten gefüllt ist.
machen wir es jetzt fragen:
select * from sites where tsvector @@ to_tsquery('simple', 'sample');
- es ist unser Rekord zurückkehren. In diesem Fall suchen wir nach 'sample'
Wort und es ist uns egal in welcher Gruppe es gefunden wird.
Sagen wir es ändern und versuchen, nur in der Gruppe A („SITE (Identifizierung, Titel, Adresse)“, wie Sie es beschrieben) suchen:
select * from sites where tsvector @@ to_tsquery('simple', 'sample:A');
- das muss nichts zurück, weil Wort 'sample'
nur sitzt in Gruppe D ("AUDIT (Beispiel_ID)"). In der Tat:
select * from sites where tsvector @@ to_tsquery('simple', 'sample:D');
- werden uns wieder unseren Rekord zurückgeben.
Beachten Sie, dass Sie to_tsquery(..)
, nicht plainto_tsquery(..)
verwenden müssen, um 4 Gruppen zu adressieren. Sie müssen also Ihre Eingaben selbst bereinigen (vermeiden Sie die Verwendung oder das Entfernen von Sonderzeichen wie &
und |
, da diese in tsquery
Werte eine besondere Bedeutung haben).
Und die gute Nachricht ist, dass man verschiedene Gruppen in einer einzigen Abfrage, wie folgt kombinieren:
ist mit
select * from sites where tsvector @@ to_tsquery('simple', 'sample:D & london:A');
Dem anderen Weg zu gehen (zB wenn Sie mit mehr als 4 Gruppen arbeiten) mehrere tsvectors, die jeweils in einer separaten Spalte sitzen, erstellen sie mit einer einzelnen Abfrage, erstellen einen Index (Sie können einen einzelnen Index für mehrere tsvector
Spalten erstellen) und die Adressierung separater Spalten abfragen. Es ist ähnlich dem, was ich oben erklärt habe, aber vielleicht weniger effizient.
Hoffe, das hilft.
Der erste Schuss wäre "denormalize" den Speicher: opfern einige Speicherstelle für die Kürze. Extrahieren Sie benötigte Daten in separaten Feldern: Site, Gebäude, Depot, Audit, die reine String-Kontantenation der benötigten Felder enthalten, zB 'building.identification || ';' || building.title || ';'|| building.address' etc . (Dies kann mit den Funktionen von Postgres als Standardwerte oder Trigger-basiert geschehen, wenn Ihre Daten geändert werden). Dann erstellen Sie GIN-Indizes für diese Felder -> und konstruieren Sie dann Ihre entsprechenden Volltext-Abfragen für diese Felder –
Danke @IlyaDyoshin. Ich mag deine Idee - werde versuchen, damit zu experimentieren. – rusllonrails
oder Sie können bis 10.0 Release warten - wo JSON/JSONB FTS wird erster Klasse Bürger sein https://www.postgresql.org/docs/10/static/release-10.html –