2015-01-15 14 views
6

Ich bin ziemlich neu in Datenbanken, und bin auf der Suche nach einem hohen Niveau Beratung.Postgres Large Text Search Beratung

Die Situation
Ich baue eine Datenbank Postgres 9.3, in der Datenbank ist eine Tabelle, in der ich Log-Dateien speichern.

CREATE TABLE errorlogs (
    id SERIAL PRIMARY KEY, 
    archive_id INTEGER NOT NULL REFERENCES archives, 
    filename VARCHAR(256) NOT NULL, 
    content TEXT); 

Der Text in Inhalt in der Länge von 1k bis 50MB überall variieren kann.

Das Problem
Ich mag würde in der Lage sein einigermaßen schnellen Textsuche auf den Daten innerhalb der „Inhalt“ Spalte ausführen (zB WHERE CONTENT LIKE '% some_error%). Derzeit sind die Suchvorgänge sehr langsam (> 10 Minuten, um 8206 Zeilen zu durchsuchen).

Ich weiß, dass die Indizierung die Lösung für mein Problem sein soll, aber ich kann anscheinend keine Indizes erstellen - wenn ich versuche, bekomme ich Fehler, dass der Index zu groß wäre.

=# CREATE INDEX error_logs_content_idx ON errorlogs (content text_pattern_ops);
ERROR: index row requires 1796232 bytes, maximum size is 8191

Ich hoffte auf einen Ratschlag, wie man dieses Problem umgehen kann. Kann ich die maximale Indexgröße ändern? Oder sollte ich nicht versuchen, Postgres für die Volltextsuche in so großen Textfeldern zu verwenden?

Jeder Rat wird sehr geschätzt!

+2

Ich glaube, Sie wahrscheinlich suchen Volltextsuche/Indizierung http://www.postgresql.org/docs/9.1/static/textsearch-intro.html. –

+1

Diese Antwort könnte auch helfen, http://stackoverflow.com/questions/1566717/postgresql-like-query-performance-variations/13452528#13452528 –

+0

Hallo John, danke für den Rat. Ich habe die Textsuchdokumente bereits durchgelesen und konnte keine Informationen zu den Indexeinschränkungen finden.Der zweite Kommentar, den Sie gepostet haben, beschreibt die Erstellung eines text_pattern_ops-Indexes, der, wie oben erwähnt, einen Fehler über den Index zurückgibt, der zu groß ist. – JBeFat

Antwort

2

Textsuchvektoren können nicht mit so großen Daten umgehen --- siehe documented limits. Ihre Stärke ist die unscharfe Suche, so dass Sie im selben Ruf nach "schwimmen" und "schwimmen", "schwimmen", "schwammen" und "schwimmen" suchen können. Sie sollen nicht grep ersetzen.

Der Grund für die Grenzen sind in der source code als MAXSTRLEN (und MAXSTRPOS). Textsuchvektoren werden in einem langen, kontinuierlichen Array mit einer Länge von bis zu 1 MiB gespeichert (Summe aller Zeichen für alle eindeutigen Lexeme). Um auf diese zuzugreifen, erlaubt die ts_vector-Indexstruktur 11 Bits für die Wortlänge und 20 Bits für ihre Position in dem Array. Diese Grenzwerte ermöglichen es, dass die Indexstruktur in einen 32-Bit-unsigned-int passt.

Wahrscheinlich stoßen Sie auf eine oder beide dieser Grenzen, wenn Sie entweder zu viele eindeutige Wörter in einer Datei haben oder Wörter sehr häufig wiederholt werden --- etwas durchaus möglich, wenn Sie 50MB Protokolldatei mit quasizufälligen Daten haben.

Sind Sie sicher, dass Sie Protokolldateien in einer Datenbank speichern müssen? Sie replizieren im Grunde das Dateisystem, und grep oder python können die Suche dort ziemlich nett tun. Wenn Sie wirklich brauchen, aber könnten Sie dies:

CREATE TABLE errorlogs (
    id SERIAL PRIMARY KEY 
    , archive_id INTEGER NOT NULL REFERENCES archives 
    , filename VARCHAR(256) NOT NULL 
); 

CREATE TABLE log_lines (
    line PRIMARY KEY 
    , errorlog INTEGER REFERENCES errorlogs(id) 
    , context TEXT 
    , tsv TSVECTOR 
); 

CREATE INDEX log_lines_tsv_idx ON log_lines USING gin(line_tsv); 

Hier behandeln Sie jede Linie als log „Dokument“. Zu suchen, würde tun Sie so etwas wie

SELECT e.id, e.filename, g.line, g.context 
FROM errorlogs e JOIN log_lines g ON e.id = g.errorlog 
WHERE g.tsv @@ to_tsquery('some & error'); 
+0

Vielen Dank für den Vorschlag. Ich habe seitdem auf eine einzelne Logzeile pro Zeile umgestellt. Ich habe es noch nicht versucht, Indexierung - nur versucht, und es funktioniert gut. Danke noch einmal! – JBeFat