Monday, 29 March 2010

Neo4J - java graph DB

Недавно я рассказывал про граф ориентированные базы данных. А сегодня хочу поделиться с Вами историей использования одной из них. Встречайте Neo4J.
Итак немного о самой системе: Neo4J предлагает Вам полноценную базу данных с транзакциями, индексами (Lucene), несколькими режимами работы и низким порогом вхождения, благодаря очень простой структуре. Все коды открыты и доступны, а приложение поставляется под двойной лицензией AGPL для некоммерческого использования и тарифная сетка для коммерческого. Для начала использования данной базы Вам достаточно знать джаву и понимать чего Вы хотите от сетевой структуры данных (графа).

Мне, при моём знакомстве, была интересна производительность при больших объемах данных и удобство работы с самой БД. Начнём с удобства и создадим базу данных с большим кол-вом вершин и ребёр. Для этого используем специальный класс доступа к БД, который оптимизирован под вставку:

batchGraphDb = new BatchInserterImpl( dbpath, stringProps );
batchIndexService = new LuceneIndexBatchInserterImpl( batchGraphDb );

, где dbPath - путь к файлам будущей базы данных, а stringProps - настройки.
Cоздадим несколько вершин следующим образом:

Map<String, Object> properties = new HashMap<String, Object>();

properties.put("a_key", 5);
properties.put("b_key", "some string");

long createdNode = batchGraphDb.createNode(properties);
batchIndexService.index(createdNode, "a_key", properties.get("a_key"));

Далее в идеале стоит вызвать метод batchIndexService.optimize(); который приведёт индексы в порядок и продолжим создавать рёбра:

Map<String, Object> edgeProperties = new HashMap<String, Object>();
edgeProperties.put("length", 345);
edgeProperties.put("version", "7.5");

long startNodeId = batchIndexService.getSingleNode("a_key", 5);
long endNodeId = batchIndexService.getSingleNode("a_key", 7);

batchGraphDb.createRelationship(
startNodeId,
endNodeId,
DynamicRelationshipType.withName("trust"),
edgeProperties);

Не хитрые манипуляции создают ребро из одной вершины в другую с типом "trust" и собственными свойствами. Ну и на последок закрытие соединения с БД:

if ( null != batchIndexService ) batchIndexService.shutdown();
if ( null != batchGraphDb ) batchGraphDb.shutdown();

Данные готовы, а нам не терпиться проверить её производительность. Показатели качества будут озвучены в следующем посте, а пока можно ознакомиться с другой статьей на эту тему: MySQL vs. Neo4j on a Large-Scale Graph Traversal

item

6 comments:

  1. Очень интересно было бы услышать о реальной задаче и том как вы её решили при помощи Neo4J

    ReplyDelete
  2. Еще не решил, но тесты все уже провёл. Следующий пост о производительности будет.

    А про конкретную задачу - как привер могу привести нахождение кратчайшего пути в OSM графе.

    ReplyDelete
  3. Простите, а где же обещанный пост о производительности?

    ReplyDelete
  4. Нда, с этим заминка. Как всегда под нагрузкой разработки руки не дошли до публикации, а на данный момент результатов исследований уже практически не осталось. Да и доступа к серверным ресурсам уже нет, хотя материал был интересный.

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

    Работали с разработчиками напрямую. Они ничего не смогли сделать с нашими объёмами, к сожалению. В целом впечатление от работы с БД осталось достаточно положительное. Ребята отзывчивые, код работает как обещано, АПИ более ли менее продумано. Для менее требовательных задач или меньшего объема данных, думаю вполне могла бы подойти.

    ReplyDelete
  5. А на каких обьемах начинался ре-маппинг? Вот есть мысли ее использовать, но не уверен до конца... И если не секрет, что вы в итоге выбрали?

    ReplyDelete
  6. Ре-маппинг, что логично, начинается если БД не помещается в ОЗУ. В нашем случае на тестовом наборе объем БД занимал около 8GB (это был маленькая часть реальных данных). Хотя реально можно гораздо более компактно удожить эти данные.

    Выбрали отпимизицию самописного велосипеда на тот момент, который был во многом ограничен, но справлялся с объемом и скоростью. Оптимизация, кстати, удалась.

    ReplyDelete