F.49. rum

F.49.1. Введение

Модуль rum предоставляет метод доступа RUM для работы с индексами. Он основан на коде методов доступа GIN.

Индексы GIN позволяют выполнять быстрый полнотекстовый поиск, используя типы tsvector и tsquery. Однако могут возникнуть некоторые проблемы с производительностью из-за того, что информация о позициях лексем и другая дополнительная информация не сохраняются.

Индекс RUM решает эти проблемы, сохраняя дополнительную информацию в дереве идентификаторов и обладает следующими преимуществами перед GIN:

  • Ускорение ранжирования. Для ранжирования необходима информация о позициях лексем. После сканирования индекса RUM нет необходимости в сканировании собственно данных, так как индекс сохраняет позиции лексем.

  • Ускорение поиска фраз. Это преимущество связано с предыдущим, так как для поиска фраз также необходима информация о позициях лексем.

  • Ускорение упорядочивания по меткам времени. Вместе с лексемами индекс RUM сохраняет дополнительную информацию, поэтому не требуется сканирование собственно данных.

  • Возможность производить поиск «сначала в глубину», а значит сразу выдавать первые результаты.

Недостаток RUM состоит в том, что он строится и изменяется медленнее, чем GIN, потому что RUM хранит помимо ключей дополнительную информацию и использует унифицированные записи WAL.

F.49.2. Установка

rum — это обычное расширение Postgres Pro Standard без каких-либо особых предварительных требований.

Процедура установки выглядит следующим образом:

 $ psql имя_бд -c "CREATE EXTENSION rum" 

F.49.3. Общие операторы

Реализованные в модуле rum операторы перечислены в Таблице F.34:

Таблица F.34. Операторы rum

ОператорВозвращаетОписание
tsvector<=>tsqueryfloat4Возвращает расстояние между значениями tsvector и tsquery.
timestamp<=>timestampfloat8Возвращает расстояние между двумя значениями timestamp.
timestamp<=|timestampfloat8Возвращает расстояние только для возрастающих значений timestamp.
timestamp|=>timestampfloat8Возвращает расстояние только для убывающих значений timestamp.

Примечание

rum вводит собственную функцию ранжирования, которая выполняется внутри оператора <=> и вычисляет оценку (инвертированное расстояние), используя заданный метод реализации. Она представляет собой сочетание функций ts_rank и ts_rank_cd (за подробностями обратитесь к Разделу 9.13). В то время, как ts_rank не поддерживает логические операции, а ts_rank_cd плохо работает с запросами OR, доступная в rum функция ранжирования лишена этих недостатков.

F.49.4. Классы операторов

Расширение rum предоставляет следующие классы операторов:

rum_tsvector_ops

Сохраняет лексемы tsvector с информацией о позициях. Поддерживает упорядочивание с оператором <=> и поиск по префиксу.

rum_tsvector_hash_ops

Сохраняет хеш лексем tsvector с информацией о позициях. Поддерживает упорядочивание с оператором <=>, но не поддерживает поиск по префиксу.

rum_tsvector_addon_ops

Сохраняет лексемы tsvector с дополнительными данными любых типов, которые принимает RUM.

Примечание

Чтобы использовать классы операторов rum_tsvector_addon_ops, при создании индекса RUM командой CREATE INDEX задайте параметры хранения attach и to в предложении WITH.

rum_tsvector_hash_addon_ops

Сохраняет лексемы tsvector с дополнительными данными любых типов, которые принимает RUM. Не поддерживает поиск по префиксу.

rum_tsquery_ops

Сохраняет ветви дерева запроса в дополнительной информации.

rum_anyarray_ops

Сохраняет элементы массива anyarray и длину массива. Поддерживает упорядочивание с оператором <=>.

Индексируемые операторы: && @> <@ = %

rum_anyarray_addon_ops

Сохраняет элементы anyarray с дополнительными данными любых типов, которые принимает RUM.

rum_type_ops

Сохраняет лексемы соответствующего типа с информацией о позициях. В качестве типа в имени класса должно подставляться одно из следующих имён типов: int2, int4, int8, float4, float8, money, oid, timestamp, timestamptz, time, timetz, date, interval, macaddr, inet, cidr, text, varchar, char, bytea, bit, varbit, numeric.

Класс операторов rum_тип_ops поддерживает упорядочивание с операторами <=>, <=| и |=>. Его можно использовать совместно с классами операторов rum_tsvector_addon_ops, rum_tsvector_hash_addon_ops и rum_anyarray_addon_ops.

Поддержка индексируемых операторов зависит от типа данных:

  • Операторы < <= = >= > <=> <=| |=> поддерживаются для типов int2, int4, int8, float4, float8, money, oid, timestamp, timestamptz.

  • Операторы < <= = >= > поддерживаются для типов time, timetz, date, interval, macaddr, inet, cidr, text, varchar, char, bytea, bit, varbit, numeric.

Примечание

Следующие классы операторов теперь считаются устаревшими: rum_tsvector_timestamp_ops, rum_tsvector_timestamptz_ops, rum_tsvector_hash_timestamp_ops, rum_tsvector_hash_timestamptz_ops.

F.49.5. Примеры

F.49.5.1. Пример с rum_tsvector_ops

Предположим, что у нас есть таблица:

CREATE TABLE test_rum(t text, a tsvector); CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON test_rum FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger('a', 'pg_catalog.english', 't'); INSERT INTO test_rum(t) VALUES ('The situation is most beautiful'); INSERT INTO test_rum(t) VALUES ('It is a beautiful'); INSERT INTO test_rum(t) VALUES ('It looks like a beautiful place');

Затем мы можем создать новый индекс:

CREATE INDEX rumidx ON test_rum USING rum (a rum_tsvector_ops);

И выполнять следующие запросы:

SELECT t, a <=> to_tsquery('english', 'beautiful | place') AS rank FROM test_rum WHERE a @@ to_tsquery('english', 'beautiful | place') ORDER BY a <=> to_tsquery('english', 'beautiful | place'); t | rank ---------------------------------+----------- The situation is most beautiful | 0.0303964 It is a beautiful | 0.0303964 It looks like a beautiful place | 0.0607927 (3 rows) SELECT t, a <=> to_tsquery('english', 'place | situation') AS rank FROM test_rum WHERE a @@ to_tsquery('english', 'place | situation') ORDER BY a <=> to_tsquery('english', 'place | situation'); t | rank ---------------------------------+----------- The situation is most beautiful | 0.0303964 It looks like a beautiful place | 0.0303964 (2 rows)

F.49.5.2. Пример с rum_tsvector_addon_ops

Предположим, что у нас есть таблица:

CREATE TABLE tsts (id int, t tsvector, d timestamp); \copy tsts from 'rum/data/tsts.data' CREATE INDEX tsts_idx ON tsts USING rum (t rum_tsvector_addon_ops, d) WITH (attach = 'd', to = 't');

С ним мы можем выполнять подобные запросы:

EXPLAIN (costs off) SELECT id, d, d <=> '2016-05-16 14:21:25' 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 <=> 'Mon May 16 14:21:25 2016'::timestamp without time zone) (4 rows) SELECT id, d, d <=> '2016-05-16 14:21:25' FROM tsts WHERE t @@ 'wr&qh' ORDER BY d <=> '2016-05-16 14:21:25' LIMIT 5; id | d | ?column? -----+---------------------------------+--------------- 355 | Mon May 16 14:21:22.326724 2016 | 2.673276 354 | Mon May 16 13:21:22.326724 2016 | 3602.673276 371 | Tue May 17 06:21:22.326724 2016 | 57597.326724 406 | Wed May 18 17:21:22.326724 2016 | 183597.326724 415 | Thu May 19 02:21:22.326724 2016 | 215997.326724 (5 rows)

F.49.5.3. Пример с rum_tsquery_ops

Предположим, что у нас таблица:

CREATE TABLE query (q tsquery, tag text); INSERT INTO query VALUES ('supernova & star', 'sn'), ('black', 'color'), ('big & bang & black & hole', 'bang'), ('spiral & galaxy', 'shape'), ('black & hole', 'color'); CREATE INDEX query_idx ON query USING rum(q);

Мы можем выполнить следующий быстрый запрос:

SELECT * FROM query WHERE to_tsvector('black holes never exists before we think about them') @@ q; q | tag ------------------+------- 'black' | color 'black' & 'hole' | color (2 rows)

F.49.5.4. Пример с rum_anyarray_ops

Предположим, что у нас есть таблица:

CREATE TABLE test_array (i int2[]); INSERT INTO test_array VALUES ('{}'), ('{0}'), ('{1,2,3,4}'), ('{1,2,3}'), ('{1,2}'), ('{1}'); CREATE INDEX idx_array ON test_array USING rum (i rum_anyarray_ops);

Теперь мы можем выполнить следующий запрос, используя сканирование индекса:

SET enable_seqscan TO off; EXPLAIN (COSTS OFF) SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC; QUERY PLAN ------------------------------------------ Index Scan using idx_array on test_array Index Cond: (i && '{1}'::smallint[]) Order By: (i <=> '{1}'::smallint[]) (3 rows) SELECT * FROM test_array WHERE i && '{1}' ORDER BY i <=> '{1}' ASC; i ----------- {1} {1,2} {1,2,3} {1,2,3,4} (4 rows)

F.49.6. Авторы

Александр Коротков

Олег Бартунов

Фёдор Сигаев

close