Оптимизация или реструктуризация nn отношений Запросы Neo4j, вызывающие очень медленное время отклика - PullRequest
0 голосов
/ 11 января 2020

Мне нужна помощь с одним из моих графиков Neo4j. Мои узлы и отношения выглядят примерно так

neo4j graph relationships

Это пример сквозных отношений в графе.

проблема связана с тем, что узел (хранилище) имеет несколько (уведомления), и они связаны со множеством (типы действий уведомления) и (типы уведомления)

Запрос выглядит примерно так:

MATCH (s:app)-[:HAS_GEOZONE]->(g:geozone)-[:HAS_ENGAGEMENTZONE]->(e:engagement_zone)-[:HAS_STORE]->(st:store)-[:HAS_NOTIFICATION]->(nt:notification), shortestPath((nt)-[r:HAS_NOTIFICATION_TYPE]->(ntt:notification_type)), shortestPath((nt)-[ra:HAS_NOTIFICATION_ACTION_TYPE]->(ntta:notification_action_type)), (st)-[:HAS_ATTRIBUTE]->(sta:store_attribute) WHERE s.uuid={app_id} AND sta.key='name' OPTIONAL MATCH (nt)-[:HAS_BRAND]->(br:brand) OPTIONAL MATCH (nt)-[:HAS_LABEL]->(l:loyalty) RETURN nt.uuid as nt_id, COLLECT(DISTINCT st.uuid) as st_ids, COLLECT(DISTINCT sta.value) as store_names, COLLECT(DISTINCT properties(br)) as notification_brands, COLLECT(DISTINCT properties(l)) as notification_labels, COLLECT(DISTINCT properties(nt)) as notification, COLLECT(DISTINCT properties(ntt)) as notification_type, COLLECT(DISTINCT properties(ntta)) as notification_action_type ORDER BY nt_id

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

например, ответ одной записи из исходного запроса -

enter image description here

И, json выглядит как ниже, где имена столбцов являются узлами в графе

 [
  {
    "nt_id": "002a3ba0-2584-11ea-93de-118eb121a0f8",
    "st_ids": [
      "e5fb2cc0-2246-11ea-a327-c1a6ac2ca4a0"
    ],
    "store_names": [
      "AND"
    ],
    "notification_brands": [],
    "notification_labels": [],
    "notification": [
      {
        "sub_text": "Happy shopping!!",
        "action_url": "https://www.tatacliq.com/and/c-mbh11a00015",
        "image_url": "",
        "notification_match_type": "GENERAL",
        "validity_start": 1,
        "text": "Welcome to {{store_name}}",
        "inventory_request_params": "",
        "isActive": true,
        "validity_end": 1,
        "uuid": "002a3ba0-2584-11ea-93de-118eb121a0f8",
        "active_days": "{\"SUNDAY\":\"1100-2100\",\"MONDAY\":\"1100-2100\",\"TUESDAY\":\"1100-2100\",\"WEDNESDAY\":\"1100-2100\",\"THURSDAY\":\"1100-2100\",\"FRIDAY\":\"1100-2100\",\"SATURDAY\":\"1100-2100\"}"
      }
    ],
    "notification_type": [
      {
        "name": "Deals & Offers",
        "uuid": "2fdc2b20-4faf-11e9-bfff-47192e190163"
      }
    ],
    "notification_action_type": [
      {
        "name": "In Store",
        "uuid": "ce78fc50-4fae-11e9-b974-7995b4e2b93d"
      }
    ]
  }
]
  • neo4j версия: neo4j: 3.5.12-enterprise и работает на Docker на AWS m5.xlarge машине с настроенной кучей 12G и размером кеша

  • что за Используемый вами API / драйвер: Rest API на ECS и Node JS на отдельных экземплярах

  • снимок экрана [PROFILE or EXPLAIN]

execution plan

Кроме того, добавляется query.log, который объясняет временные рамки выполнения в реальной среде.

query.log query.log .1

Любая помощь в этом очень ценится!

Спасибо, Арнаб

Ответы [ 2 ]

2 голосов
/ 13 января 2020

Hej Arnab!

Я немного сбит с толку из-за того, что вы пытаетесь достичь с помощью вызова 2 shorttestPath, который вы имеете в своем МАТЧЕ. Возможно, вы захотите использовать функцию shorttestPath для возврата кратчайшего пути между двумя узлами, которые вы ранее сопоставили. Тогда это будет выглядеть, например, так:

MATCH (a), (b), p = shortestPath((a)-[*]-(b))
RETURN p

Вы должны использовать переменную длину пути (*), чтобы позволить функции искать все возможные пути от a до b.

Теперь, если мы возьмем вызов функции shorttestPath из вашего запроса ie и в зависимости от того, как вы написали свой запрос, вы должны получить тот же результат, но, надеюсь, быстрее:

MATCH (s:app)-[:HAS_GEOZONE]->(g:geozone)-[:HAS_ENGAGEMENTZONE]->(e:engagement_zone)-[:HAS_STORE]->(st:store)-[:HAS_NOTIFICATION]->(nt:notification), (nt)-[r:HAS_NOTIFICATION_TYPE]->(ntt:notification_type), (nt)-[ra:HAS_NOTIFICATION_ACTION_TYPE]->(ntta:notification_action_type), (st)-[:HAS_ATTRIBUTE]->(sta:store_attribute)
WHERE s.uuid={app_id} AND sta.key='name'
OPTIONAL MATCH (nt)-[:HAS_BRAND]->(br:brand)
OPTIONAL MATCH (nt)-[:HAS_LABEL]->(l:loyalty)
RETURN nt.uuid as nt_id, COLLECT(DISTINCT st.uuid) as st_ids, COLLECT(DISTINCT sta.value) as store_names, COLLECT(DISTINCT properties(br)) as notification_brands, COLLECT(DISTINCT properties(l)) as notification_labels, COLLECT(DISTINCT properties(nt)) as notification, COLLECT(DISTINCT properties(ntt)) as notification_type, COLLECT(DISTINCT properties(ntta)) as notification_action_type ORDER BY nt_id

