Gunakan modul tanpa aksen untuk itu - yang sama sekali berbeda dari apa yang Anda tautkan.
unaccent adalah kamus pencarian teks yang menghilangkan aksen (diakritik) dari leksem.
Instal sekali per database dengan:
CREATE EXTENSION unaccent;
Jika Anda mendapatkan kesalahan seperti:
ERROR: could not open extension control file "/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Instal paket contrib di server database Anda seperti yang diinstruksikan dalam jawaban terkait ini:
- Kesalahan saat membuat ekstensi tanpa aksen di PostgreSQL
Antara lain, ia menyediakan fungsi unaccent()
Anda dapat menggunakan dengan contoh Anda (di mana LIKE
sepertinya tidak diperlukan).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indeks
Untuk menggunakan indeks untuk kueri semacam itu, buat indeks pada ekspresi. Namun , Postgres hanya menerima IMMUTABLE
fungsi untuk indeks. Jika suatu fungsi dapat mengembalikan hasil yang berbeda untuk input yang sama, indeks dapat rusak secara diam-diam.
unaccent()
hanya STABLE
bukan IMMUTABLE
Sayangnya, unaccent()
hanya STABLE
, bukan IMMUTABLE
. Menurut utas ini di pgsql-bugs, ini karena tiga alasan:
- Tergantung pada perilaku kamus.
- Tidak ada koneksi terprogram ke kamus ini.
- Oleh karena itu juga tergantung pada
search_path
saat ini , yang dapat diubah dengan mudah.
Beberapa tutorial di web menginstruksikan untuk hanya mengubah volatilitas fungsi menjadi IMMUTABLE
. Metode brute force ini dapat rusak dalam kondisi tertentu.
Yang lain menyarankan IMMUTABLE
. sederhana fungsi pembungkus (seperti yang saya lakukan sendiri di masa lalu).
Ada perdebatan yang sedang berlangsung apakah akan membuat varian dengan dua parameter IMMUTABLE
yang menyatakan kamus yang digunakan secara eksplisit. Baca di sini atau di sini.
Alternatif lain adalah modul ini dengan unaccent()
I IMMUTABLE fungsi oleh Musicbrainz, disediakan di Github. Belum mengujinya sendiri. Saya rasa saya telah menemukan ide yang lebih baik :
Terbaik untuk saat ini
Pendekatan ini lebih efisien dibandingkan solusi lain yang beredar, dan lebih aman .
Buat IMMUTABLE
Fungsi pembungkus SQL mengeksekusi formulir dua parameter dengan fungsi dan kamus yang memenuhi syarat skema terprogram.
Karena menyarangkan fungsi yang tidak dapat diubah akan menonaktifkan fungsi inlining, mendasarkannya pada salinan fungsi-C, (palsu) menyatakan IMMUTABLE
demikian juga. Ini hanya tujuannya adalah untuk digunakan dalam pembungkus fungsi SQL. Tidak dimaksudkan untuk digunakan sendiri.
Kecanggihan diperlukan karena tidak ada cara untuk memasang kamus dalam deklarasi fungsi C. (Akan diperlukan untuk meretas kode C itu sendiri.) Fungsi pembungkus SQL melakukan itu dan memungkinkan kedua fungsi tersebut menyisipkan dan indeks ekspresi.
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$;
Jatuhkan PARALLEL SAFE
dari kedua fungsi untuk Postgres 9.5 atau lebih lama.
public
menjadi skema tempat Anda memasang ekstensi (public
adalah default).
Deklarasi tipe eksplisit (regdictionary
) bertahan dari serangan hipotetis dengan varian fungsi yang kelebihan beban oleh pengguna jahat.
Sebelumnya, saya menganjurkan fungsi pembungkus berdasarkan STABLE
fungsi unaccent()
dikirimkan dengan modul tanpa aksen. Fungsi yang dinonaktifkan itu sebaris. Versi ini dijalankan sepuluh kali lebih cepat daripada fungsi pembungkus sederhana yang saya miliki di sini sebelumnya.
Dan itu sudah dua kali lebih cepat dari versi pertama yang menambahkan SET search_path = public, pg_temp
ke fungsi - sampai saya menemukan bahwa kamus juga dapat memenuhi syarat skema. Masih (Postgres 12) tidak terlalu jelas dari dokumentasi.
Jika Anda tidak memiliki hak istimewa yang diperlukan untuk membuat fungsi C, Anda kembali ke implementasi terbaik kedua:IMMUTABLE
pembungkus fungsi di sekitar STABLE
unaccent()
fungsi yang disediakan oleh modul:
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;
Terakhir, indeks ekspresi untuk membuat kueri cepat :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Ingatlah untuk membuat ulang indeks melibatkan fungsi ini setelah perubahan apa pun pada fungsi atau kamus, seperti peningkatan rilis utama di tempat yang tidak akan membuat ulang indeks. Rilis besar terbaru semuanya memiliki pembaruan untuk unaccent
modul.
Sesuaikan kueri agar sesuai dengan indeks (sehingga perencana kueri akan menggunakannya):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Anda tidak memerlukan fungsi dalam ekspresi yang tepat. Di sana Anda juga dapat menyediakan string tanpa aksen seperti 'Joao'
secara langsung.
Fungsi yang lebih cepat tidak menerjemahkan ke kueri yang jauh lebih cepat menggunakan indeks ekspresi . Itu beroperasi pada nilai yang telah dihitung sebelumnya dan sudah sangat cepat. Tetapi pemeliharaan indeks dan kueri tidak menggunakan manfaat indeks.
Keamanan untuk program klien telah diperketat dengan Postgres 10.3 / 9.6.8 dll. Anda membutuhkan untuk fungsi kualifikasi skema dan nama kamus seperti yang ditunjukkan saat digunakan dalam indeks apa pun. Lihat:
- Entri
- 'kamus pencarian teks "tidak ada aksen" di log postgres, diduga selama analisis otomatis
Ligatur
Di Postgres 9.5 atau lebih lama ligatur seperti 'Œ' atau 'ß' harus diperluas secara manual (jika Anda membutuhkannya), karena unaccent()
selalu menggantikan tunggal surat:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Anda akan menyukai pembaruan ini untuk menghilangkan aksen di Postgres 9.6 :
Perluas
contrib/unaccent
standarunaccent.rules
file untuk menangani semua diakritik yang diketahui Unicode, dan memperluas ligatur dengan benar (ThomasMunro, Léonard Benedetti)
Penekanan saya yang berani. Sekarang kita mendapatkan:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Pencocokan pola
Untuk LIKE
atau ILIKE
dengan pola arbitrer, gabungkan ini dengan modul pg_trgm
di PostgreSQL 9.1 atau lebih baru. Buat trigram GIN (biasanya lebih disukai) atau indeks ekspresi GIST. Contoh untuk GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Dapat digunakan untuk pertanyaan seperti:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Indeks GIN dan GIST lebih mahal untuk dipelihara daripada btree biasa:
- Perbedaan antara indeks GiST dan GIN
Ada solusi sederhana untuk pola berlabuh kiri saja. Lebih lanjut tentang pencocokan pola dan kinerja:
- Pencocokan pola dengan LIKE, SIMILAR TO atau ekspresi reguler di PostgreSQL
pg_trgm
juga menyediakan operator yang berguna untuk "kesamaan" (%
) dan "jarak" (<->
).
Indeks trigram juga mendukung ekspresi reguler sederhana dengan ~
dkk. dan tidak peka huruf besar/kecil pencocokan pola dengan ILIKE
:
- Aksen PostgreSQL + pencarian tidak peka huruf besar/kecil