PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Apakah PostgreSQL mendukung pengumpulan aksen yang tidak sensitif?

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:

  1. Tergantung pada perilaku kamus.
  2. Tidak ada koneksi terprogram ke kamus ini.
  3. 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 standar unaccent.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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa membuat batasan untuk memeriksa apakah email valid di postgres?

  2. Kembalikan Hanya Nilai Numerik dari Kolom Database PostgreSQL

  3. Kembalikan beberapa bidang sebagai catatan di PostgreSQL dengan PL/pgSQL

  4. lastInsertId tidak berfungsi di Postgresql

  5. POSTGRESQL Kunci Asing Merujuk Kunci Utama dari dua Tabel Berbeda