postgresql是否支持“不区分重音”的排序规则?

zdwk9cvp  于 2021-07-26  发布在  Java
关注(0)|答案(3)|浏览(371)

在microsoftsqlserver中,可以指定一个“不区分重音”的排序规则(对于数据库、表或列),这意味着对于类似

SELECT * FROM users WHERE name LIKE 'João'

找一排有 Joao 姓名。
我知道在postgresql中使用uncent\u string contrib函数可以去除字符串中的重音,但是我想知道postgresql是否支持这些“不区分重音”的排序规则,所以 SELECT 上面的话就行了。

chhqkbe1

chhqkbe11#

使用uncent模块来实现这一点-这与您正在链接的内容完全不同。
uncent是一个文本搜索字典,它可以从词素中删除重音(变音符号)。
每个数据库安装一次:

CREATE EXTENSION unaccent;

如果出现如下错误:

ERROR: could not open extension control file
"/usr/share/postgresql/<version>/extension/unaccent.control": No such file or directory

在数据库服务器上安装contrib包,如以下相关答案所示:
在postgresql上创建非关联扩展时出错
除此之外,它还提供 unaccent() 你可以用你的例子(其中 LIKE 似乎不需要)。

SELECT *
FROM   users
WHERE  unaccent(name) = unaccent('João');

索引

若要对此类查询使用索引,请在表达式上创建索引。然而,postgres只接受 IMMUTABLE 索引函数。如果一个函数可以为同一个输入返回不同的结果,索引可能会自动中断。

uncent()只稳定不不变

不幸的是, unaccent() 只是 STABLE ,不是 IMMUTABLE . 根据pgsql bug上的这个线程,这是由三个原因造成的:
这取决于词典的行为。
这本词典没有硬连线。
因此,这也取决于电流 search_path ,很容易改变。
网上的一些教程指示只需将函数更改为 IMMUTABLE . 这种蛮力方法在某些情况下可以破坏。
其他人则建议一个简单的方法 IMMUTABLE Package 函数(就像我以前做的那样)。
是否用两个参数来制作变型,目前仍有争论 IMMUTABLE 它显式声明使用的字典。读这里或这里。
另一种选择是使用不可变的 unaccent() musicbrainz提供的函数,在github上提供。我自己也没试过。我想我想出了一个更好的主意:

现在最好

这种方法比其他解决方案更有效,也更安全。
创建 IMMUTABLE sql Package 器函数使用硬连线的模式限定函数和字典执行双参数表单。
因为嵌套一个非不变函数会禁用函数内联,所以它基于声明的c函数的副本(fake) IMMUTABLE 也。它的唯一用途是在sql函数 Package 器中使用。不打算单独使用。
复杂度是必需的,因为在c函数的声明中没有办法硬连接字典(sql Package 函数可以做到这一点,并允许函数内联和表达式索引。

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$;

放下 PARALLEL SAFE 来自postgres 9.5或更高版本的两个函数。 public 作为安装扩展的架构( public 是默认值)。
显式类型声明( regdictionary )防止恶意用户使用函数的重载变体进行假设攻击。
以前,我提倡使用基于 STABLE 功能 unaccent() 随未安装模块一起提供。禁用了函数内联。这个版本的执行速度比我之前在这里使用的简单 Package 函数快十倍。
这已经是第一个版本的两倍了 SET search_path = public, pg_temp 直到我发现字典也可以是模式限定的。不过(postgres 12)从文档中看不太明显。
如果您缺乏创建c函数所需的特权,那么您将回到第二个最佳实现:一个 IMMUTABLE 函数 Package 器
STABLE unaccent() 模块提供的功能:

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;

最后,使用表达式索引来快速查询:

CREATE INDEX users_unaccent_name_idx ON users(public.f_unaccent(name));

记住,在对函数或字典进行任何更改之后,重新创建涉及此函数的索引,就像不重新创建索引的就地主要版本升级一样。最近的主要版本都有 unaccent 模块。
调整查询以匹配索引(以便查询规划器使用它):

SELECT * FROM users
WHERE  f_unaccent(name) = f_unaccent('João');

您不需要正确表达式中的函数。在这里,您还可以提供无注解的字符串,如 'Joao' 直接。
使用表达式索引时,faster函数不会转换为更快的查询。它对预先计算的值进行操作,并且已经非常快了。但是索引维护和查询不使用索引的好处。
postgres 10.3/9.6.8等加强了客户端程序的安全性。在任何索引中使用时,都需要对函数和字典名进行模式限定。请参见:
“文本搜索词典”uncent“不存在”词条在postgres日志中,假设在自动分析期间

连字

在postgres 9.5或更老的连字中,如'œ' 或'ß' 必须手动展开(如果需要),因为 unaccent() 始终替换单个字母:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
E A e a S

您会喜欢postgres 9.6中的uncent更新:
延伸 contrib/unaccent 的标准 unaccent.rules 文件来处理unicode已知的所有音调符号,并正确展开连字(thomas munro,lé奥纳德·贝内德蒂)
我的。现在我们得到:

SELECT unaccent('Œ Æ œ æ ß');

unaccent
----------
OE AE oe ae ss

模式匹配

为了 LIKE 或者 ILIKE 对于任意模式,请将其与模块相结合 pg_trgm 在postgresql 9.1或更高版本中。创建一个三角图(通常更可取)或gist表达式索引。琴酒示例:

CREATE INDEX users_unaccent_name_trgm_idx ON users
USING gin (f_unaccent(name) gin_trgm_ops);

可用于以下查询:

SELECT * FROM users
WHERE  f_unaccent(name) LIKE ('%' || f_unaccent('João') || '%');

gin和gist索引的维护成本高于普通btree:
gist和gin指数之间的差异
对于左锚定模式有更简单的解决方案。有关模式匹配和性能的详细信息:
postgresql中like、similor或正则表达式的模式匹配 pg_trgm 还为“相似性”提供了有用的运算符( % )和“距离”( <-> ).
三角形索引还支持简单的正则表达式 ~ 和不区分大小写的模式匹配 ILIKE :
postgresql重音+不区分大小写搜索

x6492ojm

x6492ojm2#

不,postgresql不支持这种排序规则

postgresql不支持这样的排序规则(不区分重音与否),因为除非二进制相等,否则任何比较都不能返回相等。这是因为在内部,它会给哈希索引之类的东西带来很多复杂性。因此,严格意义上的排序只影响顺序,而不影响相等。

变通办法

全文搜索词典,不包括词素。

对于fts,您可以使用 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;

你可以用函数索引,

-- 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));

现在可以非常简单地查询它

SELECT *
FROM myTable
WHERE to_tsvector('mydict', myCol) @@ 'foo & bar'

    mycol    
-------------
 fóó bar baz
(1 row)

另请参见
在字段上创建不区分大小写和重音/音调符号的搜索

孤零零的。

这个 unaccent 模块也可以自己使用,而无需fts集成,为此,请查看erwin的答案

aoyhnmkz

aoyhnmkz3#

我很确定postgresql依赖于底层操作系统进行排序。它确实支持创建新的排序规则和自定义排序规则。不过,我不确定你要做多少工作(可能很多。)

相关问题