具有多列的 Postgres 全文搜索,为什么在索引中而不是在运行时连接?

lat*_*lip 14 postgresql index full-text-search

最近几天我在 postgres 中遇到了全文搜索,在跨多列搜索时我对索引有点困惑。

postgres文档讨论了ts_vector在连接列上创建索引,如下所示:

CREATE INDEX pgweb_idx ON pgweb 
    USING gin(to_tsvector('english', title || ' ' || body));
Run Code Online (Sandbox Code Playgroud)

我可以这样搜索:

... WHERE 
      (to_tsvector('english', title||' '||body) @@ to_tsquery('english', 'foo'))
Run Code Online (Sandbox Code Playgroud)

但是,如果我想有时只搜索标题,有时只搜索正文,有时两者都搜索,我将需要 3 个单独的索引。如果我添加了第三列,那可能是 6 个索引,依此类推。

我在文档中没有看到的另一种方法是单独索引两列,然后只使用普通WHERE...OR查询:

... WHERE
      (to_tsvector('english', title) @@ to_tsquery('english','foo'))
    OR
      (to_tsvector('english', body) @@ to_tsquery('english','foo'))
Run Code Online (Sandbox Code Playgroud)

在大约 100 万行上对两者进行基准测试似乎在性能上基本上没有差异。

所以我的问题是:

为什么我要像这样连接索引,而不是单独索引列?两者的优点/缺点是什么?

我最好的猜测是,如果我事先知道我只想搜索两列(一次从不搜索),我将只需要通过连接使用较少内存的一个索引。

Nei*_*gan 5

不,您不需要单独的索引。使用权重功能。它们只是您可以查询的标签。您最多可以有四个标签来查询 (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
Run Code Online (Sandbox Code Playgroud)

您可能想要连接 tsvectors,以便您可以分别对它们应用权重,然后将它们放在一起:

select
  setweight( name_column::tsvector, 'A') || setweight( phone_column::tsvector, 'B');
Run Code Online (Sandbox Code Playgroud)


小智 3

实际上,替代方法是将 where 与OR一起使用,而不是AND

如果您在 tsvector(body + title) 上有索引,并且正在其中搜索,则搜索的单词可以在标题正文中。

另外 - 测试时,请确保表中有合理的行数。

最简单的情况应该显示出良好的差异:找到两个单词 - 其中一个很可能出现在标题中。另一个——很可能是在身体里。但请确保没有太多行符合这两个条件。例如 - 正文中可能有 30% 的单词“depesz”。您还有大约 30% 的机会在标题中包含“mysql”。但是在同一行的任何字段中出现“depesz 和 mysql”的可能性很小。然后用这些索引检查性能。