PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Czy PostgreSQL obsługuje sortowanie niewrażliwe na akcenty?

Użyj modułu nieakcentów za to - co jest zupełnie inne od tego, do którego linkujesz.

unaccent to słownik wyszukiwania tekstu, który usuwa akcenty (znaki diakrytyczne) z leksemów.

Zainstaluj raz na bazę danych za pomocą:

CREATE EXTENSION unaccent;

Jeśli pojawi się błąd taki jak:

ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory

Zainstaluj pakiet contrib na serwerze bazy danych zgodnie z instrukcją w tej powiązanej odpowiedzi:

  • Błąd podczas tworzenia nieakcentowanego rozszerzenia w PostgreSQL

Między innymi udostępnia funkcję unaccent() możesz użyć ze swoim przykładem (gdzie LIKE wydaje się niepotrzebne).

SELECT *
FROM   users
WHERE  unaccent(name) = unaccent('João');

Indeks

Aby użyć indeksu dla tego rodzaju zapytania, utwórz indeks na wyrażeniu. Jednak , Postgres akceptuje tylko IMMUTABLE funkcje indeksów. Jeśli funkcja może zwrócić inny wynik dla tych samych danych wejściowych, indeks może po cichu się zepsuć.

unaccent() tylko STABLE nie IMMUTABLE

Niestety, unaccent() jest tylko STABLE , a nie IMMUTABLE . Według tego wątku na pgsql-bugs, jest to spowodowane trzem powody:

  1. To zależy od zachowania słownika.
  2. Nie ma połączenia przewodowego z tym słownikiem.
  3. W związku z tym zależy to również od bieżącej search_path , które można łatwo zmienić.

Niektóre samouczki w sieci instruują, aby zmienić zmienność funkcji na IMMUTABLE . Ta brutalna metoda może się zepsuć w pewnych warunkach.

Inni proponują prosty IMMUTABLE funkcja opakowująca (tak jak robiłem to sam w przeszłości).

Trwa debata, czy zrobić wariant z dwoma parametrami IMMUTABLE który jawnie deklaruje używany słownik. Przeczytaj tutaj lub tutaj.

Inną alternatywą byłby ten moduł z IMMUTABLE unaccent() funkcja Musicbrainz, dostępna na Github. Sam tego nie testowałem. Myślę, że wpadłem na lepszy pomysł :

Na razie najlepsze

Takie podejście jest bardziej wydajne i bezpieczniejsze niż inne rozwiązania. .
Utwórz IMMUTABLE Funkcja opakowująca SQL wykonująca formularz dwuparametrowy z przewodową funkcją kwalifikowaną do schematu i słownikiem.

Ponieważ zagnieżdżenie niezmiennej funkcji wyłączyłoby funkcję inline, oprzyj ją na kopii funkcji C, (fałszywie) zadeklarowanej IMMUTABLE także. To tylko cel ma być używany w opakowaniu funkcji SQL. Nie jest przeznaczony do samodzielnego użytku.

Potrzebne jest wyrafinowanie, ponieważ nie ma sposobu na stałe zakodowanie słownika w deklaracji funkcji C. (Wymagałoby to zhakowania samego kodu C.) Funkcja opakowująca SQL robi to i umożliwia zarówno wstawianie funkcji i indeksy wyrażeń.

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$;

Upuść PARALLEL SAFE z obu funkcji dla Postgresa 9.5 lub starszego.

public będący schematem, w którym zainstalowałeś rozszerzenie (public jest ustawieniem domyślnym).

Jawna deklaracja typu (regdictionary ) chroni przed hipotetycznymi atakami z przeciążonymi wariantami funkcji przez złośliwych użytkowników.

Wcześniej opowiadałem się za funkcją opakowującą opartą na STABLE funkcja unaccent() dostarczane z nieakcentowanym modułem. Ta wyłączona funkcja inliningu. Ta wersja działa dziesięć razy szybciej niż prosta funkcja opakowująca, którą miałem tutaj wcześniej.
I to było już dwa razy szybsze niż pierwsza wersja, która dodała SET search_path = public, pg_temp do funkcji - dopóki nie odkryłem, że słownik może być również kwalifikowany według schematu. Jednak (Postgres 12) nie jest zbyt oczywisty z dokumentacji.

