PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

PostgreSQL có hỗ trợ các cụm từ không nhạy cảm trọng âm không?

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:

  1. Nó phụ thuộc vào hoạt động của từ điển.
  2. Không có kết nối có dây với từ điển này.
  3. 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 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ủa unaccent.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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuyển một hàng thành nhiều hàng với ít cột hơn

  2. Mẫu bảng và các phương pháp khác để lấy các bộ số ngẫu nhiên

  3. Oracle đến PostgreSQL:Cú pháp nối ngoài ANSI trong PostgreSQL

  4. PostgreSQL khác gì với MySQL?

  5. Ngủ đông chậm để có được kết nối Postgres