SlideShare a Scribd company logo
Эффективный поиск ближайших 
соседей в PostgreSQL 
Александр Коротков, Олег Бартунов, Федор Сигаев 
PostgreSQL Development Team 
Avito, 2014
Олег Бартунов::Teodor Sigaev 
• Locale support 
• Extendability (indexing) 
• GiST, GIN, SP-GiST 
• Extensions: 
• intarray 
• pg_trgm 
• ltree 
• hstore, hstore v2.0 → jsonb 
• plantuner 
• jsquery 
• Full Text Search (FTS) 
https://www.facebook.com/oleg.bartunov 
obartunov@gmail.com
Alexander Korotkov 
• Indexed regexp search 
• GIN compression & fast scan 
• Fast GiST build 
• Range types indexing 
• Split for GiST 
• Indexing for jsonb 
• jsquery 
• Generic WAL + create am (WIP) aekorotkov@gmail.com
KNN-GiST 
• KNN — найти K ближайших соседей (K- nearest neighbourhood) 
• Очень трудная для традиционных алгоритмов поиска 
• Индекс не помогает, так как нет предиката 
• Требуется full table scan, сортировка 
• Используются разные «костыли» - range search, как задать нужный радиус ? 
• Идея KNN-GiST 
• Использовать новую стратегию обхода поискового дерева (GiST) - 
Priority Queue вместо DFS (BFS) 
• Сразу получаем необходимые K-записей в нужном порядке 
• Чем больше таблица, тем больше выигрыш KNN-GiST
Knn: History of development 
• Начало проекта - Sep 8, 2007 at 7:54 PM 
date Sat, Sep 8, 2007 at 7:54 PM 
subject Chat with Sergey V. Karpov 
7:36 PM me: я тут knn-search занимаюсь, масса интересного. Все думаю, 
как в постгресе это поиметь 
Sergey: а что это такое? 
7:37 PM me: k-nearest соседей - супер важная задача 
найти 5 ближайших точек 
7:38 PM Sergey: ближайших к чему? 
me: к заданной точке 
7:39 PM Sergey: в какой системе координат? 
me: в любой, в n-мерном пространстве. В простом варианте - хотя бы 
на земле/небе 
7:40 PM это нужно для поиска похожих картинок, например. 
навиный вариант повторять запросы - не катит
Knn: History of development 
• TODO (http://www.sai.msu.su/~megera/wiki/TODO) 
начало 2008 года, уже есть понимание что делать 
• 25 июля 2009 года – письмо Paul Ramsey (POSTGIS) 
• 10 июля 2009 года – контракт Open Planning Project Inc. 
• 20 ноября 2009 года – патч KNNGiST v.0.1 (модуль расш) 
• Commitfest nightmare 
• 22 июля 2010 – KNNGiST (v.0.8), commitfest 
• 13 сентября 2010 – KNNGiST (v.0.9) 
• 03 декабря 2010 – Tom Lane committed for 9.1 ! 
• 21 января 2011 – contrib/btree_gist committed !
KNN-GiST: Как найти нужный радиус ? 
Рестораны
KNN-search: Examples 
• Synthetic data – 1,000,000 randomly distributed points 
create table qq ( id serial, p point, s int4); 
insert into qq (p,s) select point( p.lat, p.long), (random()*1000)::int 
from ( select (0.5-random())*180 as lat, random()*360 as long 
from ( select generate_series(1,1000000) ) as t 
) as p; 
create index qq_p_s_idx on qq using gist(p); 
analyze qq; 
• Query – find k-closest points to (0,0) 
set enable_indexscan=on|off; 
explain (analyze on, buffers on) 
SELECT * FROM qq ORDER BY (p <-> '(0,0)') ASC LIMIT 10; 
• <-> - distance operator, provided by data type
KNN-search: Examples 
• Выигрыш 1700 раз для K=10 ! 
Limit (actual time=327.674..327.675 rows=10 loops=1) 
Buffers: shared hit=7353 
-> Sort (actual time=327.673..327.674 rows=10 loops=1) 
Sort Key: ((p <-> '(0,0)'::point)) 
Sort Method: top-N heapsort Memory: 25kB 
Buffers: shared hit=7353 
-> Seq Scan on qq (actual time=0.009..180.513 rows=1000000 loops=1) 
Buffers: shared hit=7353 
Execution time: 327.698 ms 
-------------------------- 
Limit (actual time=0.116..0.160 rows=10 loops=1) 
Buffers: shared hit=14 
-> Index Scan using qq_p_s_idx on qq (actual time=0.116..0.156 rows=10 loops=1) 
Order By: (p <-> '(0,0)'::point) 
Buffers: shared hit=14 
Execution time: 0.183 ms
KNN-search: Examples 
• Выигрыш 220 раз для K=1000 ! 
Limit (actual time=314.262..314.471 rows=1000 loops=1) 
Buffers: shared hit=7353 
-> Sort (actual time=314.261..314.365 rows=1000 loops=1) 
Sort Key: ((p <-> '(0,0)'::point)) 
Sort Method: top-N heapsort Memory: 127kB 
Buffers: shared hit=7353 
-> Seq Scan on qq (actual time=0.008..172.222 rows=1000000 loops=1) 
Buffers: shared hit=7353 
Execution time: 314.599 ms 
-------------------------- 
Limit (actual time=0.073..1.334 rows=1000 loops=1) 
Buffers: shared hit=1016 
-> Index Scan using qq_p_s_idx on qq (actual time=0.072..1.225 rows=1000 loops=1) 
Order By: (p <-> '(0,0)'::point) 
Buffers: shared hit=1016 
Execution time: 1.429 ms1
KNN-search: Examples 
• Выигрыш 15600 раз для K=10 и N=10,000,000 ! 
Limit (actual time=3212.470..3212.473 rows=10 loops=1) 
Buffers: shared hit=96 read=73434 
-> Sort (actual time=3212.469..3212.470 rows=10 loops=1) 
Sort Key: ((p <-> '(0,0)'::point)) 
Sort Method: top-N heapsort Memory: 25kB 
Buffers: shared hit=96 read=73434 
-> Seq Scan on qq (actual time=0.009..1827.449 rows=10000000 loops=1) 
Buffers: shared hit=96 read=73434 
Execution time: 3212.492 ms 
-------------------------- 
Limit (actual time=0.143..0.184 rows=10 loops=1) 
Buffers: shared read=14 
-> Index Scan using qq_p_s_idx on qq (actual time=0.143..0.182 rows=10 loops=1) 
Order By: (p <-> '(0,0)'::point) 
Buffers: shared read=14 
Execution time: 0.205 ms
KNN-search: Очепятки 
• Триграммы ( лопата: '__л', '_ло', 'лоп', 'опа', 'пат', 'ата') 
• Метрика (похожесть) S (W1, W2) 
• Nunion/max(N1, N2) 
• 2 * Nunion/(N1 + N2) 
• Nunion/(N1 + N2 - Nunion) 
• Расстояние D (W1,W2): 
• 1 – S 
• 1/S 
CREATE EXTENSION pg_trgm; 
=# d words 
Table "public.words" 
Column | Type | Modifiers 
--------+------+----------- 
w | text | 
Indexes: 
"words_w_idx" gist (w gist_trgm_ops)
KNN-search: Очепятки 
select w from words order by w <-> 'risource' limit 5; 
w 
---------- 
resource 
rice 
rivets 
ridden 
rivalled 
(5 rows) 
Limit (actual time=0.333..0.345 rows=5 loops=1) 
-> Index Scan using words_w_idx on words (actual time=0.333..0.344 rows=5 loops=1) 
Order By: (w <-> 'risource'::text) 
Execution time: 0.366 ms
KNN-search: Очепятки (Lateral Query) 
SELECT w.w, s.w as similar FROM words w CROSS JOIN LATERAL (SELECT w FROM words 
ORDER BY w.w <-> w limit 2) s WHERE w.w LIKE 'ar%' AND w.w <> s.w; 
w | similar 
--------------+------------- 
archiver | anniversary 
armadillos | armchairs 
artillery | distillery 
arithmetized | authorized 
armchairs | airspeed 
(5 rows) 
Nested Loop (actual time=0.727..2.592 rows=5 loops=1) 
-> Index Scan using words_w_idx on words w (actual time=0.127..0.165 rows=5 loops=1) 
Index Cond: (w ~~ 'ar%'::text) 
-> Subquery Scan on s (actual time=0.483..0.483 rows=1 loops=5) 
Filter: (w.w <> s.w) 
Rows Removed by Filter: 1 
-> Limit (actual time=0.321..0.481 rows=2 loops=5) 
-> Index Scan using words_w_idx on words (actual time=0.318..0.477 rows=2 loops=5) 
Order By: (w <-> w.w) 
Execution time: 2.633 ms
KNN-search: Очепятки 
=# select w from words order by w <-> '%isourc%' limit 5; 
w 
---------- 
resource 
iron 
into 
idles 
injure 
(5 rows) 
Limit (actual time=0.251..0.261 rows=5 loops=1) 
-> Index Scan using words_w_idx on words (actual time=0.251..0.260 rows=5 loops=1) 
Order By: (w <-> '%isourc%'::text) 
Execution time: 0.282 ms
KNN-Search: Ограничения 
Как найти 
ближайшие 
улицы, зная 
только их MBR? 
Расстояние до 
границы MBR 
или до центра 
MBR даёт лишь 
приближение.
KNN-Search: Ограничения 
User-level hack. 
Откуда 
известно, что 
100 
оптимальное 
значение? 
WITH closest_candidates AS ( 
SELECT streets.gid, streets.name, streets.geom 
FROM nyc_streets streets 
ORDER BY streets.geom <-> 
'SRID=26918;POINT(583571.905921312 4506714.34119218)'::geometry 
LIMIT 100 
) 
SELECT gid, name 
FROM closest_candidates 
ORDER BY ST_Distance(geom, 
'SRID=26918;POINT(583571.905921312 4506714.34119218)'::geometry) 
LIMIT 1;
Решение: Exact KNN 
1) Из R-tree добавляем iptr вместе с оценкой 
расстояния в очередь (как и было раньше) 
2) Взятую из очереди оценку расстояния 
перепроверяем по heap 
3) Точное расстояние возвращаем в heap
Exact KNN: статус 
●Даёт правильный результат за минимально 
возможное время. 
●Выложен патч на commitfest. 
●Есть много архитектурных вопросов (доступ к 
heap из index scan).
20 
KNN-GiST: Похожие картинки 
Работает!
Spaghetti indexing ... 
R-tree fails here — bounding box of each separate spaghetti is the same
22 
KNN-GiST: Похожие картинки 
Работает!
23 
KNN-GiST: Похожие картинки 
Работает!
24 
KNN-GiST: Похожие картинки 
Работает!
25 
KNN-GiST: Похожие картинки 
Работает!
26 
KNN-GiST: Похожие картинки 
Работает!
27 
KNN-GiST: Похожие картинки 
Работает!
28 
KNN-GiST: Похожие картинки 
«Не идеально»
29 
Как это устроено: предобработка 
CREATE TABLE pat AS ( 
SELECT 
id, 
shuffle_pattern(pattern) AS pattern, 
pattern2signature(pattern) AS signature 
FROM ( 
SELECT 
id, 
jpeg2pattern(data) AS pattern 
FROM 
image 
) x 
); 
CREATE INDEX pat_signature_idx ON pat USING gist (signature); 
CREATE INDEX pat_id_idx ON pat(id);
30 
Как это устроено: поисковый запрос 
SELECT 
id, 
smlr 
FROM 
( 
SELECT 
id, 
pattern <-> (SELECT pattern FROM pat WHERE id = :id) AS smlr 
FROM pat 
WHERE id <> :id 
ORDER BY 
signature <-> (SELECT signature FROM pat WHERE id = :id) 
LIMIT 100 
) x 
ORDER BY x.smlr ASC 
LIMIT 10 
Можно будет применить Exact-KNN!
31 
Как это устроено внутри? 
B&W and resize Haar wavelet 
pattern2signature 
shuffle_pattern 
jpeg2pattern 
https://github.com/akorotkov/imgsmlr
Spaghetti indexing ... 
R-tree fails here — bounding box of each separate spaghetti is the same
GIN index structure for jsonb 
{ 
"product_group": "Book", 
"product_sales_rank": 15000 
}, 
{ 
"product_group": "Music", 
"product_sales_rank": 25000 
}
Idea: Use multiple boxes
Vodka index structure for jsonb 
{ 
"product_group": "Book", 
"product_sales_rank": 15000 
}, 
{ 
"product_group": "Music", 
"product_sales_rank": 25000 
}
ССпПаАсСиИбБОо ЗзАа В ВНИнМиАмНаИнЕи !е !

More Related Content

PDF
2014.12.23 Николай Самохвалов, Ещё раз о JSON(b) в PostgreSQL 9.4
PPTX
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
PPTX
MongoDB в продакшен - миф или реальность?
PPTX
MongoDB первые впечатления
PPTX
MongoDB. Области применения, преимущества и узкие места, тонкости использован...
PDF
NoSQL внутри SQL: приземленные вопросы практического применения / Дмитрий До...
ODP
Кратко о MongoDB
PDF
Долгожданный релиз pg_pathman 1.0 / Александр Коротков, Дмитрий Иванов (Post...
2014.12.23 Николай Самохвалов, Ещё раз о JSON(b) в PostgreSQL 9.4
Разработка real-time приложений с RethinkDB / Илья Вербицкий (Независимый кон...
MongoDB в продакшен - миф или реальность?
MongoDB первые впечатления
MongoDB. Области применения, преимущества и узкие места, тонкости использован...
NoSQL внутри SQL: приземленные вопросы практического применения / Дмитрий До...
Кратко о MongoDB
Долгожданный релиз pg_pathman 1.0 / Александр Коротков, Дмитрий Иванов (Post...

What's hot (20)

PDF
CodeFest 2014. Бартунов О. — Hstore — документо-ориентированное хранилище и д...
PPT
MongoDB basics in Russian
PDF
Базы данных. Lucene
PDF
Курсы по мобильной разработке под iOS. 5 лекция. Работа с данными
PPTX
Поиск наизнанку
PDF
Linux API с точки зрения разработчика веб-сервера / Валентин Бартенев (NGINX,...
ODP
Новое в Mongodb 2.4
ODP
ClickHouse
PDF
Базы данных. MongoDB
PDF
Обзор перспективных баз данных для highload / Юрий Насретдинов
PDF
2014.09.24 история небольшого успеха с PostgreSQL (Yandex)
PDF
Доклад Валерия Старынина на DevConf 2014. "StatsCollector, или "Мама! Он и ме...
PDF
Сравнение парсеров Json. Android SDK, Gson, Jackson
PDF
Romanenko
PDF
Выбор NoSQL базы данных для вашего проекта: "Не в свои сани не садись"
PDF
Не SQL'ем единым
PDF
ClickHouse: очень быстро и очень удобно / Виктор Тарнавский, Алексей Миловидо...
PDF
Ещё один поиск Яндекса
PDF
Адаптивная оптимизация запросов в реляционных СУБД / Олег Иванов (Postgres Pr...
PPTX
Анализируем данные с Clickhouse
CodeFest 2014. Бартунов О. — Hstore — документо-ориентированное хранилище и д...
MongoDB basics in Russian
Базы данных. Lucene
Курсы по мобильной разработке под iOS. 5 лекция. Работа с данными
Поиск наизнанку
Linux API с точки зрения разработчика веб-сервера / Валентин Бартенев (NGINX,...
Новое в Mongodb 2.4
ClickHouse
Базы данных. MongoDB
Обзор перспективных баз данных для highload / Юрий Насретдинов
2014.09.24 история небольшого успеха с PostgreSQL (Yandex)
Доклад Валерия Старынина на DevConf 2014. "StatsCollector, или "Мама! Он и ме...
Сравнение парсеров Json. Android SDK, Gson, Jackson
Romanenko
Выбор NoSQL базы данных для вашего проекта: "Не в свои сани не садись"
Не SQL'ем единым
ClickHouse: очень быстро и очень удобно / Виктор Тарнавский, Алексей Миловидо...
Ещё один поиск Яндекса
Адаптивная оптимизация запросов в реляционных СУБД / Олег Иванов (Postgres Pr...
Анализируем данные с Clickhouse
Ad

Similar to 2014.10.15 блиц-доклад PostgreSQL kNN search (9)

PPTX
"Многомерные индексы в РСУБД с открытым кодом" Бородин Андрей , Октоника, УрФУ
PDF
Анализ изображений и видео. Поиск по подобию, поиск нечетких дубликатов.
PDF
CV2011 Lecture 10. Image retrieval
PDF
Multidimensional indexing
PPTX
Мастер класс по алгоритмам. Часть 1
PPTX
Денормализованное хранение данных в PostgreSQL 9.2 (Александр Коротков)
PDF
Олег Бартунов, Федор Сигаев, Александр Коротков (PostgreSQL)
PDF
CV2015. Лекция 7. Поиск изображений по содержанию.
PDF
Работа с геоданными в MongoDb
"Многомерные индексы в РСУБД с открытым кодом" Бородин Андрей , Октоника, УрФУ
Анализ изображений и видео. Поиск по подобию, поиск нечетких дубликатов.
CV2011 Lecture 10. Image retrieval
Multidimensional indexing
Мастер класс по алгоритмам. Часть 1
Денормализованное хранение данных в PostgreSQL 9.2 (Александр Коротков)
Олег Бартунов, Федор Сигаев, Александр Коротков (PostgreSQL)
CV2015. Лекция 7. Поиск изображений по содержанию.
Работа с геоданными в MongoDb
Ad

More from Nikolay Samokhvalov (20)

PDF
Эксперименты с Postgres в Docker и облаках — оптимизация настроек и схемы ва...
PDF
Промышленный подход к тюнингу PostgreSQL: эксперименты над базами данных
PDF
The Art of Database Experiments – PostgresConf Silicon Valley 2018 / San Jose
PDF
Nancy CLI. Automated Database Experiments
PDF
#RuPostgresLive 4: как писать и читать сложные SQL-запросы
PDF
#RuPostgresLive 4: как писать и читать сложные SQL-запросы
PDF
Database First! О распространённых ошибках использования РСУБД
PDF
2016.10.13 PostgreSQL in Russia
PDF
#RuPostges в Yandex, эпизод 3. Что же нового в PostgreSQL 9.6
PDF
#noBackend, или Как выжить в эпоху толстеющих клиентов
PPTX
#PostgreSQLRussia в банке Тинькофф, доклад №1
PDF
SFPUG 2015.11.20 lightning talk "PostgreSQL in Russia"
PDF
Владимир Бородин: Как спать спокойно - 2015.10.14 PostgreSQLRussia.org meetu...
PDF
#PostgreSQLRussia 2015.09.15 - Николай Самохвалов - 5 главных особенностей Po...
PPTX
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
PDF
Три вызова реляционным СУБД и новый PostgreSQL - #PostgreSQLRussia семинар по...
PPTX
2014.12.23 Александр Андреев, Parallels
PDF
2014.10.15 Сергей Бурладян, Avito.ru
PDF
2014.10.15 Мурат Кабилов, Avito.ru #PostgreSQLRussia
PDF
PostgreSQL Moscow Meetup - September 2014 - Ilya Kosmodemyansky
Эксперименты с Postgres в Docker и облаках — оптимизация настроек и схемы ва...
Промышленный подход к тюнингу PostgreSQL: эксперименты над базами данных
The Art of Database Experiments – PostgresConf Silicon Valley 2018 / San Jose
Nancy CLI. Automated Database Experiments
#RuPostgresLive 4: как писать и читать сложные SQL-запросы
#RuPostgresLive 4: как писать и читать сложные SQL-запросы
Database First! О распространённых ошибках использования РСУБД
2016.10.13 PostgreSQL in Russia
#RuPostges в Yandex, эпизод 3. Что же нового в PostgreSQL 9.6
#noBackend, или Как выжить в эпоху толстеющих клиентов
#PostgreSQLRussia в банке Тинькофф, доклад №1
SFPUG 2015.11.20 lightning talk "PostgreSQL in Russia"
Владимир Бородин: Как спать спокойно - 2015.10.14 PostgreSQLRussia.org meetu...
#PostgreSQLRussia 2015.09.15 - Николай Самохвалов - 5 главных особенностей Po...
#PostgreSQLRussia 2015.09.15 - Максим Трегубов, CUSTIS - Миграция из Oracle в...
Три вызова реляционным СУБД и новый PostgreSQL - #PostgreSQLRussia семинар по...
2014.12.23 Александр Андреев, Parallels
2014.10.15 Сергей Бурладян, Avito.ru
2014.10.15 Мурат Кабилов, Avito.ru #PostgreSQLRussia
PostgreSQL Moscow Meetup - September 2014 - Ilya Kosmodemyansky

2014.10.15 блиц-доклад PostgreSQL kNN search

  • 1. Эффективный поиск ближайших соседей в PostgreSQL Александр Коротков, Олег Бартунов, Федор Сигаев PostgreSQL Development Team Avito, 2014
  • 2. Олег Бартунов::Teodor Sigaev • Locale support • Extendability (indexing) • GiST, GIN, SP-GiST • Extensions: • intarray • pg_trgm • ltree • hstore, hstore v2.0 → jsonb • plantuner • jsquery • Full Text Search (FTS) https://www.facebook.com/oleg.bartunov obartunov@gmail.com
  • 3. Alexander Korotkov • Indexed regexp search • GIN compression & fast scan • Fast GiST build • Range types indexing • Split for GiST • Indexing for jsonb • jsquery • Generic WAL + create am (WIP) aekorotkov@gmail.com
  • 4. KNN-GiST • KNN — найти K ближайших соседей (K- nearest neighbourhood) • Очень трудная для традиционных алгоритмов поиска • Индекс не помогает, так как нет предиката • Требуется full table scan, сортировка • Используются разные «костыли» - range search, как задать нужный радиус ? • Идея KNN-GiST • Использовать новую стратегию обхода поискового дерева (GiST) - Priority Queue вместо DFS (BFS) • Сразу получаем необходимые K-записей в нужном порядке • Чем больше таблица, тем больше выигрыш KNN-GiST
  • 5. Knn: History of development • Начало проекта - Sep 8, 2007 at 7:54 PM date Sat, Sep 8, 2007 at 7:54 PM subject Chat with Sergey V. Karpov 7:36 PM me: я тут knn-search занимаюсь, масса интересного. Все думаю, как в постгресе это поиметь Sergey: а что это такое? 7:37 PM me: k-nearest соседей - супер важная задача найти 5 ближайших точек 7:38 PM Sergey: ближайших к чему? me: к заданной точке 7:39 PM Sergey: в какой системе координат? me: в любой, в n-мерном пространстве. В простом варианте - хотя бы на земле/небе 7:40 PM это нужно для поиска похожих картинок, например. навиный вариант повторять запросы - не катит
  • 6. Knn: History of development • TODO (http://www.sai.msu.su/~megera/wiki/TODO) начало 2008 года, уже есть понимание что делать • 25 июля 2009 года – письмо Paul Ramsey (POSTGIS) • 10 июля 2009 года – контракт Open Planning Project Inc. • 20 ноября 2009 года – патч KNNGiST v.0.1 (модуль расш) • Commitfest nightmare • 22 июля 2010 – KNNGiST (v.0.8), commitfest • 13 сентября 2010 – KNNGiST (v.0.9) • 03 декабря 2010 – Tom Lane committed for 9.1 ! • 21 января 2011 – contrib/btree_gist committed !
  • 7. KNN-GiST: Как найти нужный радиус ? Рестораны
  • 8. KNN-search: Examples • Synthetic data – 1,000,000 randomly distributed points create table qq ( id serial, p point, s int4); insert into qq (p,s) select point( p.lat, p.long), (random()*1000)::int from ( select (0.5-random())*180 as lat, random()*360 as long from ( select generate_series(1,1000000) ) as t ) as p; create index qq_p_s_idx on qq using gist(p); analyze qq; • Query – find k-closest points to (0,0) set enable_indexscan=on|off; explain (analyze on, buffers on) SELECT * FROM qq ORDER BY (p <-> '(0,0)') ASC LIMIT 10; • <-> - distance operator, provided by data type
  • 9. KNN-search: Examples • Выигрыш 1700 раз для K=10 ! Limit (actual time=327.674..327.675 rows=10 loops=1) Buffers: shared hit=7353 -> Sort (actual time=327.673..327.674 rows=10 loops=1) Sort Key: ((p <-> '(0,0)'::point)) Sort Method: top-N heapsort Memory: 25kB Buffers: shared hit=7353 -> Seq Scan on qq (actual time=0.009..180.513 rows=1000000 loops=1) Buffers: shared hit=7353 Execution time: 327.698 ms -------------------------- Limit (actual time=0.116..0.160 rows=10 loops=1) Buffers: shared hit=14 -> Index Scan using qq_p_s_idx on qq (actual time=0.116..0.156 rows=10 loops=1) Order By: (p <-> '(0,0)'::point) Buffers: shared hit=14 Execution time: 0.183 ms
  • 10. KNN-search: Examples • Выигрыш 220 раз для K=1000 ! Limit (actual time=314.262..314.471 rows=1000 loops=1) Buffers: shared hit=7353 -> Sort (actual time=314.261..314.365 rows=1000 loops=1) Sort Key: ((p <-> '(0,0)'::point)) Sort Method: top-N heapsort Memory: 127kB Buffers: shared hit=7353 -> Seq Scan on qq (actual time=0.008..172.222 rows=1000000 loops=1) Buffers: shared hit=7353 Execution time: 314.599 ms -------------------------- Limit (actual time=0.073..1.334 rows=1000 loops=1) Buffers: shared hit=1016 -> Index Scan using qq_p_s_idx on qq (actual time=0.072..1.225 rows=1000 loops=1) Order By: (p <-> '(0,0)'::point) Buffers: shared hit=1016 Execution time: 1.429 ms1
  • 11. KNN-search: Examples • Выигрыш 15600 раз для K=10 и N=10,000,000 ! Limit (actual time=3212.470..3212.473 rows=10 loops=1) Buffers: shared hit=96 read=73434 -> Sort (actual time=3212.469..3212.470 rows=10 loops=1) Sort Key: ((p <-> '(0,0)'::point)) Sort Method: top-N heapsort Memory: 25kB Buffers: shared hit=96 read=73434 -> Seq Scan on qq (actual time=0.009..1827.449 rows=10000000 loops=1) Buffers: shared hit=96 read=73434 Execution time: 3212.492 ms -------------------------- Limit (actual time=0.143..0.184 rows=10 loops=1) Buffers: shared read=14 -> Index Scan using qq_p_s_idx on qq (actual time=0.143..0.182 rows=10 loops=1) Order By: (p <-> '(0,0)'::point) Buffers: shared read=14 Execution time: 0.205 ms
  • 12. KNN-search: Очепятки • Триграммы ( лопата: '__л', '_ло', 'лоп', 'опа', 'пат', 'ата') • Метрика (похожесть) S (W1, W2) • Nunion/max(N1, N2) • 2 * Nunion/(N1 + N2) • Nunion/(N1 + N2 - Nunion) • Расстояние D (W1,W2): • 1 – S • 1/S CREATE EXTENSION pg_trgm; =# d words Table "public.words" Column | Type | Modifiers --------+------+----------- w | text | Indexes: "words_w_idx" gist (w gist_trgm_ops)
  • 13. KNN-search: Очепятки select w from words order by w <-> 'risource' limit 5; w ---------- resource rice rivets ridden rivalled (5 rows) Limit (actual time=0.333..0.345 rows=5 loops=1) -> Index Scan using words_w_idx on words (actual time=0.333..0.344 rows=5 loops=1) Order By: (w <-> 'risource'::text) Execution time: 0.366 ms
  • 14. KNN-search: Очепятки (Lateral Query) SELECT w.w, s.w as similar FROM words w CROSS JOIN LATERAL (SELECT w FROM words ORDER BY w.w <-> w limit 2) s WHERE w.w LIKE 'ar%' AND w.w <> s.w; w | similar --------------+------------- archiver | anniversary armadillos | armchairs artillery | distillery arithmetized | authorized armchairs | airspeed (5 rows) Nested Loop (actual time=0.727..2.592 rows=5 loops=1) -> Index Scan using words_w_idx on words w (actual time=0.127..0.165 rows=5 loops=1) Index Cond: (w ~~ 'ar%'::text) -> Subquery Scan on s (actual time=0.483..0.483 rows=1 loops=5) Filter: (w.w <> s.w) Rows Removed by Filter: 1 -> Limit (actual time=0.321..0.481 rows=2 loops=5) -> Index Scan using words_w_idx on words (actual time=0.318..0.477 rows=2 loops=5) Order By: (w <-> w.w) Execution time: 2.633 ms
  • 15. KNN-search: Очепятки =# select w from words order by w <-> '%isourc%' limit 5; w ---------- resource iron into idles injure (5 rows) Limit (actual time=0.251..0.261 rows=5 loops=1) -> Index Scan using words_w_idx on words (actual time=0.251..0.260 rows=5 loops=1) Order By: (w <-> '%isourc%'::text) Execution time: 0.282 ms
  • 16. KNN-Search: Ограничения Как найти ближайшие улицы, зная только их MBR? Расстояние до границы MBR или до центра MBR даёт лишь приближение.
  • 17. KNN-Search: Ограничения User-level hack. Откуда известно, что 100 оптимальное значение? WITH closest_candidates AS ( SELECT streets.gid, streets.name, streets.geom FROM nyc_streets streets ORDER BY streets.geom <-> 'SRID=26918;POINT(583571.905921312 4506714.34119218)'::geometry LIMIT 100 ) SELECT gid, name FROM closest_candidates ORDER BY ST_Distance(geom, 'SRID=26918;POINT(583571.905921312 4506714.34119218)'::geometry) LIMIT 1;
  • 18. Решение: Exact KNN 1) Из R-tree добавляем iptr вместе с оценкой расстояния в очередь (как и было раньше) 2) Взятую из очереди оценку расстояния перепроверяем по heap 3) Точное расстояние возвращаем в heap
  • 19. Exact KNN: статус ●Даёт правильный результат за минимально возможное время. ●Выложен патч на commitfest. ●Есть много архитектурных вопросов (доступ к heap из index scan).
  • 20. 20 KNN-GiST: Похожие картинки Работает!
  • 21. Spaghetti indexing ... R-tree fails here — bounding box of each separate spaghetti is the same
  • 22. 22 KNN-GiST: Похожие картинки Работает!
  • 23. 23 KNN-GiST: Похожие картинки Работает!
  • 24. 24 KNN-GiST: Похожие картинки Работает!
  • 25. 25 KNN-GiST: Похожие картинки Работает!
  • 26. 26 KNN-GiST: Похожие картинки Работает!
  • 27. 27 KNN-GiST: Похожие картинки Работает!
  • 28. 28 KNN-GiST: Похожие картинки «Не идеально»
  • 29. 29 Как это устроено: предобработка CREATE TABLE pat AS ( SELECT id, shuffle_pattern(pattern) AS pattern, pattern2signature(pattern) AS signature FROM ( SELECT id, jpeg2pattern(data) AS pattern FROM image ) x ); CREATE INDEX pat_signature_idx ON pat USING gist (signature); CREATE INDEX pat_id_idx ON pat(id);
  • 30. 30 Как это устроено: поисковый запрос SELECT id, smlr FROM ( SELECT id, pattern <-> (SELECT pattern FROM pat WHERE id = :id) AS smlr FROM pat WHERE id <> :id ORDER BY signature <-> (SELECT signature FROM pat WHERE id = :id) LIMIT 100 ) x ORDER BY x.smlr ASC LIMIT 10 Можно будет применить Exact-KNN!
  • 31. 31 Как это устроено внутри? B&W and resize Haar wavelet pattern2signature shuffle_pattern jpeg2pattern https://github.com/akorotkov/imgsmlr
  • 32. Spaghetti indexing ... R-tree fails here — bounding box of each separate spaghetti is the same
  • 33. GIN index structure for jsonb { "product_group": "Book", "product_sales_rank": 15000 }, { "product_group": "Music", "product_sales_rank": 25000 }
  • 35. Vodka index structure for jsonb { "product_group": "Book", "product_sales_rank": 15000 }, { "product_group": "Music", "product_sales_rank": 25000 }
  • 36. ССпПаАсСиИбБОо ЗзАа В ВНИнМиАмНаИнЕи !е !