И вы даже можете попробовать использовать последующие совпадения, чтобы сделать ваш запрос еще быстрее, а не одно совпадение:

MATCH (s:app)-[:HAS_GEOZONE]->(g:geozone)-[:HAS_ENGAGEMENTZONE]->(e:engagement_zone)-[:HAS_STORE]->(st:store)-[:HAS_NOTIFICATION]->(nt:notification)
WHERE s.uuid={app_id}
MATCH (nt)-[r:HAS_NOTIFICATION_TYPE]->(ntt:notification_type)
MATCH (nt)-[ra:HAS_NOTIFICATION_ACTION_TYPE]->(ntta:notification_action_type)
MATCH (st)-[:HAS_ATTRIBUTE]->(sta:store_attribute)
WHERE sta.key='name'
OPTIONAL MATCH (nt)-[:HAS_BRAND]->(br:brand)
OPTIONAL MATCH (nt)-[:HAS_LABEL]->(l:loyalty)
RETURN nt.uuid as nt_id, COLLECT(DISTINCT st.uuid) as st_ids, COLLECT(DISTINCT sta.value) as store_names, COLLECT(DISTINCT properties(br)) as notification_brands, COLLECT(DISTINCT properties(l)) as notification_labels, COLLECT(DISTINCT properties(nt)) as notification, COLLECT(DISTINCT properties(ntt)) as notification_type, COLLECT(DISTINCT properties(ntta)) as notification_action_type ORDER BY nt_id

Но учтите, что в зависимости от вашей графовой модели эти 2 запроса могут давать разные результаты. Если вам интересно узнать разницу между этими двумя различными способами сопоставления вашего графика, вы можете прочитать ответ Адама в следующем посте: https://community.neo4j.com/t/significance-of-using-in-neo4j-multiple-relationships-cypher-query/10800

Надеюсь, это поможет! BR, Fabien

0 голосов
/ 14 января 2020

Спасибо за ответ. Ну, мне удалось решить это сейчас. Причина, по которой я ввел shorttestPath, заключалась в том, что у меня был запрос, который вы предложили ранее. Это

MATCH (s:app)-[:HAS_GEOZONE]->(g:geozone)-[:HAS_ENGAGEMENTZONE]->(e:engagement_zone)-[:HAS_STORE]->(st:store)-[:HAS_NOTIFICATION]->(nt:notification), (nt)-[r:HAS_NOTIFICATION_TYPE]->(ntt:notification_type), (nt)-[ra:HAS_NOTIFICATION_ACTION_TYPE]->(ntta:notification_action_type), (st)-[:HAS_ATTRIBUTE]->(sta:store_attribute)
WHERE s.uuid={app_id} AND sta.key='name'
OPTIONAL MATCH (nt)-[:HAS_BRAND]->(br:brand)
OPTIONAL MATCH (nt)-[:HAS_LABEL]->(l:loyalty)
RETURN nt.uuid as nt_id, COLLECT(DISTINCT st.uuid) as st_ids, COLLECT(DISTINCT sta.value) as store_names, COLLECT(DISTINCT properties(br)) as notification_brands, COLLECT(DISTINCT properties(l)) as notification_labels, COLLECT(DISTINCT properties(nt)) as notification, COLLECT(DISTINCT properties(ntt)) as notification_type, COLLECT(DISTINCT properties(ntta)) as notification_action_type ORDER BY nt_id

И если на моем графике было входящее отношение, т.е. [r:HAS_NOTIFICATION_TYPE] & [ra:HAS_NOTIFICATION_ACTION_TYPE] для каждого узла Уведомления, и было несколько уведомлений для каждого узла Магазина. Когда график вырос, т.е. когда у меня было более 1500+ магазинов и ~ 200 уведомлений под каждым и у каждого из них были указанные выше входящие отношения. Запрос просто не будет работать и зависнет и взломает сервер. Если изменить их на shorttestPath, это не произойдет, но время результатов все еще велико.

Теперь я сохраняю uuid узлов Notif_Type & Notif_Action_Type в свойствах узла Notification. И обновил запрос следующим образом:

MATCH (n:business_entity)-[:HAS_APP]->(s:app)-[:HAS_GEOZONE]->(g:geozone)-[:HAS_ENGAGEMENTZONE]->(e:engagement_zone)-[:HAS_STORE]->(st:store)-[:HAS_NOTIFICATION]->(nt:notification), 
        (st)-[:HAS_ATTRIBUTE]->(sta:store_attribute)
        WHERE n.uuid={b_id} AND s.uuid={app_id} AND sta.key='name'
        OPTIONAL MATCH (nt)-[:HAS_BRAND]->(br:brand)
        OPTIONAL MATCH(ntt:notification_type) WHERE ntt.uuid = nt.notification_type
        OPTIONAL MATCH(ntta:notification_action_type) WHERE ntta.uuid = nt.notification_action_type
        RETURN nt.uuid as nt_id,  COLLECT(DISTINCT st.uuid) as st_ids, COLLECT(DISTINCT sta.value) as store_names,
        COLLECT(DISTINCT properties(br)) as notification_brands, COLLECT(DISTINCT properties(nt)) as notification, 
        COLLECT(DISTINCT properties(ntt)) as notification_type, COLLECT(DISTINCT properties(ntta)) as notification_action_type

И теперь время отклика меньше 500 мс. Спасибо за подробное объяснение! Ура!

...