與德語變音符號的三元組相似度 (pg_trgm)
我試圖弄清楚如何使用德語變音符號 (äöü) 改進 Postgres 10.6 pg_trgm 查詢。在德語中,“ö”可以寫成“oe”。但要注意:不是每個 ‘oe’ 都可以寫成 ‘ö’。
CREATE TABLE public.names (name text COLLATE pg_catalog."default"); CREATE INDEX names_idx ON public.names USING gin (name COLLATE pg_catalog."default" gin_trgm_ops);
SHOW LC_COLLATE; -- de_DE.UTF-8
當我使用該
similarity()
函式查詢***‘Schoenstraße’***的相似性時。SELECT name, similarity (name, 'Schoenstraße') AS similarity, show_trgm (name) FROM names WHERE name % 'Schoenstraße' ORDER BY similarity DESC;
我得到以下結果:
Name similarity show_trgm Schyrenstraße 0.588235 {0x9a07c3,0xde3801,"" s"","" sc"",chy,ens,hyr,nst,ren,sch,str,tra,0x76a40e,yre} Schönstraße 0.5625 {0x9a07c3,0xde3801,0xf00320,0x095f29,"" s"","" sc"",0x6deea5,nst,sch,str,tra,0x76a40e}
db<>在這裡擺弄
我可以做些什麼來改進它,還是我需要替換數據庫中的所有變音符號?
首先:德國詩人仍然是詩人。‘詩人’ <> ‘詩人’; ‘oe’ <> ‘ö’。用 ‘oe’ 代替 ‘ö’ 的約定如今已基本不再使用。看:
我曾多次遇到相關問題。附加模組**
unaccent
**有助於涵蓋雙方的拼寫變體和拼寫錯誤。每個數據庫安裝一次:CREATE EXTENSION unaccent;
看:
棘手的部分是獲得索引支持。對於初學者來說,細節可能很難。
三元相似度
然後按照此處的說明創建包裝函式(再次使用相同的連結):
用它創建一個新索引:
CREATE INDEX names_trgm_idx ON names USING gin (f_unaccent(name) gin_trgm_ops);
查詢展示:
SELECT name , similarity(f_unaccent(name), f_unaccent('Schoenstraße')) AS sim_unaccent , similarity(name, 'Schoenstraße') AS sim FROM names WHERE f_unaccent(name) % f_unaccent('Schoenstraße') ORDER BY f_unaccent(name) <-> f_unaccent('Schoenstraße') , name <-> 'Schoenstraße'; -- best match first
排序依據
name <-> 'Schoenstraße'
還可以作為決勝局首先獲得最佳匹配(在使用索引進行廉價過濾之後)。對於“最近鄰”類型的查詢,考慮使用 GiST 索引而不是 GIN
LIMIT
。看:全文搜尋(FTS 或僅 TS)
考慮全文搜尋以匹配完整的單詞(在詞乾之後),或使用前綴匹配/片語搜尋……請參閱:
該
unaccent
模組提供了一個用於集成的字典TEXT SEARCH CONFIGURATION
:CREATE TEXT SEARCH CONFIGURATION de (COPY = german); ALTER TEXT SEARCH CONFIGURATION de ALTER MAPPING FOR hword, hword_part, word WITH unaccent, german_stem;
基於它的索引:
CREATE INDEX names_fts_idx ON names USING GIN (to_tsvector('de', name));
或者,由於您正在處理names,您可能會基於
simple
文本搜尋配置而不是german
. 沒有停用詞,沒有詞幹。名稱不一定遵循特定於語言的規則。查詢展示:
SELECT name , ts_lexize('unaccent', name) , to_tsvector('de', name) , to_tsquery('de', 'Schoenstraße') , to_tsvector('de', name) @@ to_tsquery('de', 'Schoenstraße') AS match , similarity(name, 'Schoenstraße') FROM names WHERE to_tsvector('de', name) @@ to_tsquery('de', 'Schoenstraße') ORDER BY name <-> 'Schoenstraße'; -- exact matches first
同樣,排序依據
name <-> 'Schoenstraße'
作為決勝局,可能是其他排序標準的補充。但是請注意,使用 FTS 查找“Schoenstraße”不會找到“Schönstraße”,因為
unaccent()
不會更改“oe”,並將“ö”映射到“o”。(‘oe’ <> ‘ö’)。有關的:
db<>fiddle here - 尋找“Schoenstraße”
db<>fiddle here - 尋找“Schönstraße”