Neo4j хранит данные в виде графа: набор объектов и связей между ними. Это не метафора и не способ нарисовать схему — это буквально то, как данные лежат и как по ним ходят запросы. Разберём модель по частям и поймём, почему обход связей здесь стоит дёшево.
Property graph: четыре кирпичика
Модель Neo4j называется property graph («граф со свойствами») и состоит из четырёх элементов:
- Узел (node) — сущность: человек, товар, счёт, документ. Аналог строки таблицы, но без фиксированной схемы.
- Ребро (relationship) — связь между двумя узлами:
ДРУЖИТ,КУПИЛ,ПЕРЕВЁЛ. У ребра всегда есть тип и направление (от одного узла к другому). - Свойства (properties) — пары «ключ-значение» на узлах и на рёбрах: у человека
имяивозраст, у ребра «работает в» —должностьис какого года. То, что связь сама несёт данные, — важная особенность: в реляционной базе для этого пришлось бы заводить отдельную таблицу. - Метки (labels) — теги на узлах, группирующие их по типу:
:Person,:Company. Один узел может иметь несколько меток. По метке Neo4j понимает, где искать, и к ней можно привязать индекс.
Схема при этом не жёсткая: новый тип связи — это просто рёбра с новой меткой, без миграций и перекройки таблиц. Это главная сила модели — лёгкость развития.
Index-free adjacency: почему обход дёшев
Ключевое отличие от реляционной базы — как хранятся связи. В SQL, чтобы пройти от заказа к его позициям, база берёт order_id, идёт в индекс таблицы позиций и ищет там подходящие строки. Это поиск по индексу — быстрый, но не бесплатный, и он повторяется на каждом шаге связи.
В Neo4j связь — это прямая ссылка: у каждого узла в памяти лежат указатели на его рёбра, а у ребра — на узлы-концы. Чтобы пройти от узла к соседям, база не ищет ничего в индексе — она идёт по указателю, как по ссылке в структуре данных. Это называется index-free adjacency («смежность без индексов»).
Практическое следствие: стоимость обхода зависит от того, сколько рёбер реально пройдено, а не от общего размера базы. Найти друзей друзей у человека одинаково быстро и в графе на тысячу узлов, и на миллиард — если у самого человека соседей немного. В SQL тот же запрос замедляется с ростом таблиц, потому что каждый шаг — это поиск по всё большему индексу.
Чем это отличается от реляционной модели
Сравним на одном вопросе: «есть ли путь от счёта А к счёту Б через цепочку переводов неизвестной длины».
- В SQL это рекурсивный запрос (
WITH RECURSIVE) по таблице переводов: на каждом шаге —JOINпо индексу, и чем глубже цепочка, тем дороже. Количество шагов не выражается в структуре запроса напрямую. - В Neo4j это один шаблон с переменной длиной пути (
-[:ПЕРЕВЁЛ*]->), и база просто идёт по ссылкам от счёта А, пока не упрётся в Б или не кончатся рёбра.
Это не значит, что граф всегда лучше. Для «выбрать заказы за месяц с суммой больше N» реляционная база быстрее и проще — там нет обхода связей, там фильтр по значениям. Neo4j выигрывает там, где вопрос — про связи и их глубину, а не про фильтр по полям. Когда именно стоит переходить на графовую СУБД, а когда хватает рекурсивного SQL, разбирает отдельная статья.
Где это применяется
Модель property graph хорошо ложится на данные, где связи разнотипны и живут своей жизнью: соцсети (люди, компании, события), рекомендации (пользователи и товары), антифрод (счета и переводы), граф знаний (сущности из документов). Общий признак один — связей «многие-ко-многим» больше, чем самих сущностей, и запросы идут «по цепочке».
Где спотыкаются начинающие:
- Путают узлы и свойства. Если по значению нужно искать связи (например, «все, кто в этом городе») — это узел
:City, а не строковое свойствоcityу каждого человека. Свойство — для данных, которые только читают вместе с узлом; узел — для того, что связывает. - Забывают направление ребра. У связи всегда есть направление; в запросе можно обходить в обе стороны, но при моделировании направление задают осмысленно (
КУПИЛидёт от человека к товару, а не наоборот). - Ждут, что граф ускорит всё. Простые фильтры и агрегаты граф не ускоряет — там реляционная база быстрее. Граф — про обход, а не про
GROUP BY.
Дальше — язык Cypher: как выражать шаблоны связей и обходить граф; затем моделирование и эксплуатация — как проектировать граф и какие нужны индексы.