當您需要在海量文本中進行全文檢索索引,並且希望對檢索結果基於相關度或時間戳記等欄位進行高效能排序時,RUM外掛程式是比PostgreSQL內建GIN索引更優的選擇。傳統的GIN索引在排序時需要回表(二次訪問資料表),導致效能瓶頸。RUM外掛程式通過在索引中預存排序所需的位置和附加資訊,避免了回表操作,可將特定情境下的查詢效能提升數倍。
適用範圍
支援的PolarDB PostgreSQL版的版本如下:
PostgreSQL 18(核心小版本2.0.18.1.2.0及以上)
PostgreSQL 17(核心小版本2.0.17.6.4.0及以上)
PostgreSQL 16(核心小版本2.0.16.8.3.0及以上)
PostgreSQL 15(核心小版本2.0.15.7.1.1及以上)
PostgreSQL 14(核心小版本2.0.14.5.3.0及以上)
外掛程式相容性:RUM外掛程式的
%操作符與smlar外掛程式的%操作符存在衝突。因此,這兩個外掛程式不能在同一個資料庫模式(Schema)下同時建立和使用。請在安裝前確認您的環境中沒有使用smlar外掛程式,或將它們安裝在不同的Schema中。
適用情境
在決定是否使用RUM外掛程式前,請參考下表瞭解其與原生GIN索引的核心差異,以便做出最適合您業務情境的技術選型。
對比維度 | GIN索引(內建) | RUM索引 | 決策建議 |
核心優勢 | 寫入效能好,索引體積相對較小。 | 排序效能高,支援短語搜尋和附加列排序。 | 需要對檢索結果排序的情境,請優先選擇RUM。 |
排序效能 | 慢。需要回表擷取排序依據,效能隨資料量增大而急劇下降。 | 快。直接在索引內完成排序,無需回表。 | 對全文檢索索引結果有高頻排序需求(如按相關性、時間、價格),推薦使用RUM。 |
短語搜尋 | 慢。需要回表擷取詞彙位置資訊以驗證短語。 | 快。詞彙位置資訊已在索引中,無需回表。 | 對短語搜尋效能有要求的情境,推薦使用RUM。 |
附加列排序 | 不支援。無法在索引中儲存額外列(如時間戳記)的資訊。 | 支援。可在索引中附加其他列,實現高效能自訂排序。 | 需要按文章發布時間、更新時間等排序的情境,RUM優勢大。 |
寫入效能 | 較快。 | 較慢。需要維護更複雜的索引結構。 | 在寫入密集型(高頻 |
索引體積 | 較小。 | 較大。需要額外空間儲存位置和附加資訊。 | 評估您的儲存成本,如果索引體積是主要瓶頸,可考慮RUM的 |
首碼搜尋 | 支援。 |
| 如果首碼搜尋是核心需求,避免使用RUM的 |
用RUM以空間換時間,通過增加索引體積和寫入開銷,有效提升了特定查詢情境(尤其是排序)的效能。如果您的業務核心是帶有複雜排序的全文檢索索引,RUM是理想選擇。如果您的業務主要是寫入密集型或僅需簡單文本匹配,GIN則更具成本效益。
注意事項
寫入效能與索引體積:RUM索引為了加速查詢,需要儲存額外資訊(如詞彙位置),這導致其索引體積通常大於GIN索引,並且在資料寫入和更新時,索引構建的開銷也更高。因此,在寫入密集型且對儲存空間敏感的情境下,需謹慎評估其成本。
不支援首碼搜尋的情境:使用
rum_tsvector_hash_ops或rum_tsvector_hash_addon_ops操作符類建立的索引,由於儲存的是詞素的雜湊值而非原文,因此不支援首碼搜尋。
安裝與卸載外掛程式
安裝外掛程式
在開始使用前,您需要在資料庫中執行以下命令來建立RUM外掛程式。
CREATE EXTENSION rum;卸載外掛程式
如果您不再需要RUM外掛程式,可以執行以下命令進行卸載。
DROP EXTENSION rum;使用方法
RUM外掛程式提供了多種操作符類(Operator Class),以支援不同的資料類型和查詢情境。您可以根據具體需求選擇合適的操作符類來建立索引。
操作符類(Operator Class)明確了RUM索引在處理特定資料類型時所需使用的一組操作,從而讓索引能夠正確地儲存和檢索該類型的資料。每個操作符類(Operator Class)都包含一組特定的操作符。當你WHERE子句或ORDER BY子句中使用這些受支援的操作符時,PostgreSQL就能利用RUM索引來有效地加速查詢。
因此,選擇正確的操作符類(Operator Class)是讓RUM索引生效的關鍵。更多資訊,請參見Operator Classes and Operator Families。
操作符
操作符 | 支援類型 | 傳回值類型 | 描述 |
A | 左 |
| 返回全文向量是否匹配查詢條件,會進行距離計算。 |
A | 左 |
| 返回全文向量和查詢條件的距離值,值越小相關性越高。 |
|
| 返回兩個值之間的絕對差值。
| |
A |
|
| 僅當 |
A |
|
| 僅當 |
Operator Class(操作符類)
操作符類 | 適用資料類型 | 支援的關鍵操作符 | 核心功能與說明 |
|
|
| 儲存 |
|
|
| 儲存
|
|
|
| 對非文本、非數群組類型的資料進行範圍查詢和距離排序。 |
|
|
| 在 說明 附加列的資料類型需有對應的 |
|
|
| 功能同
|
|
|
| 用於索引 |
|
|
| 索引數群組類型,支援包含、重疊等數組操作,並支援按數組間距離排序。 |
|
|
| 在數組索引的基礎上,附加一個額外列的資料,以支援更複雜的查詢情境。 說明 附加列的資料類型需有對應的 |
情境一:加速全文檢索索引結果的相關性排序
當您需要對全文檢索索引結果按相關性排序時,使用RUM索引可以避免GIN索引所需的額外排序開銷,實現高效能排序。
準備資料:首先,建立一張測試表。
CREATE TABLE t1( t text, t_vec tsvector GENERATED ALWAYS AS (to_tsvector('pg_catalog.english', t)) STORED ); -- 插入測試資料 INSERT INTO t1(t) VALUES ('The situation is most beautiful'); INSERT INTO t1(t) VALUES ('It is a beautiful'); INSERT INTO t1(t) VALUES ('It looks like a beautiful place');建立RUM索引:使用
rum_tsvector_ops操作符類為tsvector列建立RUM索引。CREATE INDEX t1_t_vec_idx ON t1 USING rum (t_vec rum_tsvector_ops);執行相關性排序查詢:使用
<=>操作符進行查詢。此操作符計算查詢與文本的距離,距離值越小,代表相關性越高。因此,通過ORDER BY即可實現按相關性降序排列。SET enable_seqscan TO off; SELECT t, t_vec <=> to_tsquery('english', 'beautiful | place') AS rank FROM t1 WHERE t_vec @@ to_tsquery('english', 'beautiful | place') ORDER BY t_vec <=> to_tsquery('english', 'beautiful | place');返回結果如下:
t | rank ---------------------------------+--------- It looks like a beautiful place | 8.22467 The situation is most beautiful | 16.4493 It is a beautiful | 16.4493
情境二:加速全文檢索索引與附加列的聯合排序
在日誌分析、電商搜尋等情境中,經常需要在全文檢索索引的同時,根據時間戳記或價格等附加欄位進行排序。RUM通過addon功能,可以將附加列的資訊存入索引,實現高效的聯集查詢和排序。
準備資料:建立一張包含
tsvector列和時間戳記列的表,並插入樣本資料。CREATE TABLE tsts (id int, t tsvector, d timestamp); INSERT INTO tsts VALUES (354, to_tsvector('wr qh'), '2016-05-16 14:21:22.326724'), (355, to_tsvector('wr qh'), '2016-05-16 13:21:22.326724'), (356, to_tsvector('ts op'), '2016-05-16 18:21:22.326724'), (358, to_tsvector('ts op'), '2016-05-16 23:21:22.326724'), (371, to_tsvector('wr qh'), '2016-05-17 06:21:22.326724'), (406, to_tsvector('wr qh'), '2016-05-18 17:21:22.326724'), (415, to_tsvector('wr qh'), '2016-05-19 02:21:22.326724');建立帶附加列的RUM索引:使用
rum_tsvector_addon_ops操作符類,並通過WITH子句指定附加列和主索引列。CREATE INDEX tsts_idx ON tsts USING rum (t rum_tsvector_addon_ops, d) WITH (attach = 'd', to = 't');說明關鍵文法
WITH (attach = 'd', to = 't')的作用是將d列(附加列,此處為時間戳記)的值附加到t列(主索引列,tsvector類型)的索引條目中。這使得資料庫在一次索引掃描中,就能同時利用t列的索引進行全文檢索索引,並利用附加的d列資訊進行高效排序,避免了回表查詢,從而有效提升效能。執行聯合排序查詢:查詢包含特定詞彙的記錄,並按時間戳記與目標時間的接近程度排序。
SET enable_seqscan TO off; EXPLAIN (costs off) SELECT id, d, d <=> '2016-05-16 14:21:25' AS distance FROM tsts WHERE t @@ 'wr&qh' ORDER BY d <=> '2016-05-16 14:21:25' LIMIT 5;執行計畫如下,排序和過濾均在一次索引掃描中完成。
QUERY PLAN ------------------------------------------------------------------------------ Limit -> Index Scan using tsts_idx on tsts Index Cond: (t @@ '''wr'' & ''qh'''::tsquery) Order By: (d <=> '2016-05-16 14:21:25'::timestamp without time zone)查詢結果如下:
id | d | distance -----+----------------------------+--------------- 354 | 2016-05-16 14:21:22.326724 | 2.673276 355 | 2016-05-16 13:21:22.326724 | 3602.673276 371 | 2016-05-17 06:21:22.326724 | 57597.326724 406 | 2016-05-18 17:21:22.326724 | 183597.326724 415 | 2016-05-19 02:21:22.326724 | 215997.326724
情境三:加速數組查詢與相似性排序
對於標籤系統或使用者畫像等情境,需要高效查詢包含特定元素的數組,並按數組元素的重合度或相似性進行排序。
準備資料:
CREATE TABLE test_array (id serial, i int2[]); INSERT INTO test_array(i) VALUES ('{}'), ('{0}'), ('{1,2,3,4}'), ('{1,2,3}'), ('{1,2}'), ('{1}');建立數組RUM索引:使用
rum_anyarray_ops操作符類為數群組類型的列建立索引。CREATE INDEX idx_array ON test_array USING rum (i rum_anyarray_ops);執行數組查詢與排序:查詢包含元素
1的記錄,並按與{1}的相似性排序。SELECT * FROM test_array WHERE i && '{1}' -- '&&' 操作符表示數組重疊 ORDER BY i <=> '{1}' ASC; -- '<=>' 操作符計算數組間的距離,值越小越相似返回結果如下:
i ----------- {1} {1,2} {1,2,3} {1,2,3,4}
情境四:反向索引,快速匹配查詢規則
在構建使用者訂閱、警示規則匹配等系統時,需要用一條新資料(如一篇文章)去快速匹配海量的存量查詢規則(如使用者的訂閱關鍵詞)。RUM支援對tsquery類型建立索引,實現高效的反向匹配。
準備查詢規則資料:
CREATE TABLE query (id serial, q tsquery, tag text); INSERT INTO query (q, tag) VALUES ('supernova & star', 'sn'), ('black', 'color'), ('big & bang & black & hole', 'bang'), ('spiral & galaxy', 'shape'), ('black & hole', 'color');建立
tsquery的RUM索引:CREATE INDEX query_idx ON query USING rum(q rum_tsquery_ops);執行反向匹配查詢:使用一篇新文章的
tsvector來匹配所有合格tsquery規則。SELECT * FROM query WHERE to_tsvector('black holes never exists before we think about them') @@ q;返回結果如下:
id | q | tag -----+----------+------- 2 | 'black' | color