Postgres-Volltextsuche mit mehreren Spalten, warum im Index und nicht zur Laufzeit?


10

Ich bin in den letzten Tagen auf die Volltextsuche in Postgres gestoßen, und ich bin etwas verwirrt über die Indizierung, wenn ich über mehrere Spalten hinweg suche.

In den Postgres- Dokumenten wird beschriebents_vector , wie ein Index für verkettete Spalten erstellt wird:

CREATE INDEX pgweb_idx ON pgweb 
    USING gin(to_tsvector('english', title || ' ' || body));

was ich so suchen kann:

... WHERE 
      (to_tsvector('english', title||' '||body) @@ to_tsquery('english', 'foo'))

Wenn ich jedoch manchmal nur den Titel, manchmal nur den Text und manchmal beides suchen wollte, würde ich 3 separate Indizes benötigen. Und wenn ich in einer dritten Spalte hinzufüge, könnten das möglicherweise 6 Indizes sein und so weiter.

Eine Alternative, die ich in den Dokumenten nicht gesehen habe, besteht darin, die beiden Spalten getrennt zu indizieren und dann einfach eine normale WHERE...ORAbfrage zu verwenden:

... WHERE
      (to_tsvector('english', title) @@ to_tsquery('english','foo'))
    OR
      (to_tsvector('english', body) @@ to_tsquery('english','foo'))

Das Benchmarking der beiden in ~ 1 Million Zeilen scheint grundsätzlich keinen Leistungsunterschied zu haben.

Meine Frage lautet also:

Warum sollte ich solche Indizes verketten wollen, anstatt nur Spalten einzeln zu indizieren? Was sind die Vor- und Nachteile von beiden?

Meine beste Vermutung ist, dass ich, wenn ich im Voraus wüsste, dass ich immer nur beide Spalten durchsuchen möchte (niemals eine nach der anderen), immer nur einen Index durch Verketten benötigen würde, der weniger Speicher benötigt.


Ich bin mir nicht sicher, wie die Verkettung titlein bodyund die anschließende Indizierung viel Wert bringen würde, obwohl ich offen für Korrekturen bin. Ich würde mich wahrscheinlich nur daran halten, sie separat zu indizieren. Wenn es sich um ein verrücktes Einzelstück handelte, bei dem Sie sich irgendwie verketten mussten, können Sie die Abfrage wahrscheinlich einfach ad-hoc ausführen.
Swasheck

Sie haben Recht mit Ihrer Vermutung. Ich würde Sie ermutigen, sich selbst zu antworten, wenn es sonst niemand tut.
Jcolebrand

Antworten:


3

Nein, Sie benötigen keine separaten Indizes. Verwenden Sie die Gewichtsfunktion. Sie sind nur eine Bezeichnung, gegen die Sie abfragen können. Sie können bis zu vier Beschriftungen abfragen (AD).

--search any "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick'::tsquery; --true

--search B "field" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:B'::tsquery; --false

--search B or C "fields" for quick:
select 'quick:1A brown:2B quick:3C'::tsvector @@ 'quick:BC'::tsquery; --true

Möglicherweise möchten Sie tsvectors verketten, damit Sie sie separat mit Gewichten versehen und dann zusammenfügen können:

select
  setweight( name_column::tsvector, 'A') || setweight( phone_column::tsvector, 'B');

2

Eigentlich wäre die Alternative, wo mit ODER und nicht UND zu verwenden .

Wenn Sie einen Index für tsvector (body + title) haben und darin suchen, können gesuchte Wörter im Titel ODER im body sein.

Stellen Sie außerdem beim Testen sicher, dass die Tabelle eine angemessene Anzahl von Zeilen enthält.

Einfachster Fall, der einen guten Unterschied zeigen sollte: Finden Sie zwei Wörter - eines davon, das sehr wahrscheinlich im Titel enthalten ist. und der andere - das ist sehr wahrscheinlich im Körper. Stellen Sie jedoch sicher, dass nicht viele Zeilen beiden Kriterien entsprechen. Zum Beispiel - Sie könnten 30% des Wortes "depesz" im Körper haben. Sie haben auch eine Chance von ~ 30%, "mysql" im Titel zu haben. Es ist jedoch sehr unwahrscheinlich, dass "depesz und mysql" in einem der Felder in derselben Zeile vorhanden ist. Überprüfen Sie dann die Leistung mit solchen Indizes.


Ha, guter Ort, auf OR vs AND Ich werde die Frage aktualisieren. Ich habe es mit 1 Million Zeilen gemacht - konnte nicht die Mühe machen, darauf zu warten, dass weitere
eingefügt werden

1
Vielen Dank, dass Sie bei depesz vorbeigekommen sind - wir haben heutzutage einige Postgres-Fragen, also hoffe ich, dass Sie dabei bleiben :-)
Jack sagt, versuchen Sie es mit topanswers.xyz

@ Jack: Ich bin mir nicht sicher - ich fand Stackexchange-Sites immer weniger nutzbar. Ich versuche im Allgemeinen, RSS zu erhalten, aber auf Stackexchange-Sites ist RSS ziemlich nutzlos - so viel Verschmutzung durch die Ausgabe alter Fragen.

Ich habe einen RSS - Feed für Sie erstellt hier - sind Sie bereit , dass ein Versuch zu geben? Ich bin froh, die Mühe zu haben
, Dinge

Jack :) Ich werde beißen - abonniert.
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.