Postgresql

在欄位上創建不區分大小寫和重音/變音符號的搜尋

  • February 28, 2020

我想知道在使用全文搜尋時創建結合兩個函式的索引是否有意義:lower(name)以及f_unaccent(name)Where f_unaccentis just my wrapper 使非重音函式不可變。

我確實有一個正在處理的索引:f_unaccent(name)使用varchar_pattern_ops. 我的問題是:結合lowerunaccent功能的索引是否會由 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;

現在你應該能夠

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。如果該列僅包含一種語言的語句,您可以使用其他字典之一來簡化內容並刪除停用詞。

引用自:https://dba.stackexchange.com/questions/177020