$30 off During Our Annual Pro Sale. View Details »

Graph Databases

Graph Databases

Georgy Angelov

June 24, 2016
Tweet

More Decks by Georgy Angelov

Other Decks in Programming

Transcript

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

    View Slide

  2. Какво е граф?

    View Slide

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

    View Slide

  4. Graph Dracula

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  17. View Slide

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

    View Slide

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

    View Slide

  20. Инсталация

    View Slide

  21. Примери с Neo4j

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  25. 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: 'Ферхунде'})
    Добавяне на върхове

    View Slide

  26. 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)
    Добавяне на ребра
    * Разчита се, че ще се изпълни едновременно с предната заявка,
    иначе ще създаде празни върхове.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  40. 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

    View Slide

  41. 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)

    View Slide

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

    View Slide

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

    View Slide

  44. 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` ще е един и същ, защото използваме едно и също
    име.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  48. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  52. Инсталация

    View Slide

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

    View Slide

  54. Примери с Gremlin

    View Slide

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

    View Slide

  56. 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', 'Ферхунде')
    Добавяне на върхове

    View Slide

  57. Добавяне на ребра
    * Разчита се, че ще се изпълни заедно с предната заявка.
    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)

    View Slide

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

    View Slide

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

    View Slide

  60. 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]
    Показване на всички ребра

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  64. 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=Неджля}

    View Slide

  65. 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=Неджля}

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  74. 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=Неджля}

    View Slide

  75. 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=Неджля}

    View Slide

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

    View Slide

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

    View Slide

  78. Обхождания с променлива дължина
    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, после произволен брой стъпки надолу, събирайки децата.

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  82. Написахме си 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide