Към съдържанието
wannacode

Графови бази

Накратко: Графовата база, като Neo4j, пази възли и връзки вместо таблици, а заявките на Cypher търсят шаблони и пътища през тях.

Проблем

Купилите кафе купиха още

Под всеки продукт магазинът иска ред „Купилите това купиха още“. За кафето на зърна заявката към SQL базата е тази:

SQLбаза: магазин

Тя минава по шест таблици: от продукта до редовете на поръчките, до поръчките, до клиента, до другите му поръчки, до техните редове и до продуктите. orders и order_items участват по два пъти. Следващото желание е още по-тежко: „продуктите на хората, чиито препоръки следваш, и на хората, които те следват“. Всяка стъпка е още съединения, а „до три стъпки“ иска WITH RECURSIVE. Въпросът е за връзките между нещата, а в таблиците връзките са разпилени във външни ключове.

Идеята

Възли и връзки

Графовата база пази данните като граф: възли (нещата, например клиент и продукт) и връзки между тях. Всяка връзка има тип (BOUGHT) и посока (от клиента към продукта). Възлите имат етикети (:Customer), а възлите и връзките имат свойства (name, price, quantity). Връзката е записана в базата, а не се търси с JOIN при всяка заявка: от възела базата стига направо до съседите му.

Най-известната графова база е Neo4j, а езикът ѝ е Cypher. Шаблоните в него са рисунка с букви: (c:Customer) е възел, а -[:BOUGHT]-> е стрелка.

графова (като Neo4j)симулатор

Заявката завършва с ;, затова може да е на няколко реда. CREATE прави възли и връзки. MATCH намира всичко, което пасва на шаблона, а RETURN казва какво да се покаже. Под изхода симулаторът рисува намерените възли и връзки.

По-точно, за любопитните

Симулаторът знае част от Cypher: MATCH, WHERE, CREATE, MERGE, SET, DELETE, DETACH DELETE, RETURN, ORDER BY, SKIP, LIMIT и няколко функции. Няма WITH, OPTIONAL MATCH, UNWIND, индекси и ограничения. Изходът е като в конзолата cypher-shell, но без реда с времето на заявката, а съобщенията за грешки са по-кратки. Симулаторът показва подканата пред всеки ред на заявката. Neo4j Browser не иска ; в края и рисува резултата сам. Без ORDER BY симулаторът връща редовете в реда, в който са направени възлите, а Neo4j не обещава никакъв ред.

Пробвай

Георги и хлябът

Базата е празна. Запиши, че клиентът Георги Петров е купил бял хляб: възел с етикет Customer и свойство name, възел с етикет Product и свойство name и връзка BOUGHT от клиента към продукта.

графова (като Neo4j)симулатор

Идеята

Шаблоните

От тук нататък базата е магазинът: 20 клиенти, 25 продукта в 6 категории и 109 връзки BOUGHT, по една за всеки клиент и продукт от поръчките, които не са отменени. Те са взети от SQL базата на курса. Продуктът е свързан с категорията си с връзка IN.

Шаблонът може да е дълъг колкото трябва: от клиента през продукта до категорията, без нито едно съединение.

графова (като Neo4j)симулатор

Посоката в шаблона трябва да съвпада с посоката на връзката:

графова (като Neo4j)симулатор

От продукта към клиента няма стрелки BOUGHT, затова първата заявка не намира никого. <-[:BOUGHT]- чете същата връзка от другия ѝ край. -[:BOUGHT]- без стрелка намира връзката в която и да е посока.

По-точно, за любопитните

Графът не пази отделните поръчки: връзката BOUGHT казва само, че клиентът е купувал продукта. Ако трябват и поръчките, те стават възли: (:Customer)-[:PLACED]->(:Order)-[:CONTAINS {quantity: 2}]->(:Product). Кое е възел и кое е връзка се решава по въпросите, които ще задаваш, както при схемата на SQL базата.

Виж го

Същият въпрос, един шаблон

Ето „купилите кафе купиха още“ на Cypher:

графова (като Neo4j)симулатор

Отговорът е същият като на SQL заявката от началото, ред по ред. Шаблонът се чете отляво надясно: кафето, купено от клиент, който е купил и друг продукт. Кафето не се брои към себе си: в един MATCH една и съща връзка не участва два пъти, а връзката към кафето вече е заета. В SQL това беше отделно условие (p2.id <> p1.id). Кафе са купили само трима души, затова петте продукта са с по двама купувачи и се подреждат по име.

