F.19. hstore — hstore ключ/значение тип данных#

F.19. hstore — hstore ключ/значение тип данных

F.19. hstore — hstore ключ/значение тип данных #

Этот модуль реализует тип данных hstore для хранения наборов пар ключ/значение внутри одного значения Tantor BE. Это может быть полезно в различных сценариях, таких как строки с большим количеством атрибутов, которые редко проверяются, или полуструктурированные данные. Ключи и значения представляют собой простые текстовые строки.

Этот модуль считается "доверенным", то есть его можно установить недоступным пользователям, у которых есть привилегия CREATE в текущей базе данных.

F.19.1. hstore Внешнее представление #

Текстовое представление типа hstore, используемое для ввода и вывода, включает ноль или более пар key => value, разделенных запятыми. Некоторые примеры:

k => v
foo => bar, baz => whatever
"1-a" => "anything at all"

Порядок пар не имеет значения (и может не быть воспроизведен при выводе). Пробелы между парами или вокруг знака => игнорируются. Ключи и значения, содержащие пробелы, запятые, = или >, должны быть заключены в двойные кавычки. Чтобы включить двойную кавычку или обратную косую черту в ключ или значение, нужно экранировать их обратной косой чертой.

Каждый ключ в hstore является уникальным. Если вы объявляете hstore с повторяющимися ключами, только один будет сохранен в hstore, и нет гарантии, какой будет сохранен:

SELECT 'a=>1,a=>2'::hstore;
  hstore
----------
 "a"=>"1"

Значение (но не ключ) может быть SQL-NULL. Например:

key => NULL

Ключевое слово NULL нечувствительно к регистру. Для обработки его как обычной строки NULL используйте двойные кавычки.

Примечание

Учтите, что формат текста hstore, используемый для ввода, применяется до любого необходимого цитирования или экранирования. Если вы передаете литерал hstore через параметр, то дополнительная обработка не требуется. Но если вы передаете его как литерал в кавычках, то символы апострофа и (в зависимости от значения параметра конфигурации standard_conforming_strings) символы обратной косой черты должны быть корректно экранированы. См. Раздел 4.1.2.1 для получения дополнительной информации о работе со строковыми константами.

На выходе двойные кавычки всегда окружают ключи и значения, даже когда это не строго необходимо.

F.19.2. hstore Операторы и функции #

Операторы, предоставляемые модулем hstore, показаны в таблице Таблица F.7, функции - в таблице Таблица F.8.

Таблица F.7. hstore Операторы

Оператор

Описание

Пример(ы)

hstore -> texttext

Возвращает значение, связанное с заданным ключом, или NULL, если оно отсутствует.

'a=>x, b=>y'::hstore -> 'a'x

hstore -> text[]text[]

Возвращает значения, связанные с заданными ключами, или NULL, если они отсутствуют.

'a=>x, b=>y, c=>z'::hstore -> ARRAY['c','a']{"z","x"}

hstore || hstorehstore

Соединяет два hstore.

'a=>b, c=>d'::hstore || 'c=>x, d=>q'::hstore"a"=>"b", "c"=>"x", "d"=>"q"

hstore ? textboolean

Содержит ли hstore ключ?

'a=>1'::hstore ? 'a't

hstore ?& text[]boolean

Содержит ли hstore все указанные ключи?

'a=>1,b=>2'::hstore ?& ARRAY['a','b']t

hstore ?| text[]boolean

Содержит ли hstore какие-либо из указанных ключей?

'a=>1,b=>2'::hstore ?| ARRAY['b','c']t

hstore @> hstoreboolean

Содержит ли левый операнд правый?

'a=>b, b=>1, c=>NULL'::hstore @> 'b=>1't

hstore <@ hstoreboolean

Содержится ли левый операнд в правом?

'a=>c'::hstore <@ 'a=>b, b=>1, c=>NULL'f

hstore - texthstore

Удаляет ключ из левого операнда.

'a=>1, b=>2, c=>3'::hstore - 'b'::text"a"=>"1", "c"=>"3"

hstore - text[]hstore

Удаляет ключи из левого операнда.

'a=>1, b=>2, c=>3'::hstore - ARRAY['a','b']"c"=>"3"

hstore - hstorehstore

Удаляет пары из левого операнда, которые соответствуют парам в правом операнде.

'a=>1, b=>2, c=>3'::hstore - 'a=>4, b=>2'::hstore"a"=>"1", "c"=>"3"

anyelement #= hstoreanyelement

Заменяет поля в левом операнде (который должен быть составным типом) соответствующими значениями из hstore.

ROW(1,3) #= 'f1=>11'::hstore(11,3)

%% hstoretext[]

Преобразует hstore в массив чередующихся ключей и значений.

%% 'a=>foo, b=>bar'::hstore{a,foo,b,bar}

%# hstoretext[]

Преобразует hstore в двумерный массив ключ/значение.

%# 'a=>foo, b=>bar'::hstore{{a,foo},{b,bar}}


Таблица F.8. hstore Функции

Функция

Описание

Пример(ы)

hstore ( record ) → hstore

Создает hstore из записи или строки.

hstore(ROW(1,2))"f1"=>"1", "f2"=>"2"

hstore ( text[] ) → hstore

Создает hstore из массива, который может быть либо массивом ключей/значений, либо двумерным массивом.

hstore(ARRAY['a','1','b','2'])"a"=>"1", "b"=>"2"

hstore(ARRAY[['c','3'],['d','4']])"c"=>"3", "d"=>"4"

hstore ( text[], text[] ) → hstore

Создает hstore из отдельных массивов ключей и значений.

hstore(ARRAY['a','b'], ARRAY['1','2'])"a"=>"1", "b"=>"2"

hstore ( text, text ) → hstore

Создает одноэлементный hstore.

hstore('a', 'b')"a"=>"b"

akeys ( hstore ) → text[]

Извлекает ключи hstore в виде массива.

akeys('a=>1,b=>2'){a,b}

skeys ( hstore ) → setof text

Извлекает ключи hstore в виде набора.

skeys('a=>1,b=>2')

a
b

avals ( hstore ) → text[]

Извлекает значения hstore в виде массива.

avals('a=>1,b=>2'){1,2}

svals ( hstore ) → setof text

Извлекает значения hstore в виде набора.

svals('a=>1,b=>2')

1
2

hstore_to_array ( hstore ) → text[]

Извлекает ключи и значения hstore в виде массива, чередующихся ключей и значений.

hstore_to_array('a=>1,b=>2'){a,1,b,2}

hstore_to_matrix ( hstore ) → text[]

Извлекает ключи и значения hstore в виде двумерного массива.

hstore_to_matrix('a=>1,b=>2'){{a,1},{b,2}}

hstore_to_json ( hstore ) → json

Преобразует значение hstore в значение json, преобразуя все ненулевые значения в JSON-строки.

Эта функция используется неявно, когда значение hstore приводится к типу json.

