本模組實現了一種名為 ltree
的資料型別,用於表示儲存在分層樹狀結構中的資料的標籤。提供了豐富的設施來搜尋標籤樹。
此模組被認為是“受信任的”,這意味著非超級使用者也可以在其擁有的資料庫上安裝它,前提是他們具有 CREATE
許可權。
一個 標籤 是由字母數字字元、下劃線和連字元組成的序列。有效的字母數字字元範圍取決於資料庫的 locale。例如,在 C locale 中,允許使用字元 A-Za-z0-9_-
。標籤的最大長度為 1000 個字元。
示例: 42
, Personal_Services
一個 標籤路徑 是由零個或多個由點分隔的標籤組成的序列,例如 L1.L2.L3
,它代表了從分層樹的根到特定節點的路徑。標籤路徑的長度不能超過 65535 個標籤。
示例: Top.Countries.Europe.Russia
ltree
模組提供了幾種資料型別:
ltree
儲存標籤路徑。
lquery
表示一種用於匹配 ltree
值的類正則表示式的模式。一個簡單的詞匹配路徑中的該標籤。星號(*
)匹配零個或多個標籤。這些可以與點連線起來形成一個必須匹配整個標籤路徑的模式。例如:
foo Match the exact label pathfoo
*.foo.* Match any label path containing the labelfoo
*.foo Match any label path whose last label isfoo
星號和簡單詞都可以量化以限制它們可以匹配的標籤數量。
*{n
} Match exactlyn
labels *{n
,} Match at leastn
labels *{n
,m
} Match at leastn
but not more thanm
labels *{,m
} Match at mostm
labels — same as *{0,m
} foo{n
,m
} Match at leastn
but not more thanm
occurrences offoo
foo{,} Match any number of occurrences offoo
, including zero
如果沒有顯式量詞,星號的預設行為是匹配任意數量的標籤(即 {,}
),而非星號項的預設行為是匹配一次(即 {1}
)。
有幾個修飾符可以放在非星號 lquery
項的末尾,使其不僅僅匹配精確匹配:
@ Match case-insensitively, for examplea@
matchesA
* Match any label with this prefix, for examplefoo*
matchesfoobar
% Match initial underscore-separated words
%
的行為有點複雜。它試圖匹配詞而不是整個標籤。例如,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
型別具有常規的比較運算子 =
、<>
、<
、>
、<=
、>=
。比較排序順序為樹遍歷順序,節點的子節點按標籤文字排序。此外,還可以使用 表 F.12 中所示的專用運算子。
表 F.12. ltree
運算子
運算子 描述 |
---|
左引數是否為右引數的祖先(或相等)? |
左引數是否為右引數的後代(或相等)? |
|
|
|
連線 |
將文字轉換為 |
陣列是否包含 |
陣列是否包含 |
陣列是否包含任何匹配 |
|
陣列是否包含任何匹配 |
返回陣列中是 |
返回陣列中是 |
返回陣列中第一個匹配 |
返回陣列中第一個匹配 |
運算子 <@
、@>
、@
和 ~
有對應的 ^<@
、^@>
、^@
、^~
,它們的功能相同,只是不使用索引。這些僅用於測試目的。
可用的函式如 表 F.13 所示。
表 F.13. ltree
函式
ltree
支援幾種型別的索引,可以加速指示的運算子:
B-tree 索引,適用於 ltree
:<
, <=
, =
, >=
, >
Hash 索引,適用於 ltree
:=
GiST 索引,適用於 ltree
(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));
GiST 索引,適用於 ltree[]
(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)
ltree_plpython3u
擴充套件為 PL/Python 實現 ltree
型別提供了轉換。如果安裝並指定了此擴充套件,則 ltree
值將被對映到 Python 列表。(反向轉換目前尚不支援。)
所有工作由 Teodor Sigaev(<teodor@stack.net>
)和 Oleg Bartunov(<oleg@sai.msu.su>
)完成。有關更多資訊,請參閱 http://www.sai.msu.su/~megera/postgres/gist/。作者感謝 Eugeny Rodichev 的有益討論。歡迎提供反饋和錯誤報告。
如果您在文件中發現任何不正確、不符合您對特定功能的實際體驗或需要進一步澄清的內容,請使用 此表單 報告文件問題。