2015-12-05 Александр Коротков, Иван Панченко -...

72
Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) Александр Коротков, Иван Панченко Postgres Professional 2015 Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 1 / 72

Upload: happydev

Post on 14-Apr-2017

172 views

Category:

Software


0 download

TRANSCRIPT

Page 1: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Слабо-структурированные данные в СУБДPostgreSQL (мастер-класс)

Александр Коротков, Иван Панченко

Postgres Professional

2015

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 1 / 72

Page 2: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

1. Немного о массивах

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 2 / 72

Page 3: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Исходные данные: products

# \d productTable ”public.product”

Column | Type | Modifiers---------------------+-----------------+-----------product_id | character(10) | not nullproduct_title | text | not nullproduct_sales_rank | bigint | not nullproduct_group | text | not nullproduct_category | text |product_subcategory | text |similar_product_ids | character(10)[] | not null

Indexes:

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 3 / 72

Page 4: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Subscrip on – вытащить элемент позаданному индексу

# SELECT product_id, similar_product_idsFROM product LIMIT 5;product_id | similar_product_ids

------------+----------------------------------------------------------0001047655 | {0061007129,0061007358,0061007137,0061099341,0061007161}0001053736 | {0440905605,0345336062,0140380531,0393320979,0395898714}0001053744 | {}0001054600 | {}0001474103 | {0895403889,0001473123,0766177610,0001472933,0766187403}

(5 rows)

# SELECT product_id, similar_product_ids[2]FROM product LIMIT 5;product_id | similar_product_ids

------------+---------------------0001047655 | 00610073580001053736 | 03453360620001053744 | NULL0001054600 | NULL0001474103 | 0001473123

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 4 / 72

Page 5: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Subscrip on – вытащить slice

# SELECT product_id, similar_product_ids[1:2]FROM product LIMIT 5;

product_id | similar_product_ids------------+-------------------------0001047655 | {0061007129,0061007358}0001053736 | {0440905605,0345336062}0001053744 | {}0001054600 | {}0001474103 | {0895403889,0001473123}

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 5 / 72

Page 6: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Subscrip on – обновление

# UPDATE productSET similar_product_ids[1] = ’0061007129’WHERE product_id = ’0001047655’;

# UPDATE productSET similar_product_ids[1:2] = ’{0440905605,0345336062}’WHERE product_id = ’0001047655’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 6 / 72

Page 7: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Осторожно – произвольные границы!

# SELECT (’[-3:-2]={1,2}’::int[])[1];int4

------NULL

(1 row)

# SELECT (’[-3:-2]={1,2}’::int[])[-2];int4

------2

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 7 / 72

Page 8: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Осторожно – многомерные массивы!

# SELECT (’{{1,2},{3,4}}’::int[])[1];int4

------NULL

(1 row)

# SELECT (’{{1,2},{3,4}}’::int[])[1][2];int4

------2

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 8 / 72

Page 9: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

array_lower и array_upper – верхняя инижняя границы массива

Откусываем у массива первый элемент.# SELECT product_id,

similar_product_ids[array_lower(similar_product_ids,1) + 1 :array_upper(similar_product_ids,1)]

FROM product LIMIT 5;product_id | similar_product_ids

------------+-----------------------------------------------0001047655 | {0061007358,0061007137,0061099341,0061007161}0001053736 | {0345336062,0140380531,0393320979,0395898714}0001053744 | NULL0001054600 | NULL0001474103 | {0001473123,0766177610,0001472933,0766187403}

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 9 / 72

Page 10: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Поиск по массиву: ANY

# SELECT product_id, product_titleFROM product WHERE ’0061007137’ = ANY(similar_product_ids);

product_id | product_title------------+------------------------------------0001047655 | Prodigal Daughter0061007129 | Kane & Abel0061007145 | The Prodigal Daughter0061007161 | First Among Equals0061007358 | Not a Penny More, Not a Penny Less0061013315 | The Eleventh Commandment0061013706 | Shall We Tell the President?0061092045 | Honor Among Thieves0061093653 | Twelve Red Herrings0061099341 | As the Crow Flies