Jeśli nie masz uprawnień niezbędnych do tworzenia funkcji C, wracasz do drugiej najlepszej implementacji:IMMUTABLE wrapper funkcji wokół STABLE unaccent() funkcja zapewniana przez moduł:

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;

Wreszcie indeks wyrażenia aby zapytania szybkie :

CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));

Pamiętaj, aby odtworzyć indeksy angażowanie tej funkcji po każdej zmianie funkcji lub słownika, na przykład w przypadku aktualizacji głównej wersji, która nie powoduje odtworzenia indeksów. Wszystkie ostatnie główne wydania zawierały aktualizacje dla unaccent moduł.

Dostosuj zapytania tak, aby pasowały do ​​indeksu (aby planer zapytań go wykorzystał):

SELECT * FROM users
WHERE  f_unaccent(name) = f_unaccent('João');

Nie potrzebujesz funkcji we właściwym wyrażeniu. Możesz tam również podać nieakcentowane ciągi, takie jak 'Joao' bezpośrednio.

Szybsza funkcja nie przekłada się na znacznie szybsze zapytania przy użyciu indeksu wyrażenia . Działa to na wstępnie obliczonych wartościach i jest już bardzo szybki. Ale utrzymanie indeksu i zapytania, które nie korzystają z indeksu, są korzystne.

Bezpieczeństwo programów klienckich zostało wzmocnione w Postgres 10.3 / 9.6.8 itd. Potrzebujesz do funkcji kwalifikowania schematu i nazwy słownika, jak pokazano, gdy są używane w dowolnych indeksach. Zobacz:

  • Wpis „nieakcentowy” słownika wyszukiwania tekstu nie istnieje w dzienniku postgres, przypuszczalnie podczas automatycznej analizy

Ligatury

W Postgresie 9.5 lub starszym ligatury, takie jak „Œ” lub „ß” muszą być rozwijane ręcznie (jeśli tego potrzebujesz), ponieważ unaccent() zawsze zastępuje singiel list:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
E A e a S

Pokochasz tę aktualizację bez akcentu w Postgresie 9.6 :

Rozszerz contrib/unaccent standardowe unaccent.rules plik do obsługi wszystkich znaków diakrytycznych znanych w Unicode i poprawnie rozwija ligatury (ThomasMunro, Leonard Benedetti)

Moje odważne podkreślenie. Teraz otrzymujemy:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
OE AE oe ae ss

Dopasowanie wzorca

Dla LIKE lub ILIKE z dowolnymi wzorcami, połącz to z modułem pg_trgm w PostgreSQL 9.1 lub nowszym. Utwórz trygram GIN (zazwyczaj preferowany) lub indeks wyrażenia GIST. Przykład dla WZ:

CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);

Może być używany do zapytań takich jak:

SELECT * FROM users
WHERE  f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');

Indeksy GIN i GIST są droższe w utrzymaniu niż zwykłe btree:

  • Różnica między indeksem GiST i GIN

Istnieją prostsze rozwiązania dla wzorów zakotwiczonych w lewo. Więcej informacji o dopasowaniu wzorców i wydajności:

  • Dopasowywanie wzorców za pomocą LIKE, SIMILAR TO lub wyrażeń regularnych w PostgreSQL

pg_trgm dostarcza również użytecznych operatorów dla "podobieństwa" (% ) i „odległość” (<-> ).

Indeksy trygramów obsługują również proste wyrażenia regularne z ~ i in. i bez uwzględniania wielkości liter dopasowanie wzorca za pomocą ILIKE :

  • Akcent PostgreSQL + wyszukiwanie bez uwzględniania wielkości liter


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak wdrożyć PostgreSQL na DigitalOcean

  2. Użyj połączenia PostgreSQL SSL w rdzy z certyfikatami z podpisem własnym

  3. Wstawiaj dane w 3 tabelach jednocześnie za pomocą Postgres

  4. Dodaj dni do daty w PostgreSQL

  5. Czy funkcje PostgreSQL są transakcyjne?