Slide 1

Slide 1 text

Графови бази от данни Георги Ангелов

Slide 2

Slide 2 text

Какво е граф?

Slide 3

Slide 3 text

Висша благородническа титла на поземлен феодал през Средновековието

Slide 4

Slide 4 text

Graph Dracula

Slide 5

Slide 5 text

Обхождане • Заявките представляват обхождане на графа • Много по-голяма производителност от RDBMS или NoSQL

Slide 6

Slide 6 text

Подходящи за • Социални мрежи • Препоръчващи системи • Анализиране на данни • Търсене на пътища • Други видове данни с много връзки

Slide 7

Slide 7 text

Например • Социална мрежа • Сайт за запознанства • Онлайн магазин • Сайт и мобилно приложение, агрегиращо онлайн концерти • Анализ на поведението на потребители в сайт

Slide 8

Slide 8 text

Графови модели

Slide 9

Slide 9 text

Неориентиран граф

Slide 10

Slide 10 text

Ориентиран граф

Slide 11

Slide 11 text

Ориентиран мултиграф

Slide 12

Slide 12 text

Ориентиран мултиграф с тегла 1 2 1 0.4 0.4 42 42

Slide 13

Slide 13 text

Ориентиран мултиграф с етикети познава познава е брат или сестра на Георги Десислава Веселка Димитър е брат или сестра на е брат или сестра на познава

Slide 14

Slide 14 text

Ориентиран мултиграф със свойства (property graph) Връзка: познава От: 2013-12-31 Име: Георги Професия: програмист Име: Десислава Име: Веселка Име: Димитър Връзка: брат или сестра Общи родители: баща Връзка: брат или сестра Общи родители: майка Връзка: брат или сестра Общи родители: майка и баща Близнаци Връзка: познава От: 2015-10-10 Връзка: познава От: 2016-01-11

Slide 15

Slide 15 text

Ориентиран мултиграф с етикети и свойства (labeled property graph) Познава От: 2013-12-31 Човек Мъж Име: Георги Професия: програмист Човек Жена Име: Десислава Човек Жена Име: Веселка Човек Мъж Име: Димитър Брат или сестра Общи родители: баща Брат или сестра Общи родители: майка Брат или сестра Общи родители: майка и баща Близнаци Познава От: 2015-10-10 Познава От: 2016-01-11

Slide 16

Slide 16 text

(Labeled) property graph • Модел за представяне на данни • Използва се от графовите бази от данни • Ребрата са ориентирани, но могат да се обхождат и в двете посоки • Всеки връх и ребро може да има нула или повече етикети и нула или повече свойства • Schema-free

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Neo4j • Най-популярната графова база от данни • Отворен код (GPL) • Платена за комерсиално използване • Консистентност • Транзакции • Репликация

Slide 19

Slide 19 text

Cypher • Език за заявки към графови данни • Създаден специално за Neo4j • OpenCypher – млад проект за разпространение на Cypher и към други СУБД • Декларативен език

Slide 20

Slide 20 text

Инсталация

Slide 21

Slide 21 text

Примери с Neo4j

Slide 22

Slide 22 text

Име: Ферхунде Жена Човек Име: Фикрет Жена Човек Име: Неджля Жена Човек Име: Хайрие Жена Човек Съпрузи родител на родител на родител на познава познава Име: Али Ръза Мъж Човек

Slide 23

Slide 23 text

Име: Ферхунде Жена Човек Име: Фикрет Жена Човек Име: Неджля Жена Човек Име: Бурак Мъж Човек Име: Хайрие Жена Човек Съпрузи родител на родител на родител на родител на познава познава Име: Али Ръза Мъж Човек

Slide 24

Slide 24 text

Име: Ферхунде Жена Човек Име: Фикрет Жена Човек Име: Неджля Жена Човек Име: Бурак Мъж Човек Име: Хайрие Жена Човек Съпрузи родител на родител на родител на родител на познава познава Име: Али Ръза Лошо му е: да Мъж Човек

Slide 25

Slide 25 text

create (ali:Person:Man {name: 'Али Ръза', lo6o: true}), (hayrie:Person:Woman {name: 'Хайрие'}), (burak:Person:Man {name: 'Бурак'}), (fikret:Person:Woman {name: 'Фикрет'}), (nedjlya:Person:Woman {name: 'Неджля'}), (ferhunde:Person:Woman {name: 'Ферхунде'}) Добавяне на върхове

Slide 26

Slide 26 text

create (ali)-[:married_to]->(hayrie), (hayrie)-[:married_to]->(ali), (ali)-[:parent_of]->(fikret), (ali)-[:parent_of]->(burak), (ali)-[:parent_of]->(nedjlya), (hayrie)-[:parent_of]->(nedjlya), (hayrie)-[:parent_of]->(fikret), (nedjlya)-[:knows]->(fikret), (fikret)-[:knows]->(nedjlya), (fikret)-[:knows]->(ferhunde), (ferhunde)-[:knows]->(burak) Добавяне на ребра * Разчита се, че ще се изпълни едновременно с предната заявка, иначе ще създаде празни върхове.

