PostgreSQL ltree

2021-09-16 15:48 更新
F.21.1. 定義
F.21.2. 操作符和函數(shù)
F.21.3. 索引
F.21.4. 例子
F.21.5. 轉(zhuǎn)換

這個(gè)模塊實(shí)現(xiàn)了一種數(shù)據(jù)類型ltree用于表示存儲(chǔ)在一個(gè)層次樹(shù)狀結(jié)構(gòu)中的數(shù)據(jù)的標(biāo)簽。還提供了在標(biāo)簽樹(shù)中搜索的擴(kuò)展功能。

這個(gè)模塊被視為trusted,也就是說(shuō),它可以是由擁有CREATE特權(quán)的非超級(jí)用戶安裝在當(dāng)前數(shù)據(jù)庫(kù)上。

F.21.1. 定義

一個(gè)標(biāo)簽是一個(gè)字母數(shù)字字符和下劃線的序列(例如,在 C 區(qū)域中允許字符A-Za-z0-9_)。 標(biāo)簽長(zhǎng)度必須少于 256 字符。

例子: 42, Personal_Services

一個(gè)標(biāo)簽路徑是由點(diǎn)號(hào)分隔的零個(gè)或者更多個(gè)標(biāo)簽的序列,例如L1.L2.L3,它表示一個(gè)從層次樹(shù)的根到一個(gè)特定節(jié)點(diǎn)的路徑。 一個(gè)標(biāo)簽路徑的長(zhǎng)度不能超過(guò)65535標(biāo)簽。

例子:Top.Countries.Europe.Russia

ltree模塊提供多種數(shù)據(jù)類型:

  • ltree存儲(chǔ)一個(gè)標(biāo)簽路徑。

  • lquery表示一個(gè)用于匹配ltree值的類正則表達(dá)式的模式。一個(gè)簡(jiǎn)單詞匹配一個(gè)路徑中的那個(gè)標(biāo)簽。 一個(gè)星號(hào)(*)匹配零個(gè)或更多個(gè)標(biāo)簽。它們可以用點(diǎn)連接起來(lái),以形成一個(gè)必須匹配整個(gè)標(biāo)簽路徑的模式。例如:

    foo         正好匹配標(biāo)簽路徑foo
    *.foo.*     匹配任何包含標(biāo)簽foo的標(biāo)簽路徑
    *.foo       匹配任何最后一個(gè)標(biāo)簽是foo的標(biāo)簽路徑
    

    星號(hào)和簡(jiǎn)單詞都可以被限定來(lái)限制它能匹配多少標(biāo)簽:

    *{n}        匹配正好n個(gè)標(biāo)簽
    *{n,}       匹配至少n個(gè)標(biāo)簽
    *{n,m}      匹配至少n個(gè)但是最多m個(gè)標(biāo)簽
    *{,m}       匹配最多m個(gè)標(biāo)簽 — 與*{0,m}相同 
    foo{n,m}    匹配至少 n 但是不超過(guò) m 并發(fā)的 foo
    foo{,}      匹配任何數(shù)量的并發(fā)的 foo, 包括零
    

    在缺乏任何顯式量詞的情況下,星號(hào)的默認(rèn)值是匹配任意數(shù)量的標(biāo)簽(也就是{,}),而非星號(hào)項(xiàng)的默認(rèn)值是只匹配一次(也就是{1})。

    有幾個(gè)修飾符可以放在一個(gè)非星號(hào)的lquery項(xiàng)的末尾,使它能匹配除了精確匹配之外更多的匹配:

    @           不區(qū)分大小寫匹配,例如a@匹配A
    *           匹配帶此前綴的任何標(biāo)簽,例如foo*匹配foobar
    %           匹配開(kāi)頭以下劃線分隔的詞
    

    %的行為有點(diǎn)復(fù)雜。它嘗試匹配詞而不是整個(gè)標(biāo)簽。例如,foo_bar%匹配foo_bar_baz但是不匹配foo_barbaz。如果和*組合,前綴匹配可以單獨(dú)應(yīng)用于每一個(gè)詞,例如foo_bar%*匹配 foo1_bar2_baz但不匹配foo1_br2_baz。

    此外,你可以寫多個(gè)帶有|(OR)的可能改過(guò)的非星號(hào)項(xiàng)目來(lái)匹配那些項(xiàng)目中的任何一個(gè)(或幾個(gè)),并且你可以在非星號(hào)組最前面放上!(NOT)來(lái)匹配任何不匹配那些分支的標(biāo)簽。 量詞,若有的話,位于組的末尾;它意味著作為一個(gè)整體的組的一些匹配(也就是說(shuō),一些匹配或不匹配任何替代的標(biāo)簽)。

    這里是一個(gè)lquery的例子:

    Top.*{0,2}.sport*@.!football|tennis{1,}.Russ*|Spain
    a.  b.     c.      d.                   e.
    

    這個(gè)查詢將匹配任何這樣的標(biāo)簽路徑:

    1. 開(kāi)始于標(biāo)簽Top

    2. 并且接著具有 0 到 2 個(gè)標(biāo)簽

    3. 之后是一個(gè)開(kāi)始于大小寫無(wú)關(guān)的前綴sport的標(biāo)簽

    4. 然后有一個(gè)或多個(gè)標(biāo)簽,沒(méi)有匹配footballtennis

    5. 并且結(jié)尾是一個(gè)開(kāi)始于Russ的標(biāo)簽,或者完全匹配Spain的標(biāo)簽。

  • ltxtquery表示一種用于匹配ltree值的類全文搜索的模式。一個(gè)ltxtquery值包含詞,也可能在末尾帶有修飾符@、*、%,修飾符具有和lquery中相同的含義。詞可以用 &(AND)、|(OR)、!(NOT)以及圓括號(hào)組合。lqueryltxtquery的關(guān)鍵區(qū)別是前者匹配詞時(shí)不考慮它們?cè)跇?biāo)簽路徑中的位置。

    這是一個(gè)ltxtquery的例子:

    Europe & Russia*@ & !Transportation
    

    這將匹配包含標(biāo)簽Europe以及任何以Russia開(kāi)始(大小寫不敏感)的標(biāo)簽的路徑,但是不匹配包含標(biāo)簽Transportation的路徑。這些詞在路徑中的位置并不重要。還有,當(dāng)使用%時(shí),該次可以與一個(gè)標(biāo)簽中任何下劃線分隔的詞匹配,而不管它們的位置如何。

