当语言依赖于行时,高效的全文搜索

时间:2014-02-17 16:43:18

标签: sql postgresql full-text-search postgresql-9.2

为了这个问题,我有两张桌子:

CREATE TABLE room (
    id serial primary key,
    lang varchar(12) NOT NULL default 'english'
);

CREATE TABLE message (
    id bigserial primary key,
    room integer references room(id),
    content text NOT NULL
);

我希望通过语言相关标记化进行全文搜索:消息的标记化及其搜索必须取决于房间的语言。

完全未经优化和无索引的搜索将是这样的:

select message.id, content, lang from message, room
where message.room=room.id
and to_tsvector(lang::regconfig, content)
   @@ plainto_tsquery(lang::regconfig,'what I search')
and room=33;

搜索查询总是在一个独特的房间内完成(因此语言是同质的)。

现在我的问题是如何有效地做到这一点?我无法直接构建表达式索引,因为索引中使用的表达式必须是“不可变的”(仅依赖于索引行)。

如果我想要一个索引,那么创建一个包含to_tsvector(lang::regconfig, content)(并使用触发器维护)的新列是唯一合理的解决方案吗?

这是最有效的吗?

2 个答案:

答案 0 :(得分:2)

如果您知道语言和房间之间的关联没有变化,您可以通过IMMUTABLE函数将此信息提供给Postgres。

CREATE OR REPLACE FUNCTION room_lang(int)
RETURNS varchar(12) AS
$$
   SELECT lang FROM room WHERE id = $1
$$ LANGUAGE sql IMMUTABLE;

并将其用于partial indexes

CREATE INDEX idx_en ON message ...
WHERE room_lang(room) = 'english';

CREATE INDEX idx_es ON message ...
WHERE room_lang(room) = 'spanish';

当然,你必须重新创建任何这样的索引,如果你在room中改变了违反" immutability"的承诺,从而破坏了索引......

为查询使用兼容的WHERE子句让Postgres知道它可以使用索引:

SELECT ...
WHERE room_lang(room) = 'english';

以下是具有IMMUTABLE功能的索引的相关示例,其中包含更多详细信息:
Does PostgreSQL support "accent insensitive" collations?

除此之外:我宁愿只使用text instead of varchar(12)

答案 1 :(得分:-3)

在MS SQL中,我们获得了全文搜索,但我不知道Postgres是否有类似内容。如果你的RDBMS没有提供我一年前创建的解决方案。 当时我们无法激活共享服务器中的FTS我的客户端租用。 所以我创建了一个完整的定制解决方案。

我在解决方案中写了一篇文章: SQL Server Central

(Obs:你需要创建一个免费帐户才能看到这篇文章)

该解决方案是为MS Sql编写的,但我敢打赌它可以轻松移植到Postgres

还发布了一个例子: SQL Fiddle

我希望你不需要像我一样写一个完整的解决方案,并希望如果你需要它,这篇文章可以让你轻松痛苦。

请注意,最终的解决方案就像一个魅力(在制作中),但结束了一点复杂。