Продвигая наш новый курс по графовой аналитике больших данных в бизнес-приложениях, сегодня разберем особенности работы оператора MERGE во встроенном SQL-подобном языке запросов Cypher популярной NoSQL-СУБД Neo4j. Чем он отличается от запросов CREATE и MATCH, а также когда этот оператор более всего полезен.
Как работает MERGE-запрос в Neo4j
Data Scientist’ы и аналитики данных знают, что Neo4j – это чрезвычайно мощная графовая СУБД. Она не просто предоставляет абстракцию графа как слоя, выполняя таблиц соединения в фоновом режиме, а по своей сути поддерживает базу данных на основе графа. Она включает SQL-подобный язык запросов Cypher, который содержит множество полезных операторов. Одним из них является слияние (MERGE), которое проверяет, существует ли шаблон в базе данных. Если его нет, он создает шаблон.
MERGE сопоставляет существующие узлы и связывает их, либо создает новые данные и тоже связывает их. Это похоже на комбинацию запросов MATCH и CREATE, которая дополнительно позволяет указать, что произойдет, если данные будут сопоставлены или созданы. Например, можно указать, что граф должен содержать узел для пользователя с определенным именем. Если в графе нет узла с таким именем, будет создан новый узел и задано его свойство имени. По соображениям производительности при использовании слияния настоятельно рекомендуется создать индекс схемы для метки или свойства. Для полных шаблонов MERGE работает по принципу транзакции: либо полностью, либо никак, проверяя весь шаблон целиком, а не его отдельные части. MERGE не использует частично существующие шаблоны. Поэтому если нужно обработать частичные совпадения, следует делить шаблон на несколько слияний.
Важно, что при одновременных обновлениях MERGE гарантирует только существование шаблона, но не его уникальность. Чтобы гарантировать уникальность узлов с определенными свойствами, следует использовать ограничение уникальности. Cypher предотвращает получение противоречивых результатов от слияния при использовании шаблонов, включающих уникальные ограничения. В этом случае должен быть не более одного узла, соответствующего этому шаблону.
Как и в случае с MATCH, MERGE может сопоставлять несколько вхождений шаблона. Если есть несколько совпадений, все они будут переданы на более поздние этапы запроса. Последняя часть слияния — это ON CREATE и ON MATCH. Они позволяют запросу выражать дополнительные изменения свойств узла или отношения в зависимости от того, был ли элемент сопоставлен (MATCH) в базе данных или он был создан (CREATE). MERGE не поддерживает параметры сопоставления так, как это делает CREATE. Чтобы использовать параметры сопоставления со слиянием, необходимо явно использовать ожидаемые свойства.
Таким образом, оператор MERGE является идемпотентным, т.е. его повторный запуск с одними и теми же данными всегда дает один и тот же результат, в отличие от предложения CREATE, которое будет создавать узел столько раз, сколько раз его вызывали. Поэтому хорошей практикой сопоставления шаблонов является слияние сначала для узлов, а затем для отношений. Это помогает, когда нужно создать отношение между двумя узлами, которые могут отсутствовать. Также этот прием очень удобен при получении данных из внешнего источника.
К примеру, можно запустить MERGE даже на пустой базе Neo4j:
MERGE (n:Shool{name:"BigDataSchool"}) return n
В этом запросе Neo4j не смогла найти требуемый шаблон (узел n с меткой School, именем свойства и значением BigDataSchool), и создала этот узел. Важно, что MERGE на шаблоне одного узла может создавать дубликаты, если нет уникального ограничения. При выполнении MERGE для шаблона с одним узлом, когда узел еще не существует, и нет уникального ограничения, блокировать нечего, чтобы избежать условий гонки. Поэтому одновременные транзакции могут привести к дублированию узлов.
Когда слияние не может найти существующий шаблон, он блокирует все связанные узлы и отношения в шаблоне, прежде чем создавать отсутствующие элементы шаблона. Это делается для того, чтобы MERGE или CREATE не могли одновременно создать шаблон или изменить свойства существующего, чтобы сделать его идентичным желаемому шаблону во время выполнения MERGE, что ведет к дублированию. После блокировки связанных элементов MERGE выполняет еще один MATCH для шаблона, чтобы избежать условий гонки, когда шаблон может быть создан в промежутке времени между моментом, когда MERGE определил, что шаблон не существует, и моментом, когда были получены блокировки для Neo4j младше 3.0.9 для версий 3.0.x и младше 3.1.2 для версий 3.1.x была ошибка в планировщике затрат. Она препятствовала блокировке с двойной проверкой при слиянии. Это допускало условия гонки, которые могли привести к созданию повторяющихся шаблонов параллельными операциями MERGE или другой операцией записи, которая приводила к существованию ранее несуществующего шаблона.
О том, как использовать вместо Cypher-запросов язык Python, читайте в нашей новой статье.
Освойте администрирование и эксплуатацию Neo4j и Apache Spark для графовой аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники