Настройка Neo4j для производительности

Я импортировал данные с помощью Michael Hunger Batch Import, через которые я создал: -

4,612,893 nodes
14,495,063 properties
    node properties are indexed.
5,300,237 relationships

{ Вопрос} Запросы Cypher выполняются слишком медленно, почти обход, простой обход занимает > 5 минут, чтобы вернуть результаты, пожалуйста, дайте мне знать, как настроить сервер, чтобы получить лучшую производительность и что я делать неправильно.

Сведения о магазине: -

-rw-r--r-- 1 root root 567M Jul 12 12:42 data/graph.db/neostore.propertystore.db
-rw-r--r-- 1 root root 167M Jul 12 12:42 data/graph.db/neostore.relationshipstore.db
-rw-r--r-- 1 root root  40M Jul 12 12:42 data/graph.db/neostore.nodestore.db
-rw-r--r-- 1 root root 7.8M Jul 12 12:42 data/graph.db/neostore.propertystore.db.strings
-rw-r--r-- 1 root root  330 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.keys
-rw-r--r-- 1 root root  292 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.names
-rw-r--r-- 1 root root  153 Jul 12 12:42 data/graph.db/neostore.propertystore.db.arrays
-rw-r--r-- 1 root root   88 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index
-rw-r--r-- 1 root root   69 Jul 12 12:42 data/graph.db/neostore
-rw-r--r-- 1 root root   58 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.nodestore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.arrays.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.index.keys.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.propertystore.db.strings.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshipstore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.id
-rw-r--r-- 1 root root    9 Jul 12 12:42 data/graph.db/neostore.relationshiptypestore.db.names.id

Я использую

neo4j-community-1.9.1
java version "1.7.0_25"
Amazon EC2 m1.large instance with Ubuntu 12.04.2 LTS (GNU/Linux 3.2.0-40-virtual x86_64)
RAM ~8GB.
EBS 200 GB, neo4j is running on EBS volume.

Вызывается как. /neo 4j-community-1.9.1/bin/neo4j start

Ниже представлена ​​информация о сервере neo4j:

neostore.nodestore.db.mapped_memory                 161M
neostore.relationshipstore.db.mapped_memory         714M
neostore.propertystore.db.mapped_memory              90M
neostore.propertystore.db.index.keys.mapped_memory    1M
neostore.propertystore.db.strings.mapped_memory     130M
neostore.propertystore.db.arrays.mapped_memory      130M
mapped_memory_page_size                               1M
all_stores_total_mapped_memory_size                 500M

{ Модель данных} похожа на Социальный график: -

User-User
    User-[:FOLLOWS]->User
User-Item
    User-[:CREATED]->Item
    User-[:LIKE]->Item
    User-[:COMMENT]->Item
    User-[:VIEW]->Item
Cluster-User
    User-[:FACEBOOK]->SocialLogin_Cluster
Cluster-Item
    Item-[:KIND_OF]->Type_Cluster
Cluster-Cluster
    Cluster-[:KIND_OF]->Type_Cluster

{ Некоторые запросы} и время:

START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
WHERE NOT(a=b)
RETURN u,COUNT(b)

Запрос занял 1015348мс. Возвращено 70956115 количество результатов.

START a=node:nodes(kind="user")
RETURN a,length(a-[:CREATED|LIKE|COMMENT|FOLLOWS]-()) AS cnt
ORDER BY cnt DESC
LIMIT 10

Запрос занял 231613мс


Из предложений я усовершенствовал коробку до M1.xlarge и M2.2xlarge

  • M1.xlarge(vCPU: 4, ECU: 8, RAM: 15 ГБ, хранилище экземпляров: ~ 600 ГБ).
  • M2.2xlarge (vCPU: 4, ECU: 13, RAM: 34 ГБ, хранилище экземпляров: ~ 800 ГБ).

Я настроил свойства, как показано ниже, и запустил их из хранилища экземпляров (в отличие от EBS)

neo4j.properties

neostore.nodestore.db.mapped_memory=1800M
neostore.relationshipstore.db.mapped_memory=1800M
neostore.propertystore.db.mapped_memory=100M
neostore.propertystore.db.strings.mapped_memory=150M
neostore.propertystore.db.arrays.mapped_memory=10M

Neo4j-wrapper.conf