hstore_to_json('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": "1", "b": "t", "c": null, "d": "12345", "e": "012345", "f": "1.234", "g": "2.345e+4"}

hstore_to_jsonb ( hstore ) → jsonb

Преобразует значение hstore в значение jsonb, преобразуя все ненулевые значения в JSON-строки.

Эта функция используется неявно, когда значение hstore приводится к типу jsonb.

hstore_to_jsonb('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": "1", "b": "t", "c": null, "d": "12345", "e": "012345", "f": "1.234", "g": "2.345e+4"}

hstore_to_json_loose ( hstore ) → json

Преобразует значение hstore в значение json, но пытается различать числовые и логические значения, чтобы они не были заключены в кавычки в JSON.

hstore_to_json_loose('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": 1, "b": true, "c": null, "d": 12345, "e": "012345", "f": 1.234, "g": 2.345e+4}

hstore_to_jsonb_loose ( hstore ) → jsonb

Преобразует значение hstore в значение jsonb, но пытается различать числовые и логические значения, чтобы они не были заключены в кавычки в JSON.

hstore_to_jsonb_loose('"a key"=>1, b=>t, c=>null, d=>12345, e=>012345, f=>1.234, g=>2.345e+4'){"a key": 1, "b": true, "c": null, "d": 12345, "e": "012345", "f": 1.234, "g": 2.345e+4}

slice ( hstore, text[] ) → hstore

Извлекает подмножество hstore, содержащее только указанные ключи.

slice('a=>1,b=>2,c=>3'::hstore, ARRAY['b','c','x'])"b"=>"2", "c"=>"3"

each ( hstore ) → setof record ( key text, value text )

Извлекает ключи и значения hstore в виде набора записей.

select * from each('a=>1,b=>2')

 key | value
-----+-------
 a   | 1
 b   | 2

exist ( hstore, text ) → boolean

Содержит ли hstore ключ?

exist('a=>1', 'a')t

defined ( hstore, text ) → boolean

Содержит ли значение hstore ненулевое значение для ключа?

defined('a=>NULL', 'a')f

delete ( hstore, text ) → hstore

Удаляет пару с соответствующим ключом.

delete('a=>1,b=>2', 'b')"a"=>"1"

delete ( hstore, text[] ) → hstore

Удаляет пары с совпадающими ключами.

delete('a=>1,b=>2,c=>3', ARRAY['a','b'])"c"=>"3"

delete ( hstore, hstore ) → hstore

Удаляет пары, соответствующие тем, которые указаны во втором аргументе.

delete('a=>1,b=>2', 'a=>4,b=>2'::hstore)"a"=>"1"

populate_record ( anyelement, hstore ) → anyelement

Заменяет поля в левом операнде (который должен быть составным типом) соответствующими значениями из hstore.

populate_record(ROW(1,2), 'f1=>42'::hstore)(42,2)


В дополнение к этим операторам и функциям, значения типа hstore могут быть индексированы, что позволяет им действовать как ассоциативные массивы. Может быть указан только один индекс типа text; он интерпретируется как ключ, и соответствующее значение извлекается или сохраняется. Например,

CREATE TABLE mytable (h hstore);
INSERT INTO mytable VALUES ('a=>b, c=>d');
SELECT h['a'] FROM mytable;
 h
---
 b
(1 row)

UPDATE mytable SET h['c'] = 'new';
SELECT h FROM mytable;
          h
----------------------
 "a"=>"b", "c"=>"new"
(1 row)

Подстрочный запрос возвращает NULL, если подстрока равна NULL или ключ не существует в hstore. (Таким образом, подстрочный запрос не сильно отличается от оператора ->). Подстрочное обновление завершается неудачей, если подстрока равна NULL; в противном случае оно заменяет значение для этого ключа, добавляя запись в hstore, если ключ еще не существует.

F.19.3. Индексы #

hstore имеет поддержку индексов GiST и GIN для операторов @>, ?, ?& и ?|. Например:

CREATE INDEX hidx ON testhstore USING GIST (h);

CREATE INDEX hidx ON testhstore USING GIN (h);

gist_hstore_ops Оператор GiST приближает набор пар ключ/значение в виде битовой подписи. Его необязательный целочисленный параметр siglen определяет длину подписи в байтах. По умолчанию длина составляет 16 байт. Допустимые значения длины подписи находятся в диапазоне от 1 до 2024 байт. Более длинные подписи обеспечивают более точный поиск (сканирование меньшей доли индекса и меньшее количество страниц кучи), но требуют большего объема индекса.

Пример создания такого индекса с длиной сигнатуры 32 байта:

CREATE INDEX hidx ON testhstore USING GIST (h gist_hstore_ops(siglen=32));

hstore также поддерживает индексы btree или hash для оператора =. Это позволяет объявлять столбцы hstore как UNIQUE или использовать их в выражениях GROUP BY, ORDER BY или DISTINCT. Порядок сортировки для значений hstore не особенно полезен, но эти индексы могут быть полезны для поиска эквивалентности. Создайте индексы для сравнений = следующим образом:

CREATE INDEX hidx ON testhstore USING BTREE (h);

CREATE INDEX hidx ON testhstore USING HASH (h);

F.19.4. Примеры #

Добавить ключ или обновить существующий ключ новым значением:

UPDATE tab SET h['c'] = '3';

Еще один способ сделать то же самое:

UPDATE tab SET h = h || hstore('c', '3');

Если необходимо добавить или изменить несколько ключей одновременно, подход с конкатенацией более эффективен, чем использование индексации:

UPDATE tab SET h = h || hstore(array['q', 'w'], array['11', '12']);

Удаление ключа:

UPDATE tab SET h = delete(h, 'k1');

Преобразование записи в hstore:

CREATE TABLE test (col1 integer, col2 text, col3 text);
INSERT INTO test VALUES (123, 'foo', 'bar');

SELECT hstore(t) FROM test AS t;
                   hstore
---------------------------------------------
 "col1"=>"123", "col2"=>"foo", "col3"=>"bar"
(1 row)

Преобразование типа hstore в предопределенный тип record:

CREATE TABLE test (col1 integer, col2 text, col3 text);

SELECT * FROM populate_record(null::test,
                              '"col1"=>"456", "col2"=>"zzz"');
 col1 | col2 | col3
------+------+------
  456 | zzz  |
(1 row)

Изменить существующую запись, используя значения из hstore:

CREATE TABLE test (col1 integer, col2 text, col3 text);
INSERT INTO test VALUES (123, 'foo', 'bar');

SELECT (r).* FROM (SELECT t #= '"col3"=>"baz"' AS r FROM test t) s;
 col1 | col2 | col3
------+------+------
  123 | foo  | baz
(1 row)

F.19.5. Статистика #

Тип hstore, благодаря своей внутренней свободе, может содержать множество различных ключей. Проверка наличия допустимых ключей - это задача приложения. В следующих примерах показаны несколько техник проверки ключей и получения статистики.

Простой пример:

SELECT * FROM each('aaa=>bq, b=>NULL, ""=>1');

Использование таблицы:

CREATE TABLE stat AS SELECT (each(h)).key, (each(h)).value FROM testhstore;

Онлайн статистика:

SELECT key, count(*) FROM
  (SELECT (each(h)).key FROM testhstore) AS stat
  GROUP BY key
  ORDER BY count DESC, key;
    key    | count
-----------+-------
 line      |   883
 query     |   207
 pos       |   203
 node      |   202
 space     |   197
 status    |   195
 public    |   194
 title     |   190
 org       |   189
...................

F.19.6. Совместимость #

Согласно PostgreSQL 9.0, hstore использует другое внутреннее представление, чем предыдущие версии. Это не создает препятствий для обновления через dump/restore, так как текстовое представление (используемое в дампе) остается неизменным.

В случае двоичного обновления обеспечивается обратная совместимость путем распознавания новым кодом данных в старом формате. Это приведет к небольшому снижению производительности при обработке данных, которые еще не были изменены новым кодом. Возможно принудительное обновление всех значений в столбце таблицы с помощью оператора UPDATE следующим образом:

UPDATE tablename SET hstorecol = hstorecol || '';

Еще один способ сделать это:

ALTER TABLE tablename ALTER hstorecol TYPE hstore USING hstorecol || '';

Метод ALTER TABLE требует ACCESS EXCLUSIVE блокировку на таблице, но не приводит к раздутию таблицы старыми версиями строк.

F.19.7. Преобразования #

Дополнительные расширения доступны, которые реализуют преобразования для типа hstore для языков PL/Perl и PL/Python. Расширения для PL/Perl называются hstore_plperl и hstore_plperlu для доверенного и недоверенного PL/Perl соответственно. Если вы установите эти преобразования и укажете их при создании функции, значения hstore будут отображаться на хеши Perl. Расширение для PL/Python называется hstore_plpython3u. Если вы его используете, значения hstore будут отображаться на словари Python.

Предостережение

Сильно рекомендуется установить расширения преобразования в ту же схему, что и hstore. В противном случае, при установке могут возникнуть проблемы с безопасностью, если схема расширения преобразования содержит объекты, определенные враждебным пользователем.

F.19.8. Авторы #

Олег Бартунов , Москва, Московский университет, Россия

Teodor Sigaev , Moscow, Delta-Soft Ltd.,Russia

Дополнительные улучшения от Andrew Gierth , Великобритания