多语言列上的全文搜索索引

时间:2014-01-22 16:32:44

标签: postgresql sequel

我有一个数据库,其中有一个表shows,其中包含多语言列title。我想通过添加如下索引来优化全文搜索:

CREATE INDEX title_idx ON shows USING gin(to_tsvector(title));

我收到此错误:

ERROR:  functions in index expression must be marked IMMUTABLE

它基本上要求我添加语言参数以使to_tsvector不可变。结果将是:

 CREATE INDEX title_idx ON shows USING gin(to_tsvector(LANGUAGE, title));

其中LANGUAGE将成为我的目标语言之一。

是否可以创建适用于多种语言的索引?

3 个答案:

答案 0 :(得分:33)

  

是否可以创建适用于多种语言的索引?

是的,但您需要第二列来标识文本的语言。假设您在表中添加了一列doc_language;然后你可以写:

CREATE INDEX title_idx ON shows USING gin(to_tsvector(doc_language, title));

当然,这要求您了解主题文本的语言,这在实践中很难实现。如果你不需要词干等,你可以使用simple语言,但我猜你已经完成了它,如果它是一个选项。

作为替代方案,如果您拥有固定且有限的一组语言,则可以连接不同语言的向量。 E.g:

regress=> SELECT to_tsvector('english', 'cafés') || to_tsvector('french', 'cafés') || to_tsvector('simple', 'cafés');
          ?column?          
----------------------------
 'caf':2 'café':1 'cafés':3
(1 row)

在这三种语言中,cafés匹配tsquery。

作为索引:

CREATE INDEX title_idx ON shows USING gin((
    to_tsvector('english', title) || 
    to_tsvector('french', title) || 
    to_tsvector('simple', title)
));

但是在查询中使用这一点很笨拙,因为规划者在匹配索引码时并不是很聪明。所以我将它包装在一个函数中:

CREATE FUNCTION to_tsvector_multilang(text) RETURNS tsvector AS $$
SELECT to_tsvector('english', $1) || 
       to_tsvector('french', $1) || 
       to_tsvector('simple', $1)
$$ LANGUAGE sql IMMUTABLE;

CREATE INDEX title_idx ON shows USING gin(to_tsvector_multilang(title));

如果你想要你甚至可以得到幻想:将语言列表作为一个数组传递(但请记住它必须完全相同的顺序才能使索引质量匹配起作用) 。使用setweight的优先级,因此您更喜欢英语匹配,法语匹配。各种选择。

答案 1 :(得分:4)

我刚刚制作了Postgres函数来测试文本语言。它并不完美,但适用于长篇文章。

CREATE OR REPLACE FUNCTION get_language(t text) RETURNS regconfig AS $$
DECLARE
    ret regconfig;
    BEGIN
            WITH l as ( SELECT cfgname, to_tsvector(cfgname::regconfig, title) as vector, length(to_tsvector(cfgname::regconfig, title)) as len
        FROM pg_ts_config, (select t as title) as ti)
    SELECT cfgname::regconfig
    INTO ret 
    FROM l
    WHERE len=(SELECT MIN(len) FROM l)
    ORDER BY cfgname='simple' DESC, cfgname ASC
    LIMIT 1;
    RETURN ret;
    END;
$$ LANGUAGE plpgsql;

它只是查找给定文本的最短tsvector(因此它会尝试postgres的每个ts配置)。

答案 2 :(得分:0)

就我而言,我知道当前ligne的语言。我有一个“语言”列。但是,如果我这样做:

CREATE INDEX filmtraduction_tsindex ON filmtraduction USING GIN (
to_tsvector((case when $1=''language.fr'' then ''french'' when $1=''language.es'' then ''spanish'' else ''english'' end)::regconfig, body));

如果具有“索引表达式中的功能必须标记为IMMUTABLE”。

所以我需要创建一个不变的函数:

 CREATE FUNCTION toregconfig(text) RETURNS regconfig AS 'select (case
 when $1=''language.fr'' then ''french'' when $1=''language.es'' then
 ''spanish'' else ''english'' end)::regconfig;' LANGUAGE SQL IMMUTABLE
 RETURNS NULL ON NULL INPUT;

然后我可以创建索引:

CREATE INDEX filmtraduction_tsindex ON filmtraduction USING GIN (
to_tsvector(toregconfig(language), body));

我这样查询:

select * from movietraduction where to_tsvector(toregconfig(language), body) @@ plainto_tsquery('foo');