Разликата не е само в дължината. SQL базата търси всяко съединение в индекс или в цялата таблица. Графовата тръгва от кафето и минава само по неговите връзки: работата зависи от това колко връзки има около кафето, а не колко поръчки има магазинът.

Идеята

Пътища с променлива дължина

Да кажем, че магазинът има профили и всеки клиент може да следва препоръките на други клиенти: (:Customer)-[:FOLLOWS]->(:Customer). Тези връзки са измислени за урока, в SQL базата ги няма.

-[:FOLLOWS*1..2]-> е път от една до две стъпки по FOLLOWS. p = … дава име на целия път, а length(p) е броят на стъпките му:

графова (като Neo4j)симулатор

В първия резултат Виктория е два пъти: Елена следва Мария и Димитър, а двамата следват Виктория. MATCH връща всеки път, не всеки човек. Във втората заявка WHERE f <> me маха самата Елена: по три стъпки пътят се връща при нея (Елена, Мария, Виктория, Елена).

Кои са хората по пътя, се вижда с nodes(p):

графова (като Neo4j)симулатор

В SQL същото е WITH RECURSIVE върху таблица follows: начало, UNION ALL и стъпка, която съединява follows с предните редове, плюс брояч на стъпките. Тук е *1..3.

Виж го

Път без граница

Шаблон без тип и без посока, „всичко, свързано с Елена“, с все по-дълъг път:

графова (като Neo4j)симулатор

98 маршрута, после 688, после 4 370. Всяка стъпка ги умножава между шест и седем пъти, защото продукт като бял хляб е свързан с много клиенти, а всеки от тях с много продукти. * без горна граница пробва всички маршрути. Симулаторът спира след 100 000 стъпки, а Neo4j не спира сама: заявката върви, докато свърши времето или паметта. Затова пиши горна граница винаги, а когато можеш, и типа и посоката на връзката.

Упражнение

Препоръки

1. Под сиренето също трябва ред „Купилите това купиха още“.

Кои три продукта са купували най-много от хората, купили сирене? Покажи името и броя купувачи (buyers), от най-много надолу, а при равен брой по име.

графова (като Neo4j)симулатор

2. Мария Иванова следва няколко души, а те следват други.

Покажи клиентите, до които Мария Иванова стига по FOLLOWS в една или две стъпки, всеки по веднъж, подредени по име.

графова (като Neo4j)симулатор

3. Сега истинската препоръка.

Намери продуктите, които са купили хората, следвани от Елена Димитрова в една или две стъпки, но тя още не ги е купила. Покажи трите, купени от най-много различни хора (people), а при равен брой по име.

графова (като Neo4j)симулатор

Идеята

Кога графова база, кога не

Графовата база е добра, когато въпросът е за връзки, често на няколко стъпки: препоръки („купилите това купиха още“), социални мрежи, откриване на измами (сметки, които делят телефон или адрес), маршрути и зависимости, права за достъп през групи. Тя не е добра за отчети, които събират числа от всички записи, например оборот по месеци: такава заявка не обхожда връзки, а чете всичко подред. Това е работа за SQL с GROUP BY или за база за отчети (OLAP). Затова графът обикновено стои до SQL базата: поръчките и парите са в SQL, а копие на връзките отива в графа за препоръките.

По-точно, за любопитните

Освен Neo4j, Cypher разбират Memgraph и Amazon Neptune (там езикът се казва openCypher; Neptune разбира и Gremlin и SPARQL), а разширението Apache AGE добавя Cypher в PostgreSQL. През 2024 г. излезе международният стандарт GQL (ISO/IEC 39075), до голяма степен по идеите на Cypher. Друг вид графова база са RDF хранилищата с езика SPARQL, в които всичко е тройка „субект, предикат, обект“.

Тест

Провери се

1. Какво казва шаблонът (c:Customer)-[:BOUGHT]->(p:Product)?
2. MATCH (me)-[:FOLLOWS*1..2]->(f) RETURN f.name връща Виктория два пъти. Защо?
3. Какво става с шаблон -[*]- без горна граница в голям граф?
4. Трябва ти оборотът по месеци за последните две години. Къде е мястото на тази заявка?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·