wrapper.java.additional.1=-d64
wrapper.java.additional.1=-server
wrapper.java.additional=-XX:+UseConcMarkSweepGC
wrapper.java.additional=-XX:+CMSClassUnloadingEnabled
wrapper.java.initmemory=4098
wrapper.java.maxmemory=8192

но все же запросы (например, ниже) выполняются в минутах ~ 5-8 минут, что неприемлемо с точки зрения рекомендаций.

Query:

START u=node(467242)
MATCH u-[r1:LIKE]->a<-[r2:LIKE]-lu-[r3:LIKE]-b
RETURN u,COUNT(b)

{ Профилирование}

neo4j-sh (0)$ profile START u=node(467242) MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b RETURN u,COUNT(b);
==> +-------------------------+
==> | u            | COUNT(b) |
==> +-------------------------+
==> | Node[467242] | 70960482 |
==> +-------------------------+
==> 1 row
==> 
==> ColumnFilter(symKeys=["u", "  INTERNAL_AGGREGATEad2ab10d-cfc3-48c2-bea9-be4b9c1b5595"], returnItemNames=["u", "COUNT(b)"], _rows=1, _db_hits=0)
==> EagerAggregation(keys=["u"], aggregates=["(  INTERNAL_AGGREGATEad2ab10d-cfc3-48c2-bea9-be4b9c1b5595,Count)"], _rows=1, _db_hits=0)
==>   TraversalMatcher(trail="(u)-[r1:LIKE|COMMENT WHERE true AND true]->(a)<-[r2:LIKE|COMMENT WHERE true AND true]-(lu)-[r3:LIKE WHERE true AND true]-(b)", _rows=70960482, _db_hits=71452891)
==>     ParameterPipe(_rows=1, _db_hits=0)


neo4j-sh (0)$ profile START u=node(467242) MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b RETURN count(distinct a),COUNT(distinct b),COUNT(*);
==> +--------------------------------------------------+
==> | count(distinct a) | COUNT(distinct b) | COUNT(*) |
==> +--------------------------------------------------+
==> | 1950              | 91294             | 70960482 |
==> +--------------------------------------------------+
==> 1 row
==> 
==> ColumnFilter(symKeys=["  INTERNAL_AGGREGATEe6b94644-0a55-43d9-8337-491ac0b29c8c", "  INTERNAL_AGGREGATE1cfcd797-7585-4240-84ef-eff41a59af33", "  INTERNAL_AGGREGATEea9176b2-1991-443c-bdd4-c63f4854d005"], returnItemNames=["count(distinct a)", "COUNT(distinct b)", "COUNT(*)"], _rows=1, _db_hits=0)
==> EagerAggregation(keys=[], aggregates=["(  INTERNAL_AGGREGATEe6b94644-0a55-43d9-8337-491ac0b29c8c,Distinct)", "(  INTERNAL_AGGREGATE1cfcd797-7585-4240-84ef-eff41a59af33,Distinct)", "(  INTERNAL_AGGREGATEea9176b2-1991-443c-bdd4-c63f4854d005,CountStar)"], _rows=1, _db_hits=0)
==>   TraversalMatcher(trail="(u)-[r1:LIKE|COMMENT WHERE true AND true]->(a)<-[r2:LIKE|COMMENT WHERE true AND true]-(lu)-[r3:LIKE WHERE true AND true]-(b)", _rows=70960482, _db_hits=71452891)
==>     ParameterPipe(_rows=1, _db_hits=0)

Пожалуйста, дайте мне знать параметры конфигурации и neo4j для настройки. Спасибо заранее

Ответ 1

Запуск этого на моем компьютере macbook с небольшой оперативной памятью и процессором с вашим набором данных.

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

Вы сталкиваетесь с комбинаторным взрывом.

Каждый шаг пути добавляет "times rels" элементов/строк к вашим подстроенным подграфам.

Смотрите здесь: вы попадаете в 269268 матчей, но у вас есть только 81674 различных lu's

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

START u=node(467242)
MATCH u-[:LIKED|COMMENTED]->a
WITH distinct a
MATCH a<-[r2:LIKED|COMMENTED]-lu
RETURN count(*),count(distinct a),count(distinct lu);

