1

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

Статистика

Neo4J Version: 2.3.1 
Nodes: 820K 
Relationships: 7.6M 

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

Вот DEV консоль с тестовым набором данных: http://console.neo4j.org/r/b7jk2b

Запросов

MATCH (u1:User {id: {user_id}})-[l1:LIKES]->(p1:Product) 
WITH u1, l1, p1 
ORDER BY p1.created_at DESC 
LIMIT 10 

MATCH (p1)<-[:LIKES]-(u2:User) 
WHERE NOT u1=u2 
WITH u1, l1, p1, u2, COUNT(u2) as rating 
ORDER BY rating DESC 
LIMIT 50 

MATCH (u2)-[l2:LIKES]->(recommendation:Product) 
WHERE NOT (p1)=(recommendation) 
WITH recommendation, COUNT(recommendation) as weight 
RETURN recommendation.id as id 
ORDER BY weight DESC 
LIMIT {limit} 

Наши Индексы

Indexes 
ON :LIKES(created_at)  ONLINE 
ON :Product(id)   ONLINE 
ON :Product(created_at) ONLINE 
ON :User(id)    ONLINE 
ON :User(date_joined)  ONLINE 

No constraints 

Запрос профиля Выход (против копии нашей продукции фикция набор данных)

+-------------------+----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| Operator   | Estimated Rows | Rows | DB Hits | Identifiers        | Other             | 
+-------------------+----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +ProduceResults |    7 | 100 |  0 | id           | id              | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Projection  |    7 | 100 |  0 | anon[382], id, recommendation, weight  | anon[382]            | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Top    |    7 | 100 |  0 | anon[382], recommendation, weight   | Literal(100); weight         | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Projection  |    7 | 129342 | 129342 | anon[382], recommendation, weight   | recommendation.id; weight        | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +EagerAggregation |    7 | 129342 |  0 | recommendation, weight      | recommendation           | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Filter   |    44 | 442432 | 471953 | l1, l2, p1, rating, recommendation, u1, u2 | Ands(NOT(p1 == recommendation), recommendation:Product) | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Expand(All)  |    44 | 472039 | 472089 | l1, l2, p1, rating, recommendation, u1, u2 | (u2)-[l2:LIKES]->(recommendation)      | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Top    |    10 |  50 |  0 | l1, p1, rating, u1, u2      | Literal(50); rating          | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +EagerAggregation |    10 | 527 |  0 | l1, p1, rating, u1, u2      | u1, l1, p1, u2           | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Filter   |    92 | 563 |  563 | anon[82], anon[119], l1, p1, u1, u2  | Ands(NOT(u1 == u2), u2:User)       | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Expand(All)  |    92 | 574 |  584 | anon[82], anon[119], l1, p1, u1, u2  | (p1)<-[:LIKES]-(u2)          | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Top    |    5 |  10 |  0 | anon[82], l1, p1, u1      | Literal(10);           | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Projection  |    5 |  42 |  42 | anon[82], l1, p1, u1      | u1; l1; p1; p1.created_at        | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Filter   |    5 |  42 |  413 | l1, p1, u1         | p1:Product            | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +Expand(All)  |    6 | 413 |  414 | l1, p1, u1         | (u1)-[l1:LIKES]->(p1)         | 
| |     +----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 
| +NodeIndexSeek |    1 |  1 |  2 | u1           | :User(id)            | 
+-------------------+----------------+--------+---------+--------------------------------------------+---------------------------------------------------------+ 

Я видел тематические исследования, где люди используют Neo4j делать в режиме реального времени совместной фильтрации, поэтому я предположил, что это должно быть возможно получить такой запрос работает над такого рода данных. Неужели я нереальна? Мы запускаем это на узле Amazon EC2 Compute-Optimized (c4.large), поэтому я решил, что он будет достаточно результативным.

Я оставил царапины у меня здесь и был бы очень признателен за любой вход.

Cheers, David.

+0

Возможно, вас заинтересует: [neo4j-fiber] (https://github.com/VeliovGroup/neo4j-fiber). Этот пакет имеет встроенную оптимизацию запросов. Вот [пример приложения] (http: //neo4j-graph.meteor.com) –

+0

Как долго длится ваш запрос? –

ответ

0

[В сторону:. Консоль DEV, когда вновь, не повторно создавать индексы, поэтому они должны быть воссозданы вручную]

Я не знаю, если это достаточно хорошо для вас, но вы можете устранить около 44% из хитов БД в ваших профилированных результатов просто не уточняя этикетки для большинства узлов (p1, u2 и recommendation) в запросе:

MATCH (u1:User {id: {user_id}})-[l1:LIKES]->(p1) 
WITH u1, l1, p1 
ORDER BY p1.created_at DESC 
LIMIT 10 

MATCH (p1)<-[:LIKES]-(u2) 
WHERE NOT u1=u2 
WITH u1, l1, p1, u2, COUNT(u2) as rating 
ORDER BY rating DESC 
LIMIT 50 

MATCH (u2)-[l2:LIKES]->(recommendation) 
WHERE NOT (p1)=(recommendation) 
WITH recommendation, COUNT(recommendation) as weight 
RETURN recommendation.id as id 
ORDER BY weight DESC 
LIMIT {limit} 

ярлык для u1 должен еще указывается в запросе, si nce, что позволяет Cypher индексироваться на :User(id). В общем, следует тщательно оценить запрос, чтобы увидеть, когда метки узлов могут быть устранены. В вашем случае, p1, u2 и recommendation узлов можно найти по следующим отношениям (и, я полагаю, тип отношения LIKE используется только для указания узлов Product), поэтому указание их меток является излишним и вызывает ненужную работу.

Результатов Профиля для вышеупомянутого запроса будут иметь DB Hits значение 0 для всех Filter шагов (и в одном случае Filter шаг будет полностью исключен).

+0

Hi cybersam, Спасибо за отзыв. Я на самом деле думал, что предоставление меток каждому узлу делает запрос более целенаправленным и улучшенным: - | Рад узнать, что я был не прав в этом смысле. К сожалению, у нас также есть отношения, которые являются '(u: User) - [: LIKES] -> (p: Shop)', что означает, что мы должны фильтровать тип целевого узла. Однако, думая об этом, мы должны, вероятно, превратить отношения в нечто более специфичное, например '[: LIKES_SHOP], чтобы избежать этой необходимости. Вы дали мне пищу для размышлений. Я собираюсь вернуться в запрос и посмотреть, что я могу придумать. Еще раз спасибо, David –

Смежные вопросы