在欄位上創建不區分大小寫和重音/變音符號的搜尋
我想知道在使用全文搜尋時創建結合兩個函式的索引是否有意義:
lower(name)
以及f_unaccent(name)
Wheref_unaccent
is just my wrapper 使非重音函式不可變。我確實有一個正在處理的索引:
f_unaccent(name)
使用varchar_pattern_ops
. 我的問題是:結合lower
和unaccent
功能的索引是否會由 full_text_search 觸發lower(f_unaccent(name))
。我不知道該
lower
函式是否對全文搜尋算法有用。
首先,我們需要澄清一些事情。
模式操作和三元組
這種類型的查詢可以在 varchar/text pattern_ops 上工作,
foo LIKE 'bar%'
具有非錨定搜尋模式的查詢需要
trigram
。foo LIKE '%bar%'
只要您在查詢中保持與索引中相同的序列,它們都可以處理函式表達式。
全文搜尋是完全不同的東西。它通過存根到詞根、小寫、刪除停用詞和一系列其他技巧將您的文本轉換為詞位。繼續閱讀:
本身不重音(不建議這樣做)
不幸的是,
unaccent
它只是“穩定的”而不是“不可變的”。因此,如果您嘗試在其上創建索引,unaccent(text)
則會出現錯誤,functions in index expression must be marked IMMUTABLE
. 我認為這就是您創建包裝器f_accent
並在Erwins 上找到 Stack Overflow 答案的原因。看起來像這樣,CREATE EXTENSION unaccent; CREATE OR REPLACE FUNCTION f_unaccent(text) RETURNS text AS $func$ SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary $func$ LANGUAGE sql IMMUTABLE; CREATE TABLE foo AS SELECT 'asdf'::text AS mytext; CREATE INDEX ON foo (lower(f_unaccent(mytext)) text_pattern_ops);
或者,對於三元組,
CREATE INDEX ON foo USING gin(lower(f_unaccent(mytext)) gin_trgm_ops);
現在請記住,您必須進行很長的序列
lower(f_unaccent(mytext))
才能使其正常工作。SELECT * FROM foo WHERE lower(f_unaccent(mytext)) LIKE '%whatever%';
使用 FTS 詞典不重音
unaccent
我將創建一個使用和使用 FTS的字典,而不是那種方法。使用自定義詞典雖然它可能會做你想要的。FTS 將單詞轉換為標記,這使得搜尋變得非常簡單和快速。CREATE EXTENSION unaccent; -- still required it plugs into FTS. CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple ); ALTER TEXT SEARCH CONFIGURATION mydict ALTER MAPPING FOR hword, hword_part, word WITH unaccent, simple;
現在你應該能夠
- 刪除任何
varchar_pattern_ops
或trigram
索引- 如果需要,在 tsvector 上創建GIST 或 GIN 索引
CREATE INDEX ON foo USING to_tsvector('mydict', mytext);
你可以在這裡看到令牌和它在做什麼,
select to_tsvector( 'mydict', 'Zoë and Renée are elected to the council of Cheese Eating Surrender Monkeys' ); to_tsvector ------------------------------------------------------------------------------------------------------------------------------------- 'and':2 'are':4 'cheese':10 'council':8 'eating':11 'elected':5 'monkeys':13 'of':9 'renee':3 'surrender':12 'the':7 'to':6 'zoe':1 (1 row)
你可以像這樣簡單地查詢表,
SELECT * FROM foo WHERE to_tsvector('mydict', mytext) @@ 'cheese & council';
你也不必使用
simple
。如果該列僅包含一種語言的語句,您可以使用其他字典之一來簡化內容並刪除停用詞。