PostgreSQL 不区分大小写和不区分重音的搜索

Mar*_*nak 6 postgresql indexing search

我有一个数据表,我想过滤列。例如,按用户的全名搜索用户。

\n

但是,我希望允许用户输入搜索短语时不区分大小写和重音。

\n

所以我检查了这些(以及更多)来源和问题:

\n\n

我认为非确定性排序规则可能最终是实现这一目标的正确方法,但不幸的是我不知道如何:

\n
    \n
  • 将 case_insensitive 和ignore_accents 合并为一种排序规则
  • \n
  • 如何允许仅通过此类 WHERE 中的子字符串进行搜索(例如,仅通过字符串“joh”查找“J\xc3\xb3hn Doe”),因为非确定性排序规则不支持 LIKE 或正则表达式
  • \n
  • 使用哪个索引
  • \n
\n

对于如何最终处理此类问题的任何建议,我将非常感激。

\n

谢谢!

\n

Lau*_*lbe 6

创建不区分大小写和重音的 ICU 排序规则非常简单:

CREATE COLLATION english_ci_ai (
   PROVIDER = icu,
   DETERMINISTIC = FALSE,
   LOCALE = "en-US-u-ks-level1"
);
Run Code Online (Sandbox Code Playgroud)

或者,等效地(该语法也适用于旧的 ICU 版本:

CREATE COLLATION english_ci_ai (
   PROVIDER = icu,
   DETERMINISTIC = FALSE,
   LOCALE = "en-US@colStrength=primary"
);
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅ICU 文档和我的文章以了解详细讨论。

但你的问题是你想要子字符串搜索。所以你应该创建一个三元组索引:

CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS unaccent;

CREATE INDEX ON tab USING gin (unaccent(doc) gin_trgm_ops);
Run Code Online (Sandbox Code Playgroud)

然后你可以这样搜索:

SELECT * FROM tab
WHERE unaccent(doc) ILIKE unaccent('%joh%');
Run Code Online (Sandbox Code Playgroud)

请注意,如果您希望高效,则必须强制搜索字符串的最小长度为 4 左右。

  • 感谢您的更新,我想我必须坚持这个不重口音的解决方案。我只需要创建一个不重音的不可变版本,如我的第一个链接中所述。谢谢你! (2认同)