Slide 27

Slide 27 text

match (vertex) return vertex match ()-[edge]-() return edge Показване на всички върхове и ребра

Slide 28

Slide 28 text

match (p:Person) return p Търсене на върхове по етикети

Slide 29

Slide 29 text

match (p:Person {name: 'Али Ръза'}) return p Търсене на върхове със свойство

Slide 30

Slide 30 text

match (ali:Person {name: 'Али Ръза'})), (hayrie:Person {name: 'Хайрие'}) create (ali)-[:married_to]->(hayrie) Добавяне на ребра без "променливите"

Slide 31

Slide 31 text

match (ali:Person {name: 'Али Ръза'})), (hayrie:Person {name: 'Хайрие'}) create (ali)-[:married_to {on: '1980'}]->(hayrie) Добавяне на ребра със свойства

Slide 32

Slide 32 text

match (p:Person {name: 'Али Ръза'}) return p.name Проекция

Slide 33

Slide 33 text

match (p:Person {name: 'Али Ръза'}) -[:parent_of]->(child:Person) return child.name Прости обхождания match (child:Person) <-[:parent_of]- (p:Person {name: 'Али Ръза'}) return child.name

Slide 34

Slide 34 text

match (p:Person {name: 'Бурак'}) delete p Изтриване на върхове match (child:Person) <-[:parent_of]- (p:Person {name: 'Али Ръза'}) delete child match (v) delete v

Slide 35

Slide 35 text

Изтриване на ребра match (:Person {name: 'Неджля'}) <-[relationship:parent_of]- (:Person {name: 'Али Ръза'}) delete relationship "Неджля, ти вече не си моя дъщеря! Не стъпвай повече в тази къща!" - Али Ръза, 2010 match ()-[r]-() delete r

Slide 36

Slide 36 text

Промяна match (ali:Person {name: 'Али Ръза'}) set ali.lo6o = false return ali

Slide 37

Slide 37 text

match (p:Person)<-[:parent_of]-(child:Person) return p.name, count(child) as child_count Прости агрегации

Slide 38

Slide 38 text

match (p:Person)<-[:parent_of]-(child:Person) return p.name, count(child) as child_count order by child_count desc Сортиране

Slide 39

Slide 39 text

match (p:Person)-[:parent_of]->(child:Person) where p.name = 'Али Ръза' return p.name, count(child) as child_count order by child_count desc Филтриране с where

Slide 40

Slide 40 text

match (p:Person)-[:parent_of]->(child:Person) with p.name as name, count(child) as child_count return name, child_count Междинни стъпки с with match (p:Person)-[:parent_of]->(child:Person) with p.name as name, count(child) as child_count where child_count > 2 return name, child_count order by child_count desc

Slide 41

Slide 41 text

match (:Person {name: 'Али Ръза'})- [:parent_of*2]->(grandchild:Person) return grandchild.name Обхождания с променлива дължина Всички внуци на Али Ръза match (:Person {name: 'Али Ръза'})- [path:parent_of*1..10]-(relative:Person) return relative.name, length(path)

Slide 42

Slide 42 text

Обхождания с променлива дължина Последното ще върне и него самия – ще го филтрираме с where match (ali:Person {name: 'Али Ръза'})- [:parent_of*]-(relative:Person) where relative <> ali return relative.name

Slide 43

Slide 43 text

Обхождания с променлива дължина Всъщност ще върне и жена му и нейните роднини. Ако не ги искаме: match (ali:Person {name: 'Али Ръза'})<- [:parent_of*0..]-(:Person)- [:parent_of*0..]->(relative:Person) where relative <> ali return relative.name

Slide 44

Slide 44 text

match с няколко шаблона Предната заявка може да се напише и така match (common_parent:Person)-[:parent_of*0..]-> (ali:Person {name: 'Али Ръза'}), (common_parent)-[:parent_of*0..]-> (relative:Person) where relative <> ali return relative.name Всички хора, с които има общ родител. В двата match-а `common_parent` ще е един и същ, защото използваме едно и също име.

Slide 45

Slide 45 text

Колекции и имена Фикрет иска някой да я запознае с Бурак: match path=(:Person {name: 'Фикрет'})-[:knows*] ->(:Person {name: 'Бурак'}) return extract(person in nodes(path) | person.name)

Slide 46

Slide 46 text

Най-къс път match (fikret:Person {name: 'Фикрет'}), (burak:Person {name: 'Бурак'}), path=shortestPath((fikret)-[:knows*]->(burak)) return extract(person in nodes(path) | person.name)

Slide 47

