Sử dụng mô-đun không phù hợp cho điều đó - hoàn toàn khác với mô-đun bạn đang liên kết.
unaccent là một từ điển tìm kiếm văn bản loại bỏ dấu (dấu phụ) khỏi các từ vựng.
Cài đặt một lần cho mỗi cơ sở dữ liệu với:
CREATE EXTENSION unaccent;
Nếu bạn gặp lỗi như:
ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory
Cài đặt gói đóng góp trên máy chủ cơ sở dữ liệu của bạn như được hướng dẫn trong câu trả lời liên quan này:
Trong số những thứ khác, nó cung cấp chức năng unaccent()
bạn có thể sử dụng với ví dụ của mình (nếu LIKE
không cần thiết).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Mục lục
Để sử dụng chỉ mục cho loại truy vấn đó, hãy tạo chỉ mục trên biểu thức . Tuy nhiên , Postgres chỉ chấp nhận các IMMUTABLE
hàm cho các chỉ mục. Nếu một hàm có thể trả về một kết quả khác cho cùng một đầu vào, thì chỉ mục có thể bị ngắt một cách âm thầm.
unaccent()
chỉ STABLE
khôngIMMUTABLE
Thật không may, unaccent()
là duy nhất STABLE
, không phải IMMUTABLE
. Theo chủ đề này trên pgsql-bug , điều này là do ba lý do:
- Nó phụ thuộc vào hành vi của một từ điển.
- Không có kết nối có dây với từ điển này.
- Do đó, nó cũng phụ thuộc vào dòng điện
search_path
, có thể thay đổi dễ dàng.
Một số hướng dẫn trên web hướng dẫn chỉ thay đổi tính biến động của chức năng IMMUTABLE
. Phương pháp vũ phu này có thể phá vỡ trong một số điều kiện nhất định.
Những người khác đề xuất một chức năng trình bao bọc đơn giảnIMMUTABLE
(giống như tôi đã tự làm trong quá khứ).
Có một cuộc tranh luận đang diễn ra liệu có nên tạo biến thể có hai tham số IMMUTABLE
khai báo từ điển đã sử dụng một cách rõ ràng hay không. Đọc ở đây hoặc ở đây .
Một giải pháp thay thế khác sẽ là mô-đun này có chức năng IMMUTABLE unaccent()
của Musicbrainz , được cung cấp trên Github. Chưa tự mình kiểm tra. Tôi nghĩ tôi đã nghĩ ra một ý tưởng hay hơn :
Tốt nhất cho bây giờ
Cách tiếp cận này hiệu quả hơn khi các giải pháp khác trôi nổi và an toàn hơn .
Tạo một IMMUTABLE
hàm trình bao bọc SQL thực thi biểu mẫu hai tham số với từ điển và hàm đủ điều kiện giản đồ có dây.
Vì việc lồng một hàm không thay đổi sẽ vô hiệu hóa nội tuyến của hàm, hãy căn cứ vào bản sao của hàm C, được khai báo (giả mạo) IMMUTABLE
. Mục đích duy nhất của nó là được sử dụng trong trình bao bọc hàm SQL. Không có nghĩa là để được sử dụng riêng của mình.
Sự tinh tế là cần thiết vì không có cách nào làm khó từ điển trong phần khai báo hàm C. (Sẽ yêu cầu tự hack mã C.) Hàm trình bao bọc trong SQL thực hiện điều đó và cho phép cả chỉ mục nội tuyến và chỉ mục biểu thức.
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ỏ PARALLEL SAFE
qua cả hai chức năng cho Postgres 9.5 trở lên.
public
là lược đồ nơi bạn đã cài đặt tiện ích mở rộng ( public
là mặc định).
Khai báo kiểu rõ ràng ( regdictionary
) bảo vệ chống lại các cuộc tấn công giả định với các biến thể quá tải của hàm bởi người dùng độc hại.
Trước đây, tôi đã ủng hộ một chức năng bao bọc dựa trên STABLE
chức năng unaccent()
được vận chuyển cùng với mô-đun không lệch tâm. Đã vô hiệu hóa chức năng nội tuyến . Phiên bản này thực thi nhanh hơn mười lần so với chức năng trình bao bọc đơn giản mà tôi đã có ở đây trước đó.
Và tốc độ đó đã nhanh gấp đôi so với phiên bản đầu tiên được thêm vào SET search_path = public, pg_temp
hàm - cho đến khi tôi phát hiện ra rằng từ điển cũng có thể đủ tiêu chuẩn giản đồ. Tuy nhiên (Postgres 12) không quá rõ ràng từ tài liệu.
Nếu bạn thiếu các đặc quyền cần thiết để tạo các hàm C, bạn quay lại cách triển khai tốt thứ hai: Một IMMUTABLE
trình bao bọc hàm xung quanh STABLE
unaccent()
hàm được cung cấp bởi mô-đun:
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;
Cuối cùng, chỉ mục biểu thức để thực hiện các truy vấn nhanh chóng :
CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));
Hãy nhớ tạo lại các chỉ mục liên quan đến chức năng này sau bất kỳ thay đổi nào đối với chức năng hoặc từ điển, chẳng hạn như bản nâng cấp phát hành chính tại chỗ sẽ không tạo lại các chỉ mục. Các bản phát hành chính gần đây đều có cập nhật cho unaccent
mô-đun.
Điều chỉnh các truy vấn để phù hợp với chỉ mục (vì vậy người lập kế hoạch truy vấn sẽ sử dụng nó):
SELECT * FROM users
WHERE f_unaccent(name) = f_unaccent('João');
Bạn không cần hàm trong biểu thức đúng. Ở đó, bạn cũng có thể cung cấp các chuỗi không có phép như 'Joao'
trực tiếp.
Hàm nhanh hơn không dịch sang các truy vấn nhanh hơn nhiều bằng cách sử dụng chỉ mục biểu thức . Điều đó hoạt động dựa trên các giá trị được tính toán trước và đã rất nhanh. Nhưng bảo trì chỉ mục và các truy vấn không sử dụng chỉ mục có lợi.
Bảo mật cho các chương trình máy khách đã được thắt chặt với Postgres 10.3 / 9.6.8, v.v. Bạn cần xác định chức năng đủ điều kiện giản đồ và tên từ điển như được minh họa khi được sử dụng trong bất kỳ chỉ mục nào. Xem:
Dây chằng
Trong Postgres 9,5 trở lên ligature như 'Œ' hoặc 'ß' phải được mở rộng bằng tay (nếu bạn cần đó), vì unaccent()
luôn luôn thay thế một đơn thư:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Bạn sẽ thích bản cập nhật này cho người không công tâm trong Postgres 9.6 :
Mở rộng tệp contrib/unaccent
tiêu chuẩn của unaccent.rules
để xử lý tất cả các dấu phụ được biết đến với Unicode và mở rộng các chữ ghép một cách chính xác (Thomas Munro, Léonard Benedetti)
Tôi nhấn mạnh đậm. Bây giờ chúng tôi nhận được:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
OE AE oe ae ss
Khớp mẫu
Đối với LIKE
hoặc ILIKE
với các mẫu tùy ý, hãy kết hợp mô-đun này với mô-đun pg_trgm
trong PostgreSQL 9.1 trở lên. Tạo chỉ mục biểu thức GIN (thường thích hợp hơn) hoặc GIST. Ví dụ cho GIN:
CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);
Có thể được sử dụng cho các truy vấn như:
SELECT * FROM users
WHERE f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');
Chỉ số GIN và GIST đắt hơn để duy trì so với btree đơn giản:
Có nhiều giải pháp đơn giản hơn cho các mẫu được neo bên trái. Thông tin thêm về đối sánh mẫu và hiệu suất:
pg_trgm
cũng cung cấp các toán tử%
<->
hữu ích cho "tương tự" ( ) và "khoảng cách" ( ) .
Chỉ mục Trigram cũng hỗ trợ các biểu thức chính quy đơn giản với ~
et al. và đối sánh mẫu không phân biệt chữ hoa chữ thường với ILIKE
: