Как стать автором
Обновить

Комментарии 17

Как база данных он неплох, но браузер в нём - это что-то с чем-то.

Я в 90х начинал с графовой (сетевой) базы. Достоинства там - нет поиска (в том смысле что искать по базе не надо вообще - на все и так есть указатели), размер гораздо меньше реляционных. Но недостаток все перевешивает - все запросы к базе фактически зашиты в ее структуру. Может сейчас чего и придумали, но тогда поддерживать ее был сущий ад.

Neo4j хорош, пока не надо на нем строить прод. С этого момента надо готовить кошелек, так как в бесплатной версии, можно сказать, для этого ничего нет. В текущих реалиях, даже будучи готовым заплатить не факт что их возьмут.

Китайцы возьмут, но ценник у них был на уровне, а то и выше neo4j.

Правда опен сурс версии за глаза.

А почему выбор остановился именно на neo4j а не на arangodb, к примеру?

БД Neo4j имеет собственный язык запросов Cypher. Запросы на нем выглядят лаконичнее и понятнее, чем аналогичные запросы для реляционной БД;

Чуть больше года занимался проектом на Neo4j и категорически не согласен с этим утверждением. Когда впервые увидел, что они всерьёз рекламируют Cypher как "overcoming SQL pain", просто всплакнул кровавыми слезами))

Neo4j хорошо работает только с максимально простыми, атомарными запросами. Начинаешь усложнять логику - план запроса летит в трубу. Из-за этого приходится строить километровые портянки с аккуратной трансляцией параметров из блока в блок через with или материализовывать промежуточные результаты во внешние системы/файлы.

Уже после опыта с Neo4j довелось поработать с графами в pgrouting, это было несказанное облегчение по всем аспектам)

Я бы выбрал Neo4j только как вспомогательный инструмент для каких-то простых задач по поиску связей (но, правда, практически с неограниченным масштабом, это большой плюс). Если в приоритете не масштаб, а сложная логика поиска/сложный ETL на графах - полно инструментов гораздо лучше.

полно инструментов гораздо лучше

А каких именно? Просто интересно)

Лучшее решение - собрать собственный фреймворк под свою конкретную задачу)
Хранилище под капотом может быть и реляционным, и нет.
Все основные алгоритмы обхода графов реализованы на всех доступных языках программирования, не надо изобретать велосипед.

Из того, что можно развернуть на коленке за 10 минут пробовал pgrouting в PostgreSQL и networkx в Python - отличные и простые инструменты, которые достаточно предсказуемо масштабируются)
Ну и лично для меня большой плюс - в этих средах графы легко наложить и отобразить на географических картах в любой нужной проекции (или любой другой подложке)

Про WITH это кстати правда, так и есть

>Такие операции в реляционных базах стоят очень дорого. 

В каждом обзоре графовых баз мне не хватает ответа на вопрос «почему?» Если нужно найти друзей друзей с какими-то условиями, то реляционная БД

  1. Index only scan чтобы найти друзей

  2. Index scan чтобы найти их друзей

  3. Читаем таблицу и фильтруем результат.

Каким образом графовая БД сделает меньше чтений диска? А что будет когда мы начнём обновлять данные? А если нужно бродить подданным, то чем хеш индекс хуже чем структуры данных графовой БД?

Ну наверное не будет второго index scan как минимум. Композитный хеш-индекс (если он имеется ввиду) это тоже как бы граф, но с поддержкой только одного запроса (c1,c2,c3), а нормальный граф это "индекс" во все стороны. При обновлении перепишутся adjacency list'ы локально

Что-то я не понимаю. Предположим, что в узле графовой БД лежит adjacency list, который, скорее всего b-tree. Чтобы найти друзей нужно по этому b-tree ходить, что практически эквивалентно index scan. Далее процедуру нужно произвести для каждого из найденных друзей. Если в каждом узле лежит свое дерево, то это сканирование множества деревьев, что даже хуже чем index scan. После этого у нас список указателей на узлы, надо пойти и прочитать их.

Можно представить, что грабовая БД это triple store, что-то вроде AWS Neptune. Ну там тоже будут бесконечные сканирования индексов...

Да, adjacency list может быть типа b-tree только он маленький локальный, а не вся таблица целиком как в табличной базе. Плюс этот adjacency list читается разом с диска в память, а в табличной сначала нужно прочитать индекс кусками (весь в RAM не поместится), пока не найдешь всех нужных, потом куча random read'ов чтобы достать данные, на следующем шаге все по новой. Представьте таблицу для друзей from_id,to_id. Сначала сканируем всю from_id (первый огромный индекс), потом всю to_id таким же образом (потому что может быть связь в другом направлении), потом достаем данные из ячеек - to_id для from, from_id для to. Это первый шаг. Потом снова сканируем два огромных индекса, только уже для каждого друга первого порядка. Вообщем обычно даже на 100к юзеров табличная база ложится уже на третьем хопе.
Neptune да, больше похож на фейк, типа у нас есть графовая база, там я помню в начале он даже ошибки RDS выбрасывал, потом спрятали.

Да, adjacency list может быть типа b‑tree только он маленький локальный, а не вся таблица целиком как в табличной базе

Это серьезное допущение, например нода "касса" и связь "платежи", за пару лет накопится очень много данных. Или еще лучше "город" - "жители".

а в табличной сначала нужно прочитать индекс кусками (весь в RAM не поместится)

Это справедливо и для графовой базы, если мы хотим иметь много связей в узле. Может быть тут какие-то оптимизации появляются, типа до 100 указателей внутри узла, а затем в индекс...

Представьте таблицу для друзей from_id,to_id. ...

Думаю в базе будет примерно так

  1. Сканируем индекс друзей, находим все to_id. Так как это b-tree, то прочитать нужно всего пару страниц, прежде чем дойдем до первой записи друзей, дальше уже читаем страницы с данными. Тут, скорее всего, чтение каждой страницы это random read.

  2. Далее зависит от ситуации - если нам нужны друзья друзей, то таблицу друзей читать не надо, все идентификаторы у нас уже есть, можно опять читать индекс.

С графовой базой данных будет, наверное так

  1. Начинаем с записи "я". adjacency list хранить рядом с записью "я" нельзя, так как он растет и меняется во времени. То есть не может все храниться вот так на диске "я|adjacency list|друг|adjacency list|...", потому что adjacency list обновляется, растет, уменьшается. Тогда рядом с записью "я" лежит указатель (адрес на диске или id) помогающий найти мой adjacency list. Это первый random read.

  2. Читаем adjacency list, если он большой, то он раскидан по страницам на диске, а это несколько random reads.

  3. Теперь у нас есть список друзей, можно для каждого из них повторить процесс, начиная с пункта 1.

Собственно если все так, то мы делаем 1-2 чтения минимум для каждого друга и друга-друга, никакого выигрыша в количестве чтений диска тут не просматривается.

Кассу и платежи надо дробить по периодам, есть понятие - касовая смена, вообще это общий подход при работе с супер-нодами.

Про индекс, если хранить указатель to_id прямо в индексе, вообще без таблиц, то да верно. Так как раз работает Blazegraph, и Neptune получается тоже, я сейчас вспомнил ошибки были про btree, видимо используют из RDS.

Я думаю random-read "в среднем" меньше, потому что отличия в скорости реально видны. Причина может быть в более простом шардировании с концепцией нода, а не таблицы, и в кешированиии по той же причине. Ну и плюс типичные SQL движки не могут так джоинить указатели, да, это возможно с b+tree, но реалиовано в тех базах, которые считаются графовыми (Blazegraph, Neptune, JanusGraph например, ElasticSearch для шардированого b+tree и Cassandra для остальных данных). А вот Neo4j, к примеру, не на b+tree, а на double linked list https://neo4j.com/developer-blog/relationship-chain-locks-dont-block-the-rock/ TigerGraph тоже заявляют что у них не hashmap там.

Спасибо, этого и не хватало в статье. Вспомнился старый добрый Хабр с хардкорными техническими разговорами.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории