Sử dụng mô-đun không phù hợp cho điều đó - hoàn toàn khác với những gì 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 trọng âm (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:
- Lỗi khi tạo tiện ích mở rộng không phù hợp trên PostgreSQL
Trong số những thứ khác, nó cung cấp hàm unaccent()
bạn có thể sử dụng với ví dụ của mình (trong đó LIKE
dường như không cần thiết).
SELECT *
FROM users
WHERE unaccent(name) = unaccent('João');
Chỉ mụ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 IMMUTABLE
các chức năng 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ông phải IMMUTABLE
Rất tiếc, unaccent()
chỉ là 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 hoạt động của 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
search_path
hiện tại , có thể thay đổi dễ dàng.
Một số hướng dẫn trên web hướng dẫn chỉ thay đổi sự biến động của chức năng thành 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 IMMUTABLE
đơn giản chức năng wrapper (giống như tôi đã làm trước đây).
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
hay không khai báo từ điển đã sử dụng một cách rõ ràng. Đọc tại đây hoặc tại đây.
Một giải pháp thay thế khác sẽ là mô-đun này với IMMUTABLE unaccent()
chức năng của Musicbrainz, được cung cấp trên Github. Đã không thử nghiệm nó bản thân mình. Tôi nghĩ rằng tôi đã nghĩ ra một ý tưởng hay hơn :
Tốt nhất cho đến 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 trong SQL thực thi dạng 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, (giả mạo) được khai báo IMMUTABLE
cũng. duy nhất của nó mục đích 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.
Sự tinh tế là cần thiết vì không có cách nào làm khó từ điển trong việc 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ả hai hàm 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$;
Thả PARALLEL SAFE
từ cả hai chức năng cho Postgres 9.5 trở lên.
public
là giản đồ 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 hàm trình bao bọc dựa trên STABLE
function unaccent()
được vận chuyển với mô-đun không thẳng thắn. Đã 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à nó đã nhanh gấp đôi so với phiên bản đầu tiên đã thêm SET search_path = public, pg_temp
vào hàm - cho đến khi tôi phát hiện ra rằng từ điển cũng có thể đủ điều kiện về lược đồ. 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 đang quay lại cách triển khai tốt thứ hai:IMMUTABLE
trình bao bọc hàm xung quanh STABLE
unaccent()
chức năng đượ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 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ác bản 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ó dấu 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 trên các giá trị được tính toán trước và đã rất nhanh. Nhưng duy trì chỉ mục và các truy vấn không sử dụng lợi ích của chỉ mục.
Bảo mật cho các chương trình khách đã được thắt chặt với Postgres 10.3 / 9.6.8, v.v. Bạn cần đến hàm đủ điều kiện lược đồ 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:
- 'không tồn tại từ điển tìm kiếm văn bản' "unaccent" không tồn tại 'các mục nhập trong nhật ký postgres, được cho là trong quá trình phân tích tự động
Dây buộc
Trong Postgres 9.5 trở lên các chữ ghép như 'Œ' hoặc 'ß' phải được mở rộng theo cách thủ công (nếu bạn cần), vì unaccent()
luôn thay thế một đơn lẻ thư:
SELECT unaccent('Œ Æ œ æ ß');
unaccent
----------
E A e a S
Bạn sẽ thích cập nhật này cho người không công tâm trong Postgres 9.6 :
Mở rộng
contrib/unaccent
chuẩn củaunaccent.rules
tệp để xử lý tất cả các ký tự được biết đến với Unicode và mở rộng các chữ ghép một cách chính xác (ThomasMunro, 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
Đối sánh 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 một chỉ số 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:
- Sự khác biệt giữa chỉ số GiST và GIN
Có nhiều giải pháp đơn giản hơn cho các mẫu cố định bên trái. Tìm hiểu thêm về hiệu suất và đối sánh mẫu:
- Đối sánh mẫu với LIKE, SIMILAR TO hoặc biểu thức chính quy trong PostgreSQL
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à không phân biệt chữ hoa chữ thường khớp mẫu với ILIKE
:
- Tìm kiếm có dấu + phân biệt chữ hoa chữ thường PostgreSQL