Производительность cypher с множественными отношениями

Мне поручено создать прототип Neo4J в качестве замены нашей существующей витрины данных, которая хранит данные в схемах Redshift / Postgres. Я загрузил экземпляр neo, работающий на экземпляре EC2 на сервере m5.xlarge, чтобы смоделировать маркетинговую кампанию и попытаться получить простые подсчеты того, кто видел мои места в данной демографической группе. Результаты в том, что касается полученных цифр, точно такие же, как у моей существующей витрины данных, но я удивлен, увидев, что производительность намного ниже. Тот же запрос, чтобы получить простой подсчет показов по телевизионной сети, возвращается через 48 секунд по сравнению с 1,5 секундами в Redshift. Вопрос в том, что я делаю что-то не так в моем шифровании (т.е. слишком много соединений) или это ожидаемое поведение. Вот схема модели:

Campaign Relationship Model

Вот мой Cypher для получения результатов за 48 секунд:

match (c:Campaign{campaign_id:98})<-[:PART_OF]-(sa)
    , (sa)-[:AIRED_ON]->(n)
    , (n)-[:BELONGS_TO]->(ng:NetworkGroup{network_group_id:2})
    , (sa)<-[:EXPOSED_WITH]-(e)
    , (e)<-[se:CONTAINS_ENTITY]-(s:Sample{sample_id:2000005})
    , (e)-[:MEMBER_OF]->(a:DemographicAudience{audience_id:2})
return c.campaign_id as `campaign_id`
    , a.audience_id as `audience_id`
    , a.audience_name as `audience_name`
    , s.sample_id as `sample_id`
    , n.network_id as `network_id`
    , n.network_name as `network_name`
    , n.network_call_sign as `network_call_sign`
    , count(distinct sa.spot_airing_id) as `spot_airings`
    , sum(se.weight) as `spot_impressions`

Кроме того, я считаю, что для оптимизации добавлены все необходимые ограничения:

Indexes
   ON :DemographicAudience(audience_id) ONLINE  (for uniqueness constraint)
   ON :Campaign(campaign_id) ONLINE  (for uniqueness constraint)
   ON :Entity(entity_id) ONLINE  (for uniqueness constraint)
   ON :Network(network_id) ONLINE  (for uniqueness constraint)
   ON :NetworkGroup(network_group_id) ONLINE  (for uniqueness constraint)
   ON :Sample(sample_id) ONLINE  (for uniqueness constraint)
   ON :SpotAiring(spot_airing_id) ONLINE  (for uniqueness constraint)

Constraints
   ON ( audience:DemographicAudience ) ASSERT audience.audience_id IS UNIQUE
   ON ( campaign:Campaign ) ASSERT campaign.campaign_id IS UNIQUE
   ON ( entity:Entity ) ASSERT entity.entity_id IS UNIQUE
   ON ( network:Network ) ASSERT network.network_id IS UNIQUE
   ON ( networkgroup:NetworkGroup ) ASSERT networkgroup.network_group_id IS UNIQUE
   ON ( sample:Sample ) ASSERT sample.sample_id IS UNIQUE
   ON ( spotairing:SpotAiring ) ASSERT spotairing.spot_airing_id IS UNIQUE

Запуск сообщества Neo4J 3.3.1 на AWS: https://aws.amazon.com/marketplace/pp/B073S5MDPV/?ref_=_ptnr_intuz_ami_neoj4

Я также должен упомянуть, что загружено довольно много данных: 24 154 440 узлов и 33 220 694 отношения. Большинство из них связаны с сущностями.

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

Спасибо.

Можете ли вы ПРОФИЛИРОВАТЬ свой запрос и прикрепить план запроса (со всеми развернутыми элементами) к вашему вопросу?

InverseFalcon 11.08.2018 03:52
1
1
93
1

Ответы 1

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

В этом случае у нас есть несколько уникальных узлов, поэтому мы можем сэкономить на некоторых операциях, убедившись, что мы сначала сопоставляем все эти узлы, и мы должны увидеть Expand(Into) в нашем плане запроса вместо Expand(All), а затем Filter. У меня есть подозрение, что планировщик использует поиск по индексу только для одного узла, а остальные не используют индекс, а используют доступ к свойствам и фильтрацию, что менее эффективно.

В случае, если планировщик не просматривает сначала все ваши уникальные узлы, перед расширением, мы можем принудительно ввести LIMIT 1 после начального совпадения.

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

Попробуйте и посмотрите, как он сравнивается:

MATCH (c:Campaign{campaign_id:98}), (s:Sample{sample_id:2000005}), (a:DemographicAudience{audience_id:2}), (ng:NetworkGroup{network_group_id:2})
WITH c,s,a,ng 
LIMIT 1
MATCH (c)<-[:PART_OF]-(sa)
    , (sa)-[:AIRED_ON]->(n)
    , (n)-[:BELONGS_TO]->(ng)
    , (sa)<-[:EXPOSED_WITH]-(e)
    , (e)<-[se:CONTAINS_ENTITY]-(s)
    , (e)-[:MEMBER_OF]->(a)
WITH c, a, s, n, count(distinct sa) as `spot_airings`, sum(se.weight) as `spot_impressions`
RETURN c.campaign_id as `campaign_id`
    , a.audience_id as `audience_id`
    , a.audience_name as `audience_name`
    , s.sample_id as `sample_id`
    , n.network_id as `network_id`
    , n.network_name as `network_name`
    , n.network_call_sign as `network_call_sign`
    , `spot_airings`
    , `spot_impressions`

Другие вопросы по теме