2014-01-22 61 views
9

我有一個DB,其中有一個表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將是我的目標語言之一。

是否可以創建適用於多種語言的索引?

回答

28

Is it possible to create an index that works for several languages ?

是的,但您需要第二列標識文本的語言。假設你在表格中添加了一列doc_language;然後你可以寫:

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

當然,這需要你知道的主題文本的語言,這東西是很難在實踐中做到。如果你不需要干擾等,你可以使用語言simple,但我猜你已經做到了,如果它是一個選項。

作爲一種替代方案,如果您有固定和有限的一組語言,則可以將連接到不同語言的矢量。例如: -

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

但是這是笨拙在查詢中使用,作爲策劃人是不是匹配指數quals很聰明。所以我把它包在一個函數:

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的優先順序,所以你比較喜歡英語的一個法語比賽。各種選擇。

+0

謝謝,我不知道tsvectors是否能夠合併。那很棒。從我Upvote :) – knitti

+0

偉大的深入答案! –

+0

最後一行代碼中有一個額外的「(」(不能編輯少於6個字符......) – Victor

0

我剛剛做了一個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(所以它會試圖每TS的Postgres的配置)。