【问题标题】:Postgres Large Text Search AdvicePostgres 大文本搜索建议
【发布时间】:2015-04-25 00:30:01
【问题描述】:

我对数据库很陌生,正在寻找一些高水平的建议。

情况
我正在使用 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 不等。

问题
我希望能够对“内容”列中的数据执行相当快速的文本搜索(例如,WHERE CONTENT LIKE '%some_error%')。现在搜索速度非常慢(搜索 8206 行需要 >10 分钟)。

我知道索引旨在解决我的问题,但我似乎无法创建索引 - 每当我尝试时都会收到索引太大的错误。

=# CREATE INDEX error_logs_content_idx ON 错误日志(内容 text_pattern_ops);
错误:索引行需要 1796232 字节, 最大尺寸为 8191

我希望得到一些关于如何解决这个问题的建议。我可以更改最大索引大小吗?还是我不应该尝试使用 Postgres 对这么大的文本字段进行全文搜索?

非常感谢任何建议!

【问题讨论】:

  • 我想你可能正在寻找全文搜索/索引postgresql.org/docs/9.1/static/textsearch-intro.html
  • 这个答案也可能有帮助,stackoverflow.com/questions/1566717/…
  • 嗨,约翰,感谢您的建议。我已经浏览了 textsearch 文档,但找不到任何关于索引限制的信息。您发布的第二条评论描述了创建一个 text_pattern_ops 索引,正如我上面提到的,它返回一个关于索引太大的错误。
  • 您希望使用 gin 或 gist 索引,而不是使用 text_pattern_ops 的 B-tree。为错误的链接道歉。
  • 在包含非常大单词的字符串上使用 to_tsvector 时,我收到通知,而不是错误。尽管如果您的内容包含超过 2047 个字符的单词,我不得不怀疑它是否不是真正的二进制数据,这可能意味着它可能包含会导致问题的 \0 字符。

标签: postgresql


【解决方案1】:

文本搜索向量无法处理这么大的数据 --- 请参阅 documented limits。它们的优势是模糊搜索,因此您可以在同一个调用中搜索“游泳”并找到“游泳”、“游泳”、“游泳”和“游泳”。它们并不是要取代grep

限制的原因在 source code 中作为 MAXSTRLEN(和 MAXSTRPOS)。文本搜索向量存储在一个长达 1 MiB 的长连续数组中(所有唯一词位的所有字符的总和)。要访问这些,ts_vector 索引结构允许 11 位用于字长,20 位用于其在数组中的位置。这些限制允许索引结构适合 32 位无符号整数。

如果您在文件中有太多独特的词或词非常频繁地重复,您可能会遇到这些限制之一或两者——如果您有 50MB 的日志文件和准随机数据,这很可能发生。

您确定需要将日志文件存储在数据库中吗?您基本上是在复制文件系统,greppython 可以很好地在那里进行搜索。不过,如果你真的需要,你可以考虑这个:

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

【讨论】:

  • 非常感谢您的建议。我已经切换到每行存储一个日志行。不过,我还没有尝试过索引——只是试过了,效果很好。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 2015-03-30
  • 1970-01-01
  • 2011-04-04
相关资源
最近更新 更多