为了这个问题,我有两张桌子:
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)
(并使用触发器维护)的新列是唯一合理的解决方案吗?
这是最有效的吗?
答案 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
我希望你不需要像我一样写一个完整的解决方案,并希望如果你需要它,这篇文章可以让你轻松痛苦。
请注意,最终的解决方案就像一个魅力(在制作中),但结束了一点复杂。