Bunun için aksan olmayan modülü kullanın - bu, bağlantı kurduğunuzdan tamamen farklıdır.
unaccent, aksanları (aksan işaretleri) sözcükbirimlerinden kaldıran bir metin arama sözlüğüdür.
Aşağıdakilerle veritabanı başına bir kez yükleyin:
CREATE EXTENSION unaccent;
Aşağıdaki gibi bir hata alırsanız:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Katkı paketini, bu ilgili yanıtta belirtildiği gibi veritabanı sunucunuza yükleyin:
Diğer şeylerin yanı sıra, unaccent()
örneğinizle kullanabileceğiniz işlevi sağlar ( LIKE
gerekli görünmeyen yerlerde ).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Dizin
Bu tür bir sorgu için bir dizin kullanmak üzere ifade üzerinde bir dizin oluşturun . Ancak , Postgres yalnızca IMMUTABLE
dizinler için işlevleri kabul eder . Bir işlev aynı girdi için farklı bir sonuç döndürebiliyorsa, dizin sessizce kırılabilir.
unaccent()
sadece STABLE
değilIMMUTABLE
Ne yazık ki, unaccent()
sadece STABLE
öyle değil IMMUTABLE
. Pgsql-bugs hakkındaki bu konuya göre , bunun üç sebebi var:
- Bir sözlüğün davranışına bağlıdır.
- Bu sözlüğe hiçbir fiziksel bağlantı yok.
- Bu nedenle
search_path
, kolaylıkla değişebilen akıma da bağlıdır .
Web'deki bazı öğreticiler , işlev değişkenliğini sadece IMMUTABLE
. Bu kaba kuvvet yöntemi belirli koşullar altında kırılabilir.
Diğerleri basit bir IMMUTABLE
sarmalayıcı işlevi önermektedir (geçmişte kendim yaptığım gibi).
Kullanılan sözlüğü açıkça bildiren iki parametre ile varyantın yapılıp yapılmayacağına dair süregelen bir tartışma var IMMUTABLE
. Burayı veya buradan okuyun .
Diğer bir alternatif ise, Github'daunaccent()
sağlanan Musicbrainz'in IMMUTABLE işlevine sahip bu modül olabilir . Kendim test etmedim. Sanırım daha iyi bir fikir buldum :
Şimdilik en iyisi
Bu yaklaşım, etrafta dolaşan diğer çözümler için daha verimli ve daha güvenli . İki parametreli formu fiziksel bağlantılı şema nitelikli işlev ve sözlükle çalıştıran
bir IMMUTABLE
SQL sarmalayıcı işlevi oluşturun .
Değişmez olmayan bir işlevi iç içe yerleştirmek, işlev satırını devre dışı bırakacağından, bunu C işlevinin (sahte) de beyan ettiği bir kopyasına dayandırın IMMUTABLE
. Onun tek amacı, SQL fonksiyonu ambalajında kullanılacak. Kendi başına kullanılması amaçlanmamıştır.
C işlevinin bildiriminde sözlüğü sert bir şekilde bağlamanın bir yolu olmadığı için karmaşıklığa ihtiyaç vardır. (Misiniz C kodu kendisi kesmek gerekir.), SQL sarıcı fonksiyonu yok ve inlining her ikisinin de düzgün sağlar ve sentezleme endeksler.
CREATE OR REPLACE FUNCTION public.immutable_unaccent(regdictionary, text)
RETURNS text LANGUAGE c IMMUTABLE PARALLEL SAFE STRICT AS
'$libdir/unaccent', 'unaccent_dict';
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT AS
$func$
SELECT public.immutable_unaccent(regdictionary 'public.unaccent', $1)
$func$;
Bırak PARALLEL SAFE
Postgres 9.5 veya üstü için her iki işlevlerden.
public
uzantıyı yüklediğiniz şema olmak ( public
varsayılandır).
Açık tür bildirimi ( regdictionary
), kötü niyetli kullanıcılar tarafından işlevin aşırı yüklenmiş varyantlarıyla varsayımsal saldırılara karşı koruma sağlar.
Daha önce, temel bir sarmalayıcı işlev savunduğu STABLE
fonksiyonu unaccent()
unaccent modülü ile sevk edilir. Bu devre dışı bırakılan işlev satır içi . Bu sürüm, daha önce burada sahip olduğum basit sarmalayıcı işlevinden on kat daha hızlı çalışır.
Ve bu, SET search_path = public, pg_temp
işleve eklenen ilk sürümden iki kat daha hızlıydı - sözlüğün de şema nitelikli olabileceğini keşfedene kadar. Yine de (Postgres 12) belgelerden çok açık değil.
Eğer bir: C işlevler oluşturmak için gerekli ayrıcalıkları yoksun, geri en iyi ikinci uygulanması için vardır IMMUTABLE
etrafında işlev sarmalayıcı STABLE
unaccent()
modülü tarafından sağlanan işlevi:
CREATE OR REPLACE FUNCTION public.f_unaccent(text)
RETURNS text AS
$func$
SELECT public.unaccent('public.unaccent', $1) -- schema-qualify function and dictionary
$func$ LANGUAGE sql IMMUTABLE PARALLEL SAFE STRICT;
Son olarak, sorguları hızlı yapmak için ifade dizini :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Dizinleri yeniden oluşturmayan yerinde bir ana sürüm yükseltmesi gibi, işlev veya sözlükte yapılan herhangi bir değişiklikten sonra bu işlevi içeren dizinleri yeniden oluşturmayı unutmayın . Son ana sürümlerin hepsinde unaccent
modül için güncellemeler vardı .
Sorguları dizine uyacak şekilde uyarlayın (böylece sorgu planlayıcı onu kullanacaktır):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Doğru ifadede işleve ihtiyacınız yok. Orada 'Joao'
doğrudan gibi vurgusuz dizeler de sağlayabilirsiniz .
Daha hızlı işlev, ifade indeksini kullanarak çok daha hızlı sorgulara dönüşmez . Bu, önceden hesaplanmış değerlerle çalışır ve zaten çok hızlıdır. Ancak dizin bakımı ve dizini kullanmayan sorgular faydalıdır.
İstemci programları için güvenlik, Postgres 10.3 / 9.6.8 vb. İle sıkılaştırılmıştır . Herhangi bir dizinde kullanıldığında gösterildiği gibi, şema nitelikli işlevi ve sözlük adını belirlemeniz gerekir . Görmek:
Bitişik harfler
Postgres 9.5 veya 'older ' veya 'ß' gibi daha eski bitişik harflerin manuel olarak genişletilmesi gerekir (buna ihtiyacınız varsa), çünkü unaccent()
her zaman tek bir harfin yerini alır:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Postgres 9.6'da bu güncellemenin vurgulanmasını seveceksiniz :
Uzatın contrib/unaccent
'in standart unaccent.rules
Unicode bilinen tüm aksan işaretleri işlemek için dosyayı ve doğru olarak bitişik harfler genişletmek (Thomas Munro Léonard Benedetti)
Cesur vurgu benim. Şimdi anlıyoruz:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Desen eşleştirme
İçin LIKE
veya ILIKE
keyfi desenleri ile, modül ile birleştirmek pg_trgm
PostgreSQL 9.1 veya daha sonra. Bir trigram GIN (tipik olarak tercih edilir) veya GIST ifade indeksi oluşturun. GIN için örnek:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Şunlar gibi sorgular için kullanılabilir:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
GIN ve GIST indekslerinin bakımı düz btree'den daha pahalıdır:
Sadece sola bağlantılı desenler için daha basit çözümler var. Kalıp eşleştirme ve performans hakkında daha fazla bilgi:
pg_trgm
ayrıca "benzerlik" ( %
) ve "mesafe" ( <->
) için yararlı operatörler sağlar .
Trigram indeksleri, ~
et al. ve büyük / küçük harfe duyarsız kalıp eşleştirmesi ILIKE
: