该模块实现了数据类型 ltree,用于表示存储在层次化树状结构中的数据标签。 它还提供了丰富的标签树搜索能力。
该模块被认为是“受信任的”,也就是说,它可以由在当前数据库上具有 CREATE 权限的非超级用户安装。
标签是由字母数字字符和下划线组成的序列(例如,在 C 区域设置下,允许的字符为 A-Za-z0-9_)。标签长度必须少于 256 个字符。
示例:42、Personal_Services
标签路径是由点号分隔的零个或多个标签组成的序列,例如 L1.L2.L3,表示从层次树根节点到某个特定节点的一条路径。 标签路径的长度不能超过 65535 个标签。
示例:Top.Countries.Europe.Russia
ltree模块提供了几种数据类型:
ltree存储一个标签路径。
lquery表示一种用于匹配ltree值的、类似正则表达式的模式。 一个简单单词会匹配路径中的相应标签。星号(*)可匹配零个或多个标签。 它们可以用点号连接起来,组成一个必须匹配整个标签路径的模式。例如:
foo 精确匹配标签路径foo*.foo.* 匹配任何包含标签foo的标签路径 *.foo 匹配最后一个标签为foo的任意标签路径
星号和简单单词都可以带量词,以限制它们能够匹配的标签数量:
*{n} 精确匹配 n 个标签
*{n,} 至少匹配 n 个标签
*{n,m} 至少匹配 n 个、但不超过 m 个标签
*{,m} 至多匹配 m 个标签,与下式相同:*{0,m}
foo{n,m} 至少匹配 n 次、但不超过 m 次 foo
foo{,} 匹配任意次数的 foo,包括零次
如果没有显式量词,星号默认匹配任意数量的标签(即 {,}),而非星号项默认恰好匹配一次(即 {1})。
有几个修饰符可以放在非星号lquery项的末尾,使其不只匹配完全相同的标签:
@ 不区分大小写地匹配,例如a@可匹配A* 匹配以此前缀开头的任意标签,例如foo*可匹配foobar% 匹配标签起始处由下划线分隔的单词
%的行为稍微复杂一些。它尝试匹配单词,而不是整个标签。例如, foo_bar%可匹配foo_bar_baz,但不能匹配 foo_barbaz。如果与*组合使用,则前缀匹配会分别作用于每个单词,例如 foo_bar%*可匹配foo1_bar2_baz,但不能匹配 foo1_br2_baz。
此外,还可以写出多个可带修饰符的非星号项,并用|(OR)分隔,以匹配其中任意一项; 也可以在非星号组前加上!(NOT),以匹配不符合这些备选项中任意一项的标签。 如果有量词,就放在该组末尾;它表示整个组的匹配次数(也就是若干个标签匹配或不匹配这些备选项中的任意一项)。
下面是一个带注释的lquery示例:
Top.*{0,2}.sport*@.!football|tennis{1,}.Russ*|Spain
a. b. c. d. e.
这个查询将匹配满足以下条件的任意标签路径:
以标签Top开头
接下来,在下一个条件之前有零到两个标签
然后是一个以前缀sport开头的标签,且匹配时不区分大小写
接着有一个或多个标签,这些标签都不匹配football或tennis
最后以一个以Russ开头的标签,或精确匹配Spain的标签结束。
ltxtquery表示一种用于匹配ltree值的、类似全文检索的模式。 一个ltxtquery值包含单词,末尾还可以带有修饰符@、*、%; 这些修饰符与它们在lquery中的含义相同。单词可以通过&(AND)、 |(OR)、!(NOT)以及圆括号组合。 它与lquery的关键区别在于,ltxtquery匹配单词时不考虑它们在标签路径中的位置。
下面是一个ltxtquery示例:
Europe & Russia*@ & !Transportation
它将匹配包含标签Europe以及任意以Russia开头(不区分大小写)的标签的路径, 但不匹配包含标签Transportation的路径。这些单词在路径中的位置并不重要。 另外,当使用%时,该单词可以匹配标签中任意由下划线分隔的单词,而不考虑其位置。
注意:ltxtquery允许在符号之间出现空白,而ltree和lquery不允许。
类型ltree具有常见的比较操作符 =、<>、 <、>、<=、>=。 比较时采用树遍历顺序,其中节点的子节点按标签文本排序。此外,还提供了 Table F.12中所示的专用操作符。
Table F.12. ltree 操作符
|
操作符 描述 |
|---|
|
左参数是否为右参数的祖先(或与之相等)? |
|
左参数是否为右参数的后代(或与之相等)? |
|
|
|
|
|
|
|
连接 |
|
将文本转换为 |
|
数组是否包含 |
|
数组是否包含 |
|
数组是否包含匹配 |
|
|
|
数组是否包含匹配 |
|
返回数组中第一个是 |
|
返回数组中第一个是 |
|
返回数组中第一个匹配 |
|
返回数组中第一个匹配 |
操作符<@、@>、 @和~都有对应的 ^<@、^@>、^@、 ^~变体,它们除了不使用索引之外完全相同。这些变体仅对测试有用。
可用函数见Table F.13。
Table F.13. ltree 函数
ltree支持几种能够加速所示操作符的索引类型:
ltree上的 B-树索引: <、<=、=、 >=、>
ltree上的哈希索引: =
ltree上的 GiST 索引(gist_ltree_ops 操作符类): <、<=、=、 >=、>、 @>、<@、 @、~、?
gist_ltree_ops GiST 操作符类将一组路径标签近似为位图签名。 其可选整数参数siglen决定签名长度(以字节计)。默认签名长度为 8 字节。 该长度必须是按int对齐的正整数倍(在大多数机器上为 4 字节),最大不能超过 2024。 更长的签名会带来更精确的搜索(扫描更小比例的索引以及更少的堆页),但代价是索引更大。
使用默认 8 字节签名长度创建此类索引的示例:
CREATE INDEX path_gist_idx ON test USING GIST (path);
使用 100 字节签名长度创建此类索引的示例:
CREATE INDEX path_gist_idx ON test USING GIST (path gist_ltree_ops(siglen=100));
ltree[]上的 GiST 索引(gist__ltree_ops 操作符类): ltree[] <@ ltree、ltree @> ltree[]、 @、~、?
gist__ltree_ops GiST 操作符类的工作方式与 gist_ltree_ops类似,也接受签名长度作为参数。 在gist__ltree_ops中,siglen的默认值为 28 字节。
使用默认 28 字节签名长度创建此类索引的示例:
CREATE INDEX path_gist_idx ON test USING GIST (array_path);
使用 100 字节签名长度创建此类索引的示例:
CREATE INDEX path_gist_idx ON test USING GIST (array_path gist__ltree_ops(siglen=100));
注意:这种索引类型是有损的。
本示例使用下列数据(在源代码发行包中的 contrib/ltree/ltreetest.sql文件里也能找到):
CREATE TABLE test (path ltree);
INSERT INTO test VALUES ('Top');
INSERT INTO test VALUES ('Top.Science');
INSERT INTO test VALUES ('Top.Science.Astronomy');
INSERT INTO test VALUES ('Top.Science.Astronomy.Astrophysics');
INSERT INTO test VALUES ('Top.Science.Astronomy.Cosmology');
INSERT INTO test VALUES ('Top.Hobbies');
INSERT INTO test VALUES ('Top.Hobbies.Amateurs_Astronomy');
INSERT INTO test VALUES ('Top.Collections');
INSERT INTO test VALUES ('Top.Collections.Pictures');
INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy');
INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Stars');
INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Galaxies');
INSERT INTO test VALUES ('Top.Collections.Pictures.Astronomy.Astronauts');
CREATE INDEX path_gist_idx ON test USING GIST (path);
CREATE INDEX path_idx ON test USING BTREE (path);
CREATE INDEX path_hash_idx ON test USING HASH (path);
现在,我们有一个表test,其中的数据描述了下图所示的层次结构:
Top
/ | \
Science Hobbies Collections
/ | \
Astronomy Amateurs_Astronomy Pictures
/ \ |
Astrophysics Cosmology Astronomy
/ | \
Galaxies Stars Astronauts
我们可以做继承查询:
ltreetest=> SELECT path FROM test WHERE path <@ 'Top.Science';
path
------------------------------------
Top.Science
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
(4 rows)
下面是一些路径匹配示例:
ltreetest=> SELECT path FROM test WHERE path ~ '*.Astronomy.*';
path
-----------------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
Top.Collections.Pictures.Astronomy
Top.Collections.Pictures.Astronomy.Stars
Top.Collections.Pictures.Astronomy.Galaxies
Top.Collections.Pictures.Astronomy.Astronauts
(7 rows)
ltreetest=> SELECT path FROM test WHERE path ~ '*.!pictures@.Astronomy.*';
path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
(3 rows)
下面是一些全文检索示例:
ltreetest=> SELECT path FROM test WHERE path @ 'Astro*% & !pictures@';
path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
Top.Hobbies.Amateurs_Astronomy
(4 rows)
ltreetest=> SELECT path FROM test WHERE path @ 'Astro* & !pictures@';
path
------------------------------------
Top.Science.Astronomy
Top.Science.Astronomy.Astrophysics
Top.Science.Astronomy.Cosmology
(3 rows)
使用函数构造路径:
ltreetest=> SELECT subpath(path,0,2)||'Space'||subpath(path,2) FROM test WHERE path <@ 'Top.Science.Astronomy';
?column?
------------------------------------------
Top.Science.Space.Astronomy
Top.Science.Space.Astronomy.Astrophysics
Top.Science.Space.Astronomy.Cosmology
(3 rows)
我们可以通过创建一个 SQL 函数来简化这一操作,该函数会在路径的指定位置插入一个标签:
CREATE FUNCTION ins_label(ltree, int, text) RETURNS ltree
AS 'select subpath($1,0,$2) || $3 || subpath($1,$2);'
LANGUAGE SQL IMMUTABLE;
ltreetest=> SELECT ins_label(path,2,'Space') FROM test WHERE path <@ 'Top.Science.Astronomy';
ins_label
------------------------------------------
Top.Science.Space.Astronomy
Top.Science.Space.Astronomy.Astrophysics
Top.Science.Space.Astronomy.Cosmology
(3 rows)
有额外的扩展实现了 PL/Python 的ltree类型转换。这些扩展分别叫做ltree_plpythonu、ltree_plpython2u和ltree_plpython3u(关于 PL/Python 的命名约定请见Section 44.1)。如果安装了这些转换扩展,并在创建函数时指定它们,则ltree值会映射为 Python 列表。(不过,目前还不支持反向映射。)
强烈建议将转换扩展安装在与ltree相同的模式中。否则,如果转换扩展所在模式包含由恶意用户定义的对象,在安装时会存在安全隐患。
全部工作均由 Teodor Sigaev(<teodor@stack.net>)和 Oleg Bartunov(<oleg@sai.msu.su>)完成。更多信息见 http://www.sai.msu.su/~megera/postgres/gist/。 作者谨感谢 Eugeny Rodichev 的有益讨论。欢迎提出意见和缺陷报告。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。