+---------------------------------------------------+
| count(*) | count(distinct a) | count(distinct lu) |
+---------------------------------------------------+
| 269268   | 1952              | 81674              |
+---------------------------------------------------+
1 row

895 ms

START u=node(467242)
MATCH u-[:LIKED|COMMENTED]->a
WITH distinct a
MATCH a<-[:LIKED|COMMENTED]-lu
WITH distinct lu
MATCH lu-[:LIKED]-b
RETURN count(*),count(distinct lu), count(distinct b)
;
+---------------------------------------------------+
| count(*) | count(distinct lu) | count(distinct b) |
+---------------------------------------------------+
| 2311694  | 62705              | 91294             |
+---------------------------------------------------+

Здесь у вас есть общие совпадения 2.3M и только 91k различных элементов. Так почти на 2 порядка.

Это огромная совокупность, которая скорее представляет собой запрос BI/статистики, который представляет собой OLTP-запрос. Обычно вы можете сохранить результаты, например. на пользовательском node и только повторно выполните это в фоновом режиме.

ЭТИ типы запросов снова представляют собой глобальные запросы на график (статистика/BI), в этом случае 10 ведущих пользователей.

Обычно вы запускаете их в фоновом режиме (например, один раз в день или час) и подключаете 10 лучших пользовательских узлов к специальному node или индексу, который затем может быть запрошен в течение нескольких мс.

START a=node:nodes(kind="user") RETURN count(*);
+----------+
| count(*) |
+----------+
| 3889031  |
+----------+
1 row

27329 ms

После того, как вы выполняете соответствие по всему графику, то есть пользователям 4M, которые являются глобальными, а не графическим локальным запросом.

START n=node:nodes(kind="top-user")
MATCH n-[r?:TOP_USER]-()
DELETE r
WITH distinct n
START a=node:nodes(kind="user")
MATCH a-[:CREATED|LIKED|COMMENTED|FOLLOWS]-()
WITH n, a,count(*) as cnt
ORDER BY cnt DESC
LIMIT 10
CREATE a-[:TOP_USER {count:cnt} ]->n;

+-------------------+
| No data returned. |
+-------------------+
Relationships created: 10
Properties set: 10
Relationships deleted: 10

70316 ms

Тогда запрос будет выглядеть следующим образом:

START n=node:nodes(kind="top-user")
MATCH n-[r:TOP_USER]-a
RETURN a, r.count
ORDER BY r.count DESC;

+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| a                                                                                                                                                  | r.count |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
….
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
10 rows

4 ms

Ответ 2

Хорошо, так прежде всего, всего за 8 ГБ памяти, что очень большой график. Вы должны серьезно подумать о том, чтобы получить большую коробку. Neo4j фактически обеспечивает чрезвычайно хороший аппаратный калькулятор, который позволит вам точно определить, что подходит для ваших нужд:

http://neotechnology.com/calculatorv2/

Надуманным способом (поскольку для определения размера имеются более релевантные показатели), их калькулятор должен оценивать как минимум 10 ГБ.

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

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

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

Также похоже, что у вас есть искусственная кепка для вашего размера кучи Java. Если вы попытаетесь запустить java с помощью команды, например:

java -Xmx8g //Other stuff

Вы выделите 8 концертов вместо стандартных ~ 500 мегабайт, что также поможет.

Ответ 3

Вам не нужно:

WHERE NOT(a=b)

Два разных идентификатора никогда не являются одинаковыми node в шаблоне.

Можете ли вы использовать profile с вашими запросами?

profile START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
RETURN u,COUNT(b)

Было бы также интересно посмотреть, сколько узлов затронуто:

profile START u=node(467242)
MATCH u-[r1:LIKE|COMMENT]->a<-[r2:LIKE|COMMENT]-lu-[r3:LIKE]-b
RETURN count(distinct a),COUNT(distinct b),COUNT(*)

Вы также можете уменьшить свои настройки MMIO до реальных значений:

neostore.nodestore.db.mapped_memory=180M
neostore.relationshipstore.db.mapped_memory=750M

Если вы объявите всю оперативную память ОЗУ как кучу, она будет конкурировать с FS-буферами и буферами mmio.

wrapper.java.initmemory=5000
wrapper.java.maxmemory=5000

Вы измеряете первый запуск или последующие прогоны ваших запросов?