Czy PostgreSQL obsługuje kolacje "niewrażliwe na akcent"?
W Microsoft SQL Server można określić kolacje " niewrażliwe na akcent "(dla bazy danych, tabeli lub kolumny), co oznacza, że jest to możliwe dla zapytania typu
SELECT * FROM users WHERE name LIKE 'João'
Aby znaleźć wiersz o nazwie Joao
.
Wiem, że możliwe jest usunięcie akcentów z napisów w PostgreSQL przy użyciu funkcji contrib unaccent_string , ale zastanawiam się, czy PostgreSQL obsługuje te "nieczułe" zestawienia, więc SELECT
powyżej by zadziałało.
3 answers
Użyj moduł unaccent do tego-co jest zupełnie inne od tego, do czego linkujesz.
Unaccent jest słownikiem wyszukiwania tekstu, który usuwa akcenty (znaki diakrytyczne znaki) z leksemes.
Zainstaluj raz na bazę danych za pomocą:
CREATE EXTENSION unaccent;
Jeśli pojawi się błąd w stylu:
Błąd: nie można otworzyć pliku kontroli rozszerzenia "/usr / share / postgresql / 9.x / extension / unaccent.control": brak takiego pliku lub katalog
Zainstaluj pakiet contrib na serwerze bazy danych zgodnie z Instrukcją w tej powiązanej odpowiedzi:
Zawiera między innymi funkcję unaccent()
, której możesz użyć w swoim przykładzie (gdzie LIKE
wydaje się nie być potrzebna).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Indeks
Aby użyć indeksu dla tego rodzaju zapytań, Utwórz indeks na wyrażeniu. Jednakże , Postgres akceptuje tylko funkcje IMMUTABLE
dla indeksów. Jeśli funkcja może zwrócić inny wynik dla tego samego wejścia, indeks może się po cichu złamać.
unaccent()
tylko STABLE
Nie IMMUTABLE
Niestety, unaccent()
jest tylko STABLE
, a nie IMMUTABLE
. Zgodnie z ten wątek na pgsql-bugs, wynika to z trzech powodów:
-
To zależy od zachowania słownika.
- nie ma połączenia przewodowego z tym słownikiem.
- dlatego też zależy od prądu
search_path
, który może się łatwo zmienić.
Niektóre tutoriale w sieci instruują, aby po prostu zmienić zmienność funkcji na IMMUTABLE
. Ta metoda brute-force może pęknąć w pewnych warunkach.
Inni sugerują prostą IMMUTABLE
funkcję wrappera (tak jak ja sam w przeszłości).
Trwa dyskusja czy zrobić wariant z dwoma parametrami IMMUTABLE
który wyraźnie deklaruje używany słownik. Czytaj tutaj lub tutaj .
Inną alternatywą byłby ten moduł z niezmienną unaccent()
funkcją Musicbrainz , dostarczoną na Githubie. Sam tego nie testowałem. Myślę, że wymyśliłem lepszy pomysł:
Najlepsze na razie
Proponuję podejście, które jest co najmniej równie wydajne jak inne rozwiązania, ale bezpieczniejsze.]}: Utwórz funkcję owijania z dwu-parametrowym formularzem i "twardym drutem" schemat funkcji i słownika: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;
public
jest to schemat, w którym zainstalowano rozszerzenie (public
jest domyślne).
wcześniej dodałem SET search_path = public, pg_temp
do funkcji-dopóki nie odkryłem, że słownik może być również klasyfikowany według schematu, , który obecnie (pg 10) nie jest udokumentowany . Ta wersja jest nieco krótsza i około dwa razy szybsza w moich testach na pg 9.5 i pg 10.
Zaktualizowana wersja nadal nie pozwala funkcji inlining ponieważ funkcje zadeklarowane IMMUTABLE
nie mogą wywoływać funkcji nieujemnych w ciele, aby na to pozwolić. Nie ma znaczenia dla wydajności, podczas gdy korzystamy z indeks wyrażeń na tej funkcji IMMUTABLE
:
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Bezpieczeństwo programów klienckich zostało zaostrzone w Postgres 10.3 / 9.6.8 itd. Musisz aby schema-qualify function and dictionary były pokazane, gdy są używane w dowolnych indeksach. Zobacz:
Dostosuj swoje zapytania do indeksu (aby planista zapytań mógł go użyć):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Nie potrzebujesz funkcji w odpowiednim wyrażeniu. Możesz dostarczyć unactened ciągi jak 'Joao'
bezpośrednio.
Ligatury
W Postgres 9.5 lub starszych ligatury takie jak' œ 'lub' ß ' muszą być rozszerzane ręcznie (jeśli tego potrzebujesz), ponieważ unaccent()
zawsze zastępuje a single letter:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Pokochasz ten update to unaccent W Postgres 9.6:
/ Align = "left" / Teraz otrzymujemy:Rozszerz
contrib/unaccent
standardowy plikunaccent.rules
, aby obsłużyć wszystkie znaki diakrytyczne znane Unicode i rozwiń ligatury poprawnie (Thomas Munro, Léonard Benedetti)
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Dopasowanie wzorca
Dla LIKE
lub ILIKE
z dowolnymi wzorami, połącz to z moduł pg_trgm
W PostgreSQL 9.1 lub nowszym. Utwórz indeks wyrażenia trygram GIN (zwykle preferowany) lub GIST. Przykład dla ginu:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Może być używany do zapytań typu:
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:]}
Istnieją prostsze rozwiązania dla tylko lewych zakotwiczonych wzorów. Więcej o dopasowywaniu wzorów i wydajność:
pg_trgm
zawiera również użyteczne operatory dla "podobieństwa" (%
) i "odległości" (<->
).
Indeksy Trygramowe obsługują również proste wyrażenia regularne z ~
et al. and case niewrażliwe wzór pasujący do ILIKE
:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 08:36:26
Jestem prawie pewien, że PostgreSQL opiera się na bazowym systemie operacyjnym do sortowania. To nie obsługuje tworzenie nowych zestawień i dostosowywanie zestawień. Nie jestem pewien, ile to może być dla Ciebie pracy. (Może być sporo.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-12 21:54:48
Nie, PostgreSQL nie obsługuje kolacji w tym sensie
PostgreSQL nie obsługuje takich zestawień (nieczułych lub nie), ponieważ żadne porównanie nie może zwrócić równości, chyba że rzeczy są binarne-równe. To dlatego, że wewnętrznie wprowadzi wiele złożoności dla rzeczy takich jak indeks hash. Z tego powodu zestawienia w ich ścisłym znaczeniu wpływają tylko na uporządkowanie , a nie na równość.
Obejścia
Full-Text-Search Dictionary that / Align= "left" /
Dla FTS można zdefiniować własny słownik używając unaccent
,
CREATE EXTENSION unaccent;
CREATE TEXT SEARCH CONFIGURATION mydict ( COPY = simple );
ALTER TEXT SEARCH CONFIGURATION mydict
ALTER MAPPING FOR hword, hword_part, word
WITH unaccent, simple;
Które można następnie indeksować indeksem funkcjonalnym,
-- Just some sample data...
CREATE TABLE myTable ( myCol )
AS VALUES ('fóó bar baz'),('qux quz');
-- No index required, but feel free to create one
CREATE INDEX ON myTable
USING GIST (to_tsvector('mydict', myCol));
Możesz teraz odpytywać to bardzo prosto
SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'
mycol
-------------
fóó bar baz
(1 row)
Zobacz też
/ Align = "left" /The unaccent
Moduł może być również używany samodzielnie bez integracji FTS, do tego sprawdzenia out Erwin ' s answer
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-30 01:52:08