Настройка 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
Вы измеряете первый запуск или последующие прогоны ваших запросов?