2015-01-15 3 views
6

Я довольно новичок в базах данных, и я ищу советы на высоком уровне.Postgres Large Text Search Advice

Ситуация
Я создание базы данных с помощью Postgres 9.3, в базе данных представляет собой таблицу, в которой я храню файлы журналов.

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

Текст в тексте может варьироваться от 1k до 50MB.

Проблема
Я хотел бы быть в состоянии выполнить достаточно быстро полнотекстовый поиск по данным в столбце «содержание» (например, когда содержание LIKE «% some_error%»). Сейчас поиск выполняется очень медленно (> 10 минут для поиска по 8206 строкам).

Я знаю, что индексирование предназначено для решения моей проблемы, но, похоже, я не могу создавать индексы - всякий раз, когда я пытаюсь получить ошибки, индекс будет слишком большим.

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

Я надеялся на некоторые советы о том, как обойти эту проблему. Могу ли я изменить максимальный размер индекса? Или я не должен пытаться использовать Postgres для полнотекстового поиска в текстовых полях размером с это?

Любые советы очень ценятся!

+2

Я думаю, что вы, вероятно, ищет для полнотекстового поиска/индексации http://www.postgresql.org/docs/9.1/static/textsearch-intro.html. –

+1

Этот ответ также может помочь, http://stackoverflow.com/questions/1566717/postgresql-like-query-performance-variations/13452528#13452528 –

+0

Привет, Джон, спасибо за совет. Я уже прошел через документы по поиску текстов, и я не смог найти никакой информации об ограничениях индекса.Второй комментарий, который вы опубликовали, описывает создание индекса text_pattern_ops, который, как я упоминал выше, возвращает ошибку об слишком большом индексе. – JBeFat

ответ

2

Текстовые поисковые векторы не могут обрабатывать данные, такие большие --- см. documented limits. Их сила - нечеткий поиск, поэтому вы можете искать «плавать» и находить «плавать», «плавать», «плавать» и «плавать» по тому же призыву. Они не предназначены для замены grep.

Причины ограничений указаны в source code как MAXSTRLEN (и MAXSTRPOS). Текстовые поисковые векторы хранятся в одном длинном непрерывном массиве длиной до 1 мегабайта (всего всех символов для всех уникальных лексем). Для доступа к ним структура индекса ts_vector допускает 11 бит для длины слова и 20 бит для его позиции в массиве. Эти ограничения позволяют структуре индекса вписываться в 32-битный беззнаковый int.

Вы, вероятно, работаете в одном или обоих этих ограничениях, если в файле слишком много уникальных слов, или слова повторяются очень часто - что-то вполне возможно, если у вас есть файл журнала 50 МБ с квазислучайными данными.

Вы уверены, что вам нужно хранить файлы журналов в базе данных? Вы в основном копируете файловую систему, и grep или python можете выполнить поиск там довольно хорошо. Если вам действительно нужно, однако, вы могли бы рассмотреть это:

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); 

Здесь вы обрабатываете каждое бревно линию как «документ». Для поиска, вы могли бы сделать что-то вроде

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

Большое спасибо за предложение. С тех пор я перешел на сохранение одной строки журнала в строке. Я еще не пробовал индексировать - просто попробовал это, и он работает красиво. Еще раз спасибо! – JBeFat