(10 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 10 / 72

Page 11: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Разворачивание массива в rowset: unnest

# SELECT unnest(similar_product_ids)FROM product WHERE product_id = ’0061007137’;unnest

------------00610073580061099341006100714500610071610061007129

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 11 / 72

Page 12: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Сворачивание rowset в массив: array_agg

# SELECT array_agg(product_id)FROM productWHERE ’0061093653’ = ANY(similar_product_ids);

array_agg-----------------------------------------------{006018552X,0060185805,006100717X,0061032077}

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 12 / 72

Page 13: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #1

Для каждого продукта собрать массив тех,которые ссылаются на него черезsimilar_product_ids.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 13 / 72

Page 14: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #1: решение

SELECTsimilar_id,array_agg(product_id)

FROM (SELECT

product_id,unnest(similar_product_ids) AS similar_id

FROMproduct) s

GROUP BYsimilar_id;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 14 / 72

Page 15: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #2

Сделать выборку продуктов, для которыхвсе продукты, указанные в массивеsimilar_product_ids имеют рейтинг неменьше 100000.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 15 / 72

Page 16: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #2: решение

SELECT*

FROMproduct p1

WHERE NOT EXISTS (SELECT

1FROM

unnest(p1.similar_product_ids) sidJOIN

product p2ON

p2.product_id = sidWHERE

NOT (p2.product_sales_rank >= 100000));

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 16 / 72

Page 17: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Операторы &&, @>, <@ (1/2)

▶ a && b – у массивов a и b есть хотя бы одинобщий элемент.

▶ a@> b – в массиве a есть все элементы массива bи, быть может, другие.

▶ a <@ b – то же, что и b@> a.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 17 / 72

Page 18: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Операторы &&, @>, <@ (2/2)

# SELECT count(*) FROM productWHERE similar_product_ids && ’{0061007137,0007149689}’;count

-------11

(1 row)

# SELECT count(*) FROM productWHERE similar_product_ids @> ’{0061007137,0061007161}’;count

-------6

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 18 / 72

Page 19: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы по массивам (1/3)

▶ Встроенный GIN-индекс для массивов всех типов(операторы &&, @>, <@, =).

▶ GiST-индекс для int[] в contrib/intarray.▶ Индексы по конкретным элементам массива(например, a[3]). Не очень интересно.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 19 / 72

Page 20: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы по массивам (2/3)

# EXPLAIN ANALYZE SELECT * FROM productWHERE similar_product_ids @> ’{0061007137,0061007161}’;

QUERY PLAN-------------------------------------------------------------------------------------------------------Seq Scan on product (cost=0.00..9348.25 rows=1 width=161) (actual time=0.009..97.527 rows=6 loops=1)

Filter: (similar_product_ids @> ’{0061007137,0061007161}’::bpchar[])Rows Removed by Filter: 253614

Planning time: 0.120 msExecution time: 97.547 ms

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 20 / 72

Page 21: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы по массивам (3/3)

# CREATE INDEX product_similar_product_ids_idxON product USING gin (similar_product_ids);

CREATE INDEXTime: 18795,075 ms# EXPLAIN ANALYZE SELECT * FROM product

WHERE similar_product_ids @> ’{0061007137,0061007161}’;QUERY PLAN

-----------------------------------------------------------------------------------------------------------------------------------------Bitmap Heap Scan on product (cost=28.00..32.01 rows=1 width=161) (actual time=0.059..0.065 rows=6 loops=1)

Recheck Cond: (similar_product_ids @> ’{0061007137,0061007161}’::bpchar[])Heap Blocks: exact=5-> Bitmap Index Scan on product_similar_product_ids_idx (cost=0.00..28.00 rows=1 width=0) (actual time=0.054..0.054 rows=6 loops=1)

Index Cond: (similar_product_ids @> ’{0061007137,0061007161}’::bpchar[])Planning time: 0.123 msExecution time: 0.089 ms

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 21 / 72

Page 22: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

2. Hstore

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 22 / 72

Page 23: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Исходные данные: stocks (1/2)

Table ”public.stocks”Column | Type | Modifiers

----------+---------+-----------------------------------------------------id | integer | not null default nextval(’stocks_id_seq’::regclass)country | text | not nullindustry | text | not nullsector | text | not nullcompany | text | not nullticker | text | not nullvolume | integer | not nullh | hstore | not null

Indexes:”stocks_pkey” PRIMARY KEY, btree (id)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 23 / 72

Page 24: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Исходные данные: stocks (2/2)

# SELECT * FROM stocks LIMIT 1;-[ RECORD 1 ]-----------------------------------------------------------------------------------------------------------------------------------------id | 1country | USAindustry | Semiconductor Equipment & Materialssector | Technologycompany | Brooks Automation Inc.ticker | BRKSvolume | 516739h | ”Gap”=>”0.0151”, ”P/B”=>”1.05”, ”P/E”=>”6.07”, ”P/S”=>”1.45”, ”PEG”=>”0.34”, ”Beta”=>”1.66”, ”Price”=>”10.24”, ”Change”=>”0.0291”, ”P/Cash”

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 24 / 72

Page 25: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание полей (1/2)

# SELECT id, h -> ’Price’, h -> ’Change’FROM stocks LIMIT 10;id | ?column? | ?column?

----+-------------------+----------1 | 10.24 | 0.02912 | 26.94 | -0.0233 | 92.56999999999999 | 0.00164 | 14.95 | 0.00475 | 26.65 | 0.00136 | 25.33 | -0.02617 | 62.7 | 0.00618 | 11.9 | -0.00179 | 24.44 | 0.018810 | 36.87 | 0.0104

(10 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 25 / 72

Page 26: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание полей (2/2)

# SELECT company FROM stocksWHERE h -> ’Price’ > 1000.0;

ERROR: operator does not exist: text > numeric

# SELECT company FROM stocksWHERE (h -> ’Price’)::numeric > 1000.0;

company----------------------------Seaboard Corp.Berkshire Hathaway Inc.Google Inc.priceline.com Incorporated

(4 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 26 / 72

Page 27: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Превращаем hstore в набор парключ-значение

# SELECT (each(h)).* FROM stocks WHERE id = 4;key | value

-------------------------------+----------------------Gap | 0Price | 14.95Change | 0.004750-Day Low | 0.038150-Day High | -0.017752-Week Low | 0.3304Short Ratio | 0.14

......................................................

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 27 / 72

Page 28: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #3

Собрать статистику по использованиюразличных ключей в поле h таблицы stocks:для каждого встречающегося ключа указатьего частоту.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 28 / 72

Page 29: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #3: решение

# SELECT key,count(*)::float8 /

(SELECT count(*) FROM stocks) freqFROM (SELECT (each(h)).* FROM stocks) kvGROUP BY key;

key | freq-----------------------------------+-------------------Shares Float | 0.725725281231498Analyst Recom | 0.616489046773239Insider Transactions | 0.554026050917703Institutional Transactions | 0.705743043220841P/B | 0.71166370633511

.......................................................

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 29 / 72

Page 30: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Оператор @>

a@> b тогда и только тогда, когда для каждой парыключ => значение из b, такая же пара присутствует и вa.Примеры.

key1 | key2 | result-----------------+--------------+--------a=>x, b=>y, c=>z | a=>x, b=>y | truea=>x, b=>y | a=>x, b=>qqq | falsea=>x, b=>y | t=>x, b=>y | false

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 30 / 72

Page 31: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Операторы ?, ?&, ?|

▶ a ? b – проверяет наличие ключа b в массиве a.▶ a ?& b – проверяет наличие всех ключей измассива b в массиве a.

▶ a ?| b – проверяет наличие хотя бы одного изключей массива b в массиве a.

# SELECT count(*),count(*) FILTER

(WHERE h ? ’Short Ratio’),count(*) FILTER

(WHERE h ?| ’{Short Ratio, Change from Open}’),count(*) FILTER

(WHERE h ?& ’{Short Ratio, Change from Open}’)FROM stocks;

count | count | count | count-------+-------+-------+-------

6756 | 5412 | 6743 | 5412(1 row)Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 31 / 72

Page 32: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #4

Написать аналог оператора @> с помощьюфункций each(hstore) и операторов ->, ?.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 32 / 72

Page 33: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #4: решение

CREATE FUNCTION contains_sql(hstore, hstore) RETURNS boolAS $$

SELECT NOT EXISTS (SELECT 1FROM each($2) kvWHERE NOT (

$1 ? key AND$1 -> key IS NOT DISTINCT FROM value)

)$$ LANGUAGE sql;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 33 / 72

Page 34: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Конструируем hstore

# SELECT hstore(’{key1, key2}’::text[],’{value1, value2}’::text[]);hstore

------------------------------------”key1”=>”value1”, ”key2”=>”value2”

(1 row)

# SELECT hstore(array_agg(id::text),array_agg(company))

FROM stocks WHERE id <= 4;hstore

------------------------------------------------------”1”=>”Brooks Automation Inc.”, ”2”=>”Broadcom Corp.”

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 34 / 72

Page 35: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #5

Посчитать для каждой отрасли (sector) изтаблицы stocks суммарный объём ценныхбумаг (volume), и выдать это в виде hstoreвида: отрасль => суммарный объём ценныйбумаг.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 35 / 72

Page 36: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #5: решение

# SELECT hstore(array_agg(sector),array_agg(volume::text)) h

FROM (SELECT sector,SUM(volume) AS volume

FROM stocksGROUP BY sector) s;

-[ RECORD 1 ]-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------h | ”Services”=>”637878158”, ”Financial”=>”1389743864”,

| ”Utilities”=>”94268768”, ”Healthcare”=>”381247435”,| ”Technology”=>”1225484169”, ”Conglomerates”=>”3547704”,| ”Consumer Goods”=>”276207382”,| ”Basic Materials”=>”625043686”,| ”Industrial Goods”=>”200105263”

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 36 / 72

Page 37: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы для hstore

▶ GIN/GiST индексы: индексируем ключи отдельно,значения отдельно (операторы @>, ?, ?&, ?|).

▶ GIN индекс: индексируем пары hash(key) +hash(value) (операторы @>, ?, ?&, ?|)https://github.com/postgrespro/hstore_ops

▶ Индекс по отдельному ключу (h->’key’).

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 37 / 72

Page 38: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

3. Jsonb

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 38 / 72

Page 39: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Исходные данные: company

# \d companyTable ”public.company”

Column | Type | Modifiers--------+-------+-----------js | jsonb |

# SELECT js FROM company limit 5;

------------------------------------------------------------------{”_id”: {”$oid”: ”52cdef7c4bab8bd675297d8a”}, ”name”: ”Wetpaint”,{”_id”: {”$oid”: ”52cdef7c4bab8bd675297d8b”}, ”name”: ”AdventNet”,{”_id”: {”$oid”: ”52cdef7c4bab8bd675297d8c”}, ”name”: ”Zoho”,{”_id”: {”$oid”: ”52cdef7c4bab8bd675297d8d”}, ”ipo”: null, ”name”: ”Digg”,{”_id”: {”$oid”: ”52cdef7c4bab8bd675297d8e”}, ”ipo”: {”pub_day”: 18, ”pub_year”: 2012,$

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 39 / 72

Page 40: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Jsonb pre y print

# SELECT jsonb_pretty(js) FROM company LIMIT 1;-[ RECORD 1 ]+-------------------------------------------jsonb_pretty | {

| ”_id”: {| ”$oid”: ”52cdef7c4bab8bd675297d8a”| },| ”name”: ”Wetpaint”,| ”image”: {| ”available_sizes”: [| [| [| 150,| 75

.........................................................

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 40 / 72

Page 41: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание полей

# SELECT js -> ’name’,js -> ’acquisition’ -> ’price_amount’,js #> ’{acquisition,price_amount}’

FROM companyLIMIT 5;

?column? | ?column? | ?column?-------------------------+-----------+-----------”Wetpaint” | 30000000 | 30000000”AdventNet” | NULL | NULL”Zoho” | NULL | NULL”Digg” | 500000 | 500000”Facebook” | NULL | NULL

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 41 / 72

Page 42: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание полей и типы (1/2)

-> вытаскивает тип jsonb# SELECT js -> ’name’ FROM company

WHERE js -> ’name’ ILIKE ’%paint%’;ERROR: operator does not exist: jsonb ~~* unknown

Приведение значения поля к строке# SELECT (js -> ’name’)::text, js ->> ’name’

FROM company LIMIT 5;text | ?column?

-------------+-----------”Wetpaint” | Wetpaint”AdventNet” | AdventNet”Zoho” | Zoho”Digg” | Digg”Facebook” | Facebook

(5 rows)Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 42 / 72

Page 43: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание полей и типы (2/2)

# SELECTjs ->> ’name’,js ->> ’number_of_employees’

FROM companyWHERE

js ->> ’name’ ILIKE ’%paint%’ AND(js ->> ’number_of_employees’)::int >= 10;

?column? | ?column?----------+----------Wetpaint | 47

(1 row)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 43 / 72

Page 44: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Вытаскивание элементов массивов

# SELECTjs -> ’offices’ -> 0 ->> ’city’,js #>> ’{offices,0,city}’

FROM company LIMIT 5;?column? | ?column?

---------------+---------------Seattle | SeattlePleasanton | PleasantonPleasanton | PleasantonSan Francisco | San FranciscoMenlo Park | Menlo Park

(5 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 44 / 72

Page 45: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы по выражениям

# CREATE UNIQUE INDEX company_id_idxON company ((js -> ’_id’ ->> ’$oid’));CREATE INDEX

# EXPLAIN ANALYZE SELECT js -> ’name’ FROM companyWHERE js -> ’_id’ ->> ’$oid’ = ’52cdef7c4bab8bd675297d8a’;

QUERY PLAN--------------------------------------------------------------------------------------------------------------------------Index Scan using company_id_idx on company (cost=0.29..8.31 rows=1 width=882) (actual time=0.126..0.129 rows=1 loops=1)

Index Cond: (((js -> ’_id’::text) ->> ’$oid’::text) = ’52cdef7c4bab8bd675297d8a’::text)Planning time: 0.084 msExecution time: 0.156 ms

(4 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 45 / 72

Page 46: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Разворачивание JSON-массивов в rowset

# SELECT jsonb_array_elements(js -> ’competitions’)FROM companyWHERE js -> ’_id’ ->> ’$oid’ = ’52cdef7c4bab8bd675297d8a’;

jsonb_array_elements---------------------------------------------------------------------{”competitor”: {”name”: ”Wikia”, ”permalink”: ”wikia”}}{”competitor”: {”name”: ”JotSpot”, ”permalink”: ”jotspot”}}{”competitor”: {”name”: ”Socialtext”, ”permalink”: ”socialtext”}}{”competitor”: {”name”: ”Ning by Glam Media”, ”permalink”: ”ning”}}{”competitor”: {”name”: ”Soceeo”, ”permalink”: ”soceeo”}}{”competitor”: {”name”: ”Yola”, ”permalink”: ”yola”}}{”competitor”: {”name”: ”SocialGO”, ”permalink”: ”socialgo”}}{”competitor”: {”name”: ”IslamNor”, ”permalink”: ”islamnor”}}

(8 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 46 / 72

Page 47: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Разворачивание JSON-объектав key-value rowset

# SELECT (jsonb_each(js #> ’{offices, 0}’)).*FROM companyWHERE js -> ’_id’ ->> ’$oid’ = ’52cdef7c4bab8bd675297d8a’;

key | value--------------+--------------------city | ”Seattle”address1 | ”710 - 2nd Avenue”address2 | ”Suite 1100”latitude | 47.603122zip_code | ”98104”longitude | -122.333253state_code | ”WA”description | ””country_code | ”USA”

(9 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 47 / 72

Page 48: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Оператор @>

▶ Для скалярных a и b, a@> b тогда и только тогда, когда a = b.▶ Если a и b объекты, то для каждого ключа в b должен

существовать ключ в a, содержащий соответствующее значение.▶ Если a и b массивы, то для каждого элемента в b должен

существовать содержащий его элемент в a.

Примеры.arg1 | arg2 | result

---------------------+----------------------+--------1 | 1 | true1 | ”1” | false{”a”: 1, ”b”: 2} | {”a”: 1} | true{”a”: 1, ”b”: 2} | {”a”: 2} | false[1, 2] | [1] | true[{”a”: 1, ”b”: 2}] | [{”a”: 1}, {”b”: 2}] | true[{”a”: 1}, {”b”: 2}] | [{”a”: 1, ”b”: 2}] | false

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 48 / 72

Page 49: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Установка plv8

$ git clone https://github.com/plv8/plv8.git$ cd plv8$ make USE_PGXS=1$ sudo make USE_PGXS=1 install$ make USE_PGXS=1 installcheck$ psql DB -c ”CREATE EXTENSION plv8;”

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 49 / 72

Page 50: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #6

Написать на plv8 функцию, которая длякомпании выводит список стран, где у неёесть офисы.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 50 / 72

Page 51: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #6: решение

CREATE FUNCTION extract_countries(company jsonb)RETURNS text[]AS $$

var tmp = {}, result = [];for(var i = 0; i < company.offices.length; i++)

tmp[company.offices[i].country_code] = true;for(var i in tmp)result.push(i)return result;

$$ LANGUAGE plv8 IMMUTABLE STRICT;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 51 / 72

Page 52: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индекс по странам

CREATE INDEX company_countries_idx ON companyUSING gin(extract_countries(js));# EXPLAIN ANALYZE SELECT * FROM company

WHERE extract_countries(js) @> ’{RUS}’;QUERY PLAN

--------------------------------------------------------------------------------------------------------------------------------Bitmap Heap Scan on company (cost=8.73..348.48 rows=94 width=882)

(actual time=0.038..0.089 rows=50 loops=1)Recheck Cond: (extract_countries(js) @> ’{RUS}’::text[])Heap Blocks: exact=48-> Bitmap Index Scan on company_countries_idx (cost=0.00..8.71 rows=94 width=0) (actual time=0.027..0.027 rows=50 loops=1)

Index Cond: (extract_countries(js) @> ’{RUS}’::text[])Planning time: 0.057 msExecution time: 0.113 ms

(7 rows)

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 52 / 72

Page 53: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #7

Написать на plv8 агрегат, который которыйпосчитает частоты различных размеровкартинок.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 53 / 72

Page 54: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #7: решение (1/2)

CREATE FUNCTION image_size_agg_sfunc(state jsonb,company jsonb) RETURNS jsonb

AS $$if (!company.image) return state;var sizes = company.image.available_sizesfor (var i = 0; i < sizes.length; i++){

var sizeKey = sizes[i][0][0] + ’x’ +sizes[i][0][1];

if (sizeKey in state) state[sizeKey]++;else state[sizeKey] = 1;

}return state;

$$ LANGUAGE plv8 IMMUTABLE STRICT;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 54 / 72

Page 55: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #7: решение (2/2)

CREATE AGGREGATE image_size_agg (jsonb) (SFUNC = image_size_agg_sfunc,STYPE = jsonb,INITCOND = ’{}’);

# SELECT image_size_agg(js) FROM company;-[ RECORD 1 ]--+--------------------------------------------------------------------------------------------------------------------------------------image_size_agg | {”1x1”: 15, ”32x8”: 3, ”150x7”: 1, ”150x8”: 5, ”150x9”: 3, ”17x17”: 3, ”26x27”: 3, ”30x39”: 3, ”32x31”: 3, ”32x32”: 12, ”35x21”: 3, ”

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 55 / 72

Page 56: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Установка jsquery

$ git clone https://github.com/postgrespro/jsquery.git$ cd jsquery$ make USE_PGXS=1$ sudo make USE_PGXS=1 install$ make USE_PGXS=1 installcheck$ psql DB -c ”CREATE EXTENSION jsquery;”

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 56 / 72

Page 57: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Индексы для jsonb

▶ GIN jsonb_ops: индексируем ключи отдельно,значения отдельно (операторы @>, ?, ?&, ?|).

▶ GIN jsonb_path_ops: индексируем hash(path +value) (операторы @>).

▶ jsonb_path_value_ops: индексируем hash(path) +hash(value) (операторы @>, jsonb @@ jsquery).

▶ jsonb_value_path_ops: индексируем hash(value) +bloom(path) (операторы @>, jsonb @@ jsquery).

▶ Индексы по отдельным ключам (js -> ’key’).

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 57 / 72

Page 58: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Пример: найти комании с офисами вРоссии

-- Оператор @># SELECT js->’name’ FROM company

WHERE js @> ’{”offices”:[{”country_code”: ”RUS”}]}’;

-- Оператор jsquery# SELECT js->’name’ FROM company

WHERE js @@ ’offices.#.country_code = ”RUS”’;

-- Разворачивание jsonb в rowset# SELECT js->’name’ FROM company

WHERE EXISTS (SELECT 1FROM jsonb_array_elements(js->’offices’) elWHERE el ->> ’country_code’ = ’RUS’);

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 58 / 72

Page 59: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #8

Найти компании, конкуренты Wikia, укоторых есть офис в США.Реализовать решение с помощью:

▶ оператора @>,▶ jsquery,▶ разворачивания jsonb в rowset.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 59 / 72

Page 60: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #8: решение (1/3)

-- Оператор @># SELECT js->’name’ FROM company

WHEREjs @>’{”competitions”:[{”competitor”:

{”name”: ”Wikia”}}]}’ AND

js @>’{”offices”:[{”country_code”: ”USA”}]}’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 60 / 72

Page 61: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #8: решение (2/3)

-- jsquery# SELECT js->’name’ FROM company

WHERE js @@’competitions.#.competitor.name = ”Wikia” ANDoffices.#.country_code = ”USA”’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 61 / 72

Page 62: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #8: решение (3/3)

-- Разворачивание jsonb в rowsetSELECT js->’name’ FROM companyWHERE

EXISTS (SELECT 1FROM jsonb_array_elements(js->’competitions’) elWHERE el -> ’competitor’ ->> ’name’ = ’Wikia’

) AND EXISTS (SELECT 1FROM jsonb_array_elements(js->’offices’) elWHERE el ->> ’country_code’ = ’USA’

);

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 62 / 72

Page 63: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #9

Найти компании, в которые финансоваяорганизация Trinity Ventures инвестировалав 2007 или 2008 году.Реализовать решение с помощью:

▶ оператора @>,▶ jsquery,▶ разворачивания jsonb в rowset.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 63 / 72

Page 64: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #9: решение (1/3)

-- Оператор @># SELECT js->’name’ FROM company

WHEREjs @>’{”funding_rounds”:[{”funded_year”: 2007,

”investments”:[{”financial_org”:{”name”:”Trinity Ventures”}}

]}]}’ OR

js @>’{”funding_rounds”:[{”funded_year”: 2008,

”investments”:[{”financial_org”:{”name”:”Trinity Ventures”}}

]}]}’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 64 / 72

Page 65: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #9: решение (2/3)

-- jsquery# SELECT js->’name’ FROM company

WHEREjs @@’funding_rounds.#(

funded_year IN (2007,2008) ANDinvestments.#.financial_org.name = ”Trinity Ventures”)’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 65 / 72

Page 66: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #9: решение (3/3)

-- Разворачивание jsonb в rowset# SELECT js->’name’ FROM company

WHERE EXISTS (SELECT 1FROM jsonb_array_elements(js->’funding_rounds’) elWHERE el -> ’funded_year’ IN (’2007’,’2008’) AND EXISTS(SELECT 1FROM jsonb_array_elements(el -> ’investments’) el2WHERE el2 -> ’financial_org’ ->>

’name’ = ’Trinity Ventures’));

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 66 / 72

Page 67: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #10

Найти компании, которые в 2008 годупривлекли более 100 000 000 USDинвестиций.Реализовать решение с помощью:

▶ jsquery,▶ разворачивания jsonb в rowset.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 67 / 72

Page 68: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #10: решение (1/2)

-- jsquery# SELECT js -> ’name’

FROM companyWHERE js @@’funding_rounds.# (funded_year = 2008 AND

raised_currency_code = ”USD” ANDraised_amount > 100000000)’;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 68 / 72

Page 69: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #10: решение (2/2)

-- Разворачивание jsonb в rowset# SELECT js->’name’ FROM company

WHERE EXISTS (SELECT 1FROM jsonb_array_elements(js->’funding_rounds’) elWHEREel -> ’funded_year’ = ’2008’ ANDel ->> ’raised_currency_code’ = ’USD’ ANDel -> ’raised_amount’ > ’100000000’);

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 69 / 72

Page 70: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #11

Найти компании, у которых суммарныйобъём инвестиций был более 1 000 000 000USD.Реализовать решение с помощьюразворачивания jsonb в rowset.

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 70 / 72

Page 71: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Задача #11: решение

-- Разворачивание jsonb в rowsetSELECT js->’name’ FROM company

WHERE (SELECT SUM((el ->> ’raised_amount’)::numeric)FROM jsonb_array_elements(js->’funding_rounds’) elWHEREel ->> ’raised_currency_code’ = ’USD’) > 1000000000;

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 71 / 72

Page 72: 2015-12-05 Александр Коротков, Иван Панченко - Слабо-структурированные данные в СУБД глазами и руками разработчиков

Спасибо за внимание!

Александр Коротков, Иван Панченко Слабо-структурированные данные в СУБД PostgreSQL (мастер-класс) 72 / 72