Neo4j 3.0.6 Ограничение уникальности нарушается с помощью MERGE

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

CREATE CONSTRAINT ON (n:Person) ASSERT n.id IS UNIQUE

Затем я буду импортировать данные и отношения из нескольких источников и нескольких потоков:

MERGE (mother:Person{id: 22})
MERGE (father:Person{id: 55})
MERGE (self:Person{id: 128})
SET self += {name: "Alan"}
MERGE (self)-[:MOTHER]->(mother)
MERGE (self)-[:FATHER]->(father)

Между тем, в другом потоке, но все еще на том же сервере Neo4j и конечной точке болта, я буду импортировать остальные данные:

MERGE (husband:Person{id: 55})
MERGE (self:Person{id: 22})
SET self += {name: "Phyllis"}
MERGE (self)-[:HUSBAND]->(husband)
MERGE (wife:Person{id: 22})
MERGE (self:Person{id: 55})
SET self += {name: "Angel"}
MERGE (self)-[:WIFE]->(wife)
MERGE (brother:Person{id: 128})
MERGE (self:Person{id: 92})
SET self += {name: "Brian"}
MERGE (self)-[:BROTHER]->(brother)
MERGE (self)<-[:BROTHER]-(brother)

Наконец, если я снова запущу команду ограничения, я получу следующее:

Unable to create CONSTRAINT ON ( Person:Person ) ASSERT Person.id IS UNIQUE:
Multiple nodes with label `Person` have property `id` = 55:
  node(708823)
  node(708827)

Нет никакой гарантии, в каком порядке будут обрабатываться записи. В результате создается несколько записей для одного и того же (:Person{id}), но только одна заполняется данными name.

Похоже, в Neo4j есть условие гонки, когда два MERGE происходят для одного и того же идентификатора одновременно, они оба будут созданы. Есть ли способ избежать этого состояния гонки? Есть ли способ установить необходимые блокировки?

Возможный дубликат: Neo4J 2.1 .3 Нарушено ограничение уникальности. Является ли это ошибкой? Но это для CREATE и этот ответ группы Google указывает, что CREATE ведет себя иначе, чем MERGE в отношении ограничений.


person wizulus    schedule 17.11.2016    source источник
comment
Удалил мой ответ, так как он больше не относится к вашему обновленному описанию. Я отправлю еще один ответ, если смогу придумать лучшее решение.   -  person InverseFalcon    schedule 17.11.2016
comment
Спасибо InverseFalcon. Мне жаль, что мой ошибочный синтаксис побудил вас написать такой полный и полезный ответ, который только я мог увидеть. Я дал вам дополнительную репутацию, чтобы, надеюсь, компенсировать это :)   -  person wizulus    schedule 17.11.2016
comment
Просто из любопытства, что произойдет, если вы измените свой SET как на ON CREATE SET..., так и на ON MERGE SET... У вас все еще будут дубликаты узлов?   -  person InverseFalcon    schedule 17.11.2016
comment
Не могли бы вы привести пример того, как это будет выглядеть, учитывая любой из моих примеров?   -  person wizulus    schedule 17.11.2016
comment
Ах, я вижу ... обновляю свой код, чтобы попробовать это   -  person wizulus    schedule 17.11.2016
comment
Имейте в виду, что я не слишком уверен в этом как в решении, просто хотел подтвердить, что это также приводит к дублированию узлов.   -  person InverseFalcon    schedule 17.11.2016
comment
Это приводит к дубликату.   -  person wizulus    schedule 17.11.2016
comment
Могли ли дубликаты быть созданы до того, как вы установили ограничение уникальности?   -  person cybersam    schedule 17.11.2016
comment
@cybersam Нет, потому что если вы попытаетесь создать ограничение, вы получите сообщение об ошибке Невозможно создать ОГРАНИЧЕНИЕ...   -  person wizulus    schedule 18.11.2016
comment
ХОРОШО. Могли ли дубликаты быть созданы предыдущей версией вашего кода Cypher? Например, если вы раньше использовали CREATE вместо MERGE?   -  person cybersam    schedule 18.11.2016
comment
Вам необходимо создать ограничение и убедиться, что оно находится в сети, прежде чем вы начнете выполнять операторы MERGE. Вы можете убедиться, что ограничение подключено к сети, запустив :schema в браузере или CALL db.constraints. Если ограничение не было создано и находится в сети, уникальность не гарантируется.   -  person William Lyon    schedule 18.11.2016


Ответы (1)


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

В целом, я думаю, что лучшим подходом было бы отказаться от обработки данных одного типа в нескольких потоках и просто выполнить один импорт в одном потоке для MERGE :Persons и установить их свойства.

После того, как это будет импортировано, вы можете обработать создание своих отношений с пониманием того, что вы будете СООТВЕТСТВОВАТЬ, а не ОБЪЕДИНЯТЬ на :Persons.

person InverseFalcon    schedule 17.11.2016