此模組實作了一種資料類型 ltree
,用於表示儲存在階層式樹狀結構中的資料標籤。它提供了廣泛的功能來搜尋標籤樹。
此模組被認為是「信任的」,也就是說,擁有目前資料庫 CREATE
權限的非超級使用者也可以安裝它。
標籤是由字母數字字元、底線和連字號組成的序列。有效的字母數字字元範圍取決於資料庫的語言環境。例如,在 C 語言環境中,允許使用字元 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
: <
、<=
、=
、>=
、>
雜湊索引於 ltree
: =
GiST 索引於 ltree
( gist_ltree_ops
opclass): <
、<=
、=
、>=
、>
、@>
、<@
、@
、~
、?
gist_ltree_ops
GiST opclass 將一組路徑標籤近似為點陣圖簽章。其可選的整數參數 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
opclass): ltree[] <@ ltree
、ltree @> ltree[]
、@
、~
、?
gist__ltree_ops
GiST opclass 的運作方式與 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 列表。(但是,目前不支援反向操作。)
強烈建議將轉換擴充功能安裝在與 ltree
相同的綱要中。 否則,如果轉換擴充功能的綱要包含由惡意使用者定義的物件,則在安裝時會存在安全風險。
所有工作均由 Teodor Sigaev (<teodor@stack.net>
) 和 Oleg Bartunov (<oleg@sai.msu.su>
) 完成。 有關其他資訊,請參閱 http://www.sai.msu.su/~megera/postgres/gist/。 作者要感謝 Eugeny Rodichev 的有益討論。 歡迎提供意見和錯誤報告。
如果您在文件中發現任何不正確之處、與您使用特定功能的經驗不符,或需要進一步澄清,請使用此表格來報告文件問題。