В прошлом уроке мы говорили о графах на бытовом уровне: «узлы», «связи», «у связи есть свойство». Пора договориться о точных словах. Neo4j хранит данные в модели, которая называется property graph. В ней всего четыре строительных блока, и все они уже есть в учебном графе песочницы.
Доска с карточками и нитками
Вспомни детективный сериал: на стене висят фотографии подозреваемых, между ними натянуты красные нитки, на каждой нитке бумажка «звонил 12 мая». Это и есть property graph:
- фотография это узел;
- подпись над фотографией «свидетель» или «подозреваемый» это метка;
- нитка это связь, у неё есть тип («звонил») и направление (кто кому);
- записи на обороте фотографии и на бумажке у нитки это свойства.
Теперь то же самое строго.
Узлы и метки
Узел это объект: человек, книга, город. Метка говорит, к какой группе узел относится. В учебном графе три метки: Person, City и Book. Посчитаем узлы по меткам:
MATCH (n)
RETURN labels(n) AS labels, count(*) AS total
ORDER BY total DESC;
+--------------------+
| labels | total |
+--------------------+
| ["Person"] | 10 |
| ["Book"] | 5 |
| ["City"] | 3 |
+--------------------+
3 rows
Функция labels(n) возвращает список меток узла: у одного узла их может быть несколько, например Person и Admin сразу. Метка похожа на имя таблицы, но только похожа: узел не обязан иметь все те же поля, что его соседи по метке.
Связи, тип и направление
Связь соединяет ровно два узла. У неё всегда есть начало и конец, то есть направление, и ровно один тип. В клубе три типа связей:
KNOWS: участник знает другого участника;LIVES_IN: участник живёт в городе;READ: участник прочитал книгу.
MATCH ()-[r]->()
RETURN type(r) AS type, count(r) AS total
ORDER BY type;
+--------------------+
| type | total |
+--------------------+
| "KNOWS" | 10 |
| "LIVES_IN" | 8 |
| "READ" | 15 |
+--------------------+
3 rows
Связь в графе не бывает «висячей»: нельзя создать связь без двух концов. И нельзя удалить узел, пока на нём держатся связи, база не даст. Направление обязательно при записи, но при чтении его можно не учитывать, об этом урок про метки, типы и направление.
Свойства
Свойство это пара «ключ, значение». Свойства бывают и у узлов, и у связей. У Ани есть name и born, у связи KNOWS есть since, год знакомства, у READ есть rating, оценка книги. Значением может быть целое или дробное число, строка, логическое значение, дата или список из значений одного типа. Вложенных объектов в свойствах нет: карта целиком в свойство не положится.
Посмотрим на всё сразу: Аню и всё, на что от неё указывают стрелки.
MATCH (a:Person {name: 'Аня'})-[r]->(x)
RETURN a, r, x;
+---------------------------------------------------------------------------------------------------------------------------------------+
| a | r | x |
+---------------------------------------------------------------------------------------------------------------------------------------+
| (:Person {name: "Аня", born: 1994}) | [:READ {rating: 4}] | (:Book {title: "Пикник на обочине", year: 1972, author: "Стругацкие"}) |
| (:Person {name: "Аня", born: 1994}) | [:READ {rating: 5}] | (:Book {title: "Мастер и Маргарита", year: 1967, author: "Булгаков"}) |
| (:Person {name: "Аня", born: 1994}) | [:LIVES_IN] | (:City {name: "Москва"}) |
| (:Person {name: "Аня", born: 1994}) | [:KNOWS {since: 2020}] | (:Person {name: "Глеб", born: 1987}) |
| (:Person {name: "Аня", born: 1994}) | [:KNOWS {since: 2015}] | (:Person {name: "Борис", born: 1990}) |
+---------------------------------------------------------------------------------------------------------------------------------------+
5 rows
Так cypher-shell печатает графовые значения: узел в круглых скобках с метками через двоеточие и свойствами в фигурных, связь в квадратных скобках с типом. Аня повторяется в каждой строке, потому что каждая строка ответа это одна найденная связь.
Чем это отличается от таблиц
| Реляционная модель | Property graph |
|---|---|
| Строка таблицы | Узел |
| Имя таблицы | Метка |
| Колонка | Свойство |
| Внешний ключ или связующая таблица | Связь |
| Колонка связующей таблицы | Свойство связи |
| Схема обязательна | Схема по желанию |
Главная разница в последних двух строках. Связь в графе это полноправная запись со своими свойствами, а не пара номеров в отдельной таблице. А схема необязательна: у Егора в клубе нет года рождения, и базе это не мешает, она не хранит пустую колонку. Свобода работает в обе стороны: опечатку в имени свойства база тоже не заметит. Как защищаться от этого, расскажем в уроке про индексы и ограничения.
Есть и другая графовая модель, RDF, где всё записывается тройками «субъект, предикат, объект». У связи в RDF нет своих свойств, и год знакомства пришлось бы выражать обходными путями. Neo4j работает с property graph, и дальше мы говорим только о нём.
Попробуй сам
Запрос из урока в песочнице: Аня и всё, на что она указывает. Картинка под ответом покажет книги, город и знакомых вокруг неё.
Поменяй стрелку -> на <- и посмотри, кто указывает на Аню. Потом вместо Ани возьми 'Яна': почему ответ пустой?
Проверь себя
Задание
Дальше
Модель понятна, пора поставить настоящую базу. В следующем уроке разберём, что такое Neo4j, какие у неё редакции и как запустить её в Docker за пару минут.
домашка