Slide 47 text

Въпроси за Neo4j/Cypher?

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

OrientDB • Отворен код (Apache2 license) • Безплатна дори за комерсиално използване • Има и enterprise версия • Консистентност • Транзакции • Репликация • Език за заявки – SQL с разширения или Gremlin

Slide 50

Slide 50 text

OrientDB SQL • Прилича на SQL • Не поддържа част от по-сложните конструкции в SQL • Има допълнителни функции за работа с графи • Простите заявки стават лесно • Сложните заявки са ад и хакерии

Slide 51

Slide 51 text

• Отворен език за заявки към графови данни • Поддържа се от много графови БД, вкл. Neo4j, OrientDB, Titan и т.н. • Императивен, за разлика от Cypher и OrientDB SQL • Доста по-сложен от тях • Но е по-мощен • И имате повече контрол върху обработката

Slide 52

Slide 52 text

Инсталация

Slide 53

Slide 53 text

Инсталация След като го свалите… • Разархивирате някъде • Пускате bin/server.sh • Използвате bin/gremlin.sh за Gremlin конзола (http://orientdb.com/docs/2.0/orientdb.wiki/Gremlin.html) • Или http://localhost:2480 за OrientDB SQL конзола

Slide 54

Slide 54 text

Примери с Gremlin

Slide 55

Slide 55 text

Име: Ферхунде Жена Човек Име: Фикрет Жена Човек Име: Неджля Жена Човек Име: Бурак Мъж Човек Име: Хайрие Жена Човек Съпрузи родител на родител на родител на родител на познава познава Име: Али Ръза Лошо му е: да Мъж Човек

Slide 56

Slide 56 text

ali = g.addVertex('person', 'name', 'Али Ръза', 'lo6o', true) hayrie = g.addVertex('person', 'name', 'Хайрие') burak = g.addVertex('person', 'name', 'Бурак') fikret = g.addVertex('person', 'name', 'Фикрет') nedjlya = g.addVertex('person', 'name', 'Неджля') ferhunde = g.addVertex('person', 'name', 'Ферхунде') Добавяне на върхове

Slide 57

Slide 57 text

Добавяне на ребра * Разчита се, че ще се изпълни заедно с предната заявка. ali .addEdge('married_to', hayrie) hayrie.addEdge('married_to', ali) ali .addEdge('parent_of', fikret) ali .addEdge('parent_of', burak) ali .addEdge('parent_of', nedjlya) hayrie.addEdge('parent_of', nedjlya) hayrie.addEdge('parent_of', fikret) nedjlya.addEdge('knows', fikret) fikret .addEdge('knows', nedjlya) fikret .addEdge('knows', ferhunde) fikret .addEdge('knows', burak)

Slide 58

Slide 58 text

gremlin> g.V() ==>v[#9:0] ==>v[#9:1] ==>v[#9:2] ==>v[#9:3] ==>v[#9:4] ==>v[#9:5] Показване на всички върхове

Slide 59

Slide 59 text

gremlin> g.V().map ==>{name=Али Ръза, lo6o=true} ==>{name=Хайрие} ==>{name=Бурак} ==>{name=Фикрет} ==>{name=Неджля} ==>{name=Ферхунде} Показване на всички върхове

Slide 60

Slide 60 text

gremlin> g.E() ==>e[#11:0][#9:0-married_to->#9:1] ==>e[#11:1][#9:1-married_to->#9:0] ==>e[#12:0][#9:0-parent_of->#9:3] ==>e[#12:1][#9:0-parent_of->#9:2] ==>e[#12:2][#9:0-parent_of->#9:4] ==>e[#12:3][#9:1-parent_of->#9:4] ==>e[#12:4][#9:1-parent_of->#9:3] ==>e[#13:-2][#9:4-knows->#9:3] ==>e[#13:-3][#9:3-knows->#9:4] ==>e[#13:-4][#9:3-knows->#9:5] ==>e[#13:-5][#9:3-knows->#9:2] Показване на всички ребра

Slide 61

Slide 61 text

gremlin> ali = g.V().has('name', 'Али Ръза') ==>v[#9:0] Търсене на върхове gremlin> ali.name ==>Али Ръза gremlin> ali.lo6o ==>true gremlin> ali.map ==>{name=Али Ръза, lo6o=true}

Slide 62

Slide 62 text

Изтриване vertex = g.V().has(...) g.removeVertex(vertex) edge = g.E().has(...) g.removeEdge(edge)

Slide 63

Slide 63 text

Промяна vertex = g.V().has(...) vertex.lo6o = false

Slide 64

Slide 64 text

gremlin> ali.out('parent_of').map ==>{name=Фикрет} ==>{name=Бурак} ==>{name=Неджля} Прости обхождания gremlin> g.V().as('child') .in('parent_of').has('name', 'Али Ръза') .back('child').map ==>{name=Бурак} ==>{name=Фикрет} ==>{name=Неджля}

Slide 65

Slide 65 text

gremlin> ali.outE('parent_of') ==>e[#12:0][#9:0-parent_of->#9:3] ==>e[#12:1][#9:0-parent_of->#9:2] ==>e[#12:2][#9:0-parent_of->#9:4] Прости обхождания gremlin> ali.outE('parent_of').inV.map ==>{name=Фикрет} ==>{name=Бурак} ==>{name=Неджля}

Slide 66

Slide 66 text

• Една gremlin заявка представлява поток (pipe) • Като при функционалното програмиране • С повече възможности – видяхте "връщане назад" и именувани стъпки • Поддържа се и разклонение/сливане на потоци • Поддържат се странични ефекти Обхождане с Gremlin

Slide 67

Slide 67 text

• outE – ребра "излизащи" от текущите върхове • inE – "влизащи" ребра • outV – върхове, от които текущото ребро "излиза" • inV – върхове, в които "влиза" • out = outE.inV • in = inE.outV • Какво прави outE.outV ? • Всички приемат опционален аргумент – тип на реброто/върха Обхождане с Gremlin

Slide 68

Slide 68 text

Прости обхождания ali

Slide 69

Slide 69 text

Прости обхождания ali.outE

Slide 70

Slide 70 text

Прости обхождания ali.outE.inV

Slide 71

Slide 71 text

Прости обхождания ali.outE.inV.inE

Slide 72

Slide 72 text

Прости обхождания ali.outE.inV.inE.outV

Slide 73

Slide 73 text

Прости обхождания ali.outE.inV.inE.outV.out

Slide 74

Slide 74 text

gremlin> ali.out('parent_of').map ==>{name=Фикрет} ==>{name=Бурак} ==>{name=Неджля} Прости обхождания (отново) gremlin> g.V().as('child') .in('parent_of').has('name', 'Али Ръза') .back('child').map ==>{name=Бурак} ==>{name=Фикрет} ==>{name=Неджля}

Slide 75

Slide 75 text

gremlin> ali.outE('parent_of') ==>e[#12:0][#9:0-parent_of->#9:3] ==>e[#12:1][#9:0-parent_of->#9:2] ==>e[#12:2][#9:0-parent_of->#9:4] Прости обхождания (отново) gremlin> ali.outE('parent_of').inV.map ==>{name=Фикрет} ==>{name=Бурак} ==>{name=Неджля}

Slide 76

Slide 76 text

gremlin> g.V().transform { [it.name, it.out('parent_of').count()] } ==>[Али Ръза, 3] ==>[Хайрие, 2] ==>[Бурак, 0] ==>[Фикрет, 0] ==>[Неджля, 0] ==>[Ферхунде, 0] Прости агрегации

Slide 77

Slide 77 text

gremlin> g.V().transform { [it.name, it.out('parent_of').count()] }.filter { it[1] > 0 }.sort { -it[1] } ==>[Али Ръза, 3] ==>[Хайрие, 2] Прости агрегации

Slide 78

Slide 78 text

Обхождания с променлива дължина parents = ali.as('parents') .in('parent_of') .loop('parents') { it.loops < 100 } { true } parents.as('children') .out('parent_of') .loop('children') { it.loops < 100 } { true } Вървим произволен брой стъпки нагоре и събираме върховете в parents, после произволен брой стъпки надолу, събирайки децата.

Slide 79

Slide 79 text

Въпроси за OrientDB/Gremlin?

Slide 80

Slide 80 text

LiveList • OrientDB • Използва се по-скоро като индекс • Данните от PostgreSQL се репликират в OrientDB асинхронно

Slide 81

Slide 81 text

Предимства • Почти имунизирани към OrientDB крашове • PostgreSQL е стабилна и добре поддържана • Драйвърите за OrientDB не струват • Използваме hook-овете на ORM за генерична логика за репликацията

Slide 82

Slide 82 text

Написахме си ActiveRecord DSL class Listing < ActiveRecord::Base include RecommenderVertex recommender_vertex attributes: [ :approval_status, :featured, :start_time, :end_time ] recommender_edge name: 'HasArtist', to: :artist recommender_edge name: 'HasSource', to: :source ... end

Slide 83

Slide 83 text

Написахме си ActiveRecord DSL class ListingGenre < ActiveRecord::Base include RecommenderEdge belongs_to :listing belongs_to :genre recommender_edge name: 'HasGenre', from: :listing, to: :genre end

Slide 84

Slide 84 text

Съвети • Не се лъжете по обещания за скорост • OrientDB ви обещават скорост, но са ужасно зле по другите показатели • Крашове, ужасна документация, чести чупещи промени • NullPointerException при грешна заявка...

Slide 85

Slide 85 text

Въпроси? И извинявайте, че ви задържах толкова