注意:ltxtquery允許符號(hào)之間的空白,但是ltreelquery不允許。

F.21.2. 操作符和函數(shù)

類型ltree有普通比較操作符 =、<><、>、<=>=。 比較會(huì)按照樹(shù)遍歷的順序排序,一個(gè)節(jié)點(diǎn)的子女按照標(biāo)簽文本排序。另外,還有 表 F.13中顯示的特殊操作符。

表 F.13. ltree 操作符

操作符

描述

ltree @> ltreeboolean

左參數(shù)是右參數(shù)(或相等)的祖先么?

ltree <@ ltreeboolean

左參數(shù)是右參數(shù)(或相等)的后代么?

ltree ~ lqueryboolean

lquery ~ ltreeboolean

ltree 匹配 lquery么?

ltree ? lquery[]boolean

lquery[] ? ltreeboolean

ltree 在數(shù)組中匹配任何 lquery 么?

ltree @ ltxtqueryboolean

ltxtquery @ ltreeboolean

ltree 匹配 ltxtquery么?

ltree || ltreeltree

連接 ltree 路徑。

ltree || textltree

text || ltreeltree

把文本轉(zhuǎn)換為 ltree 并連接。

ltree[] @> ltreeboolean

ltree <@ ltree[]boolean

數(shù)組中包含一個(gè) ltree的祖先么?

ltree[] <@ ltreeboolean

ltree @> ltree[]boolean

數(shù)組中包含一個(gè) ltree的后代么?

ltree[] ~ lqueryboolean

lquery ~ ltree[]boolean

數(shù)組中包含匹配 lquery的任何路徑么?

ltree[] ? lquery[]boolean

lquery[] ? ltree[]boolean

Does ltree 數(shù)組中包含匹配任何lquery的任何路徑么?

ltree[] @ ltxtqueryboolean

ltxtquery @ ltree[]boolean

數(shù)組中包含匹配ltxtquery的任何路徑么?

ltree[] ?@> ltreeltree

返回作為ltree祖先的第一個(gè)數(shù)組條目,如果沒(méi)有則返回NULL。

ltree[] ?<@ ltreeltree

返回作為ltree后代的第一個(gè)數(shù)組條目,如果沒(méi)有則返回NULL。

ltree[] ?~ lqueryltree

返回匹配lquery的第一個(gè)數(shù)組條目,如果沒(méi)有,則返回NULL。

ltree[] ?@ ltxtqueryltree

返回匹配ltxtquery的第一個(gè)數(shù)組條目,如果沒(méi)有,則返回NULL。


操作符<@@>、 @以及~有類似的、 ^<@、^@>、^@^~,只是它們不適用索引。它們只對(duì)測(cè)試目的有用。

可用的函數(shù)在表 F.14中。

表 F.14. ltree 函數(shù)

函數(shù)

描述

例子

subltree ( ltree, start integer, end integer ) → ltree

返回從位置start到位置end-1的ltree的子路徑(從0開(kāi)始計(jì)數(shù))。

subltree('Top.Child1.Child2', 1, 2)Child1

subpath ( ltree, offset integer, len integer ) → ltree

返回從位置offset開(kāi)始的ltree的子路徑,長(zhǎng)度為len。 如果offset為負(fù),則子路徑從距離路徑終點(diǎn)的遠(yuǎn)端開(kāi)始。如果len為負(fù),將許多標(biāo)簽留在路徑的末尾。

subpath('Top.Child1.Child2', 0, 2)Top.Child1

subpath ( ltree, offset integer ) → ltree

返回從位置offset開(kāi)始的ltree的子路徑,擴(kuò)展到路徑的結(jié)束。 如果offset為負(fù),則子路徑從距離路徑終點(diǎn)的遠(yuǎn)端開(kāi)始。

subpath('Top.Child1.Child2', 1)Child1.Child2

nlevel ( ltree ) → integer

返回路徑中標(biāo)簽的數(shù)量。

nlevel('Top.Child1.Child2')3

index ( a ltree, b ltree ) → integer

返回ba中第一次出現(xiàn)的位置,如果沒(méi)有發(fā)現(xiàn)則返回-1。

index('0.1.2.3.5.4.5.6.8.5.6.8', '5.6')6

index ( a ltree, b ltree, offset integer ) → integer

返回ba中第一次出現(xiàn)的位置,如果沒(méi)有發(fā)現(xiàn)則返回-1。 搜索從位置offset開(kāi)始;負(fù)的offset是指從路徑的末端開(kāi)始的-offset標(biāo)簽。

index('0.1.2.3.5.4.5.6.8.5.6.8', '5.6', -4)9

text2ltree ( text ) → ltree

轉(zhuǎn)換 textltree。

ltree2text ( ltree ) → text

轉(zhuǎn)換 ltreetext。

lca ( ltree [, ltree [, ... ]] ) → ltree

計(jì)算路徑的最長(zhǎng)公共祖先(最多可支持8個(gè)參數(shù))。

lca('1.2.3', '1.2.3.4.5.6')1.2

lca ( ltree[] ) → ltree

計(jì)算數(shù)組中的路徑的最長(zhǎng)公共祖先。

lca(array['1.2.3'::ltree,'1.2.3.4'])1.2


F.21.3. 索引

ltree支持一些能加速上述操作符的索引類型:

  • ltree上的 B-樹(shù)索引: <<==>=>

  • ltree 之上的GiST索引(gist_ltree_ops opclass): <、<=、=、 >=、>、 @>、<@、 @、~、?

    gist_ltree_ops GiST opclass將一組路徑標(biāo)簽近似計(jì)算為位圖簽名。 它的可選整數(shù)參數(shù)siglen決定了簽名的字節(jié)長(zhǎng)度。默認(rèn)簽名長(zhǎng)度為8字節(jié)。 簽名長(zhǎng)度的有效值在1到2024字節(jié)之間。更長(zhǎng)的簽名將導(dǎo)致更精確的搜索(掃描更小的索引部分和更少的堆頁(yè)),但代價(jià)是更大的索引。

    創(chuàng)建默認(rèn)簽名長(zhǎng)度為8字節(jié)的索引的例子:

    CREATE INDEX path_gist_idx ON test USING GIST (path);
    

    創(chuàng)建簽名長(zhǎng)度為100字節(jié)的索引的例子:

    CREATE INDEX path_gist_idx ON test USING GIST (path gist_ltree_ops(siglen=100));
    
  • ltree[] 之上的GiST索引(gist__ltree_ops opclass): ltree[] <@ ltree、ltree @> ltree[]@~、 ?

    gist__ltree_ops GiST opclass 的工作類似于gist_ltree_ops 并且也使用簽名長(zhǎng)度作為參數(shù)。 gist__ltree_ops中的siglen的默認(rèn)值為28字節(jié)。

    創(chuàng)建這樣一個(gè)默認(rèn)簽名長(zhǎng)度為28字節(jié)的索引的例子:

    CREATE INDEX path_gist_idx ON test USING GIST (array_path);
    

    創(chuàng)建這樣一個(gè)簽名長(zhǎng)度為100字節(jié)的索引的例子:

    CREATE INDEX path_gist_idx ON test USING GIST (array_path gist__ltree_ops(siglen=100));
    

    注意:這種索引類型是有損的。

F.21.4. 例子

這個(gè)例子使用下列數(shù)據(jù)(在源代碼發(fā)布的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);

現(xiàn)在,我們有一個(gè)表test,它被填充了描述下列層次的數(shù)據(jù):

                        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)

使用函數(shù)的路徑構(gòu)建:

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)

我們可以通過(guò)常見(jiàn)一個(gè)在路徑中指定位置插入標(biāo)簽的 SQL 函數(shù)來(lái)簡(jiǎn)化:

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)

F.21.5. 轉(zhuǎn)換

有一些額外的擴(kuò)展為 PL/Python 實(shí)現(xiàn)了ltree類型的轉(zhuǎn)換。 這些擴(kuò)展是ltree_plpythonu、ltree_plpython2u 以及ltree_plpython3u(PL/Python 命名習(xí)慣請(qǐng)見(jiàn) 第 45.1 節(jié))。如果安裝了這些轉(zhuǎn)換并且在 創(chuàng)建函數(shù)時(shí)指定了它們,ltree值會(huì)被映射為 Python 列表( 不過(guò),當(dāng)前并不支持逆向的轉(zhuǎn)換)。

小心

強(qiáng)烈建議轉(zhuǎn)換擴(kuò)展安裝在與ltree相同的模式中。否則,如果轉(zhuǎn)換擴(kuò)展的模式包含惡意用戶定義的對(duì)象,就會(huì)存在安裝時(shí)的安全隱患。

 


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)