功能#
Cypher 变更日志格式#
[所需插件版本 : 4.9.0.1]
该扩展支持多格式变更日志(XML、SQL、YAML 等)。SQL 格式已别名为更惯用的 Cypher 格式。
Cypher 文件名必须以 .cypher
结尾。Cypher 变更日志必须以注释 --liquibase formatted cypher
开头。以下是一个支持的 Cypher 文件示例
-- liquibase formatted cypher
-- changeset fbiville:my-movie-init
CREATE (:Movie {title: 'My Life', genre: 'Comedy'});
作为文件夹包含一部分的 Cypher 文件必须仅包含一个 Cypher 查询,并且没有注释指令。
Cypher 和回滚变更#
[所需插件版本 (Cypher 别名) : 4.7.1.1]
支持内置的SQL和回滚变更。SQL 变更也别名为 cypher
。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
</changeSet>
<changeSet id="translate" author="fbiville">
<neo4j:cypher>MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comédie'</neo4j:cypher>
<rollback>MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comedy'</rollback>
</changeSet>
</databaseChangeLog>
警告
cypher
XML 标签需要在其前面加上相应的扩展命名空间前缀。- 如果查询包含 XML 特殊字符,例如
<
或>
,请确保在查询内容开头使用<![CDATA[
,在结尾使用]]>
将其包围。
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
}
]
}
},
{
"changeSet": {
"id": "translate",
"author": "fbiville",
"changes": [
{
"cypher": "MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comédie'"
}
],
"rollback": [
{
"cypher": "MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comedy'"
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- changeSet:
id: translate
author: fbiville
changes:
- cypher: 'MATCH (m:Movie {title: ''My Life''}) SET m.genre = ''Comédie'''
rollback:
- cypher: 'MATCH (m:Movie {title: ''My Life''}) SET m.genre = ''Comedy'''
-- liquibase formatted cypher
-- changeset fbiville:my-movie-init
CREATE (:Movie {title: 'My Life', genre: 'Comedy'});
-- changeset fbiville:translate
MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comédie'
-- rollback MATCH (m:Movie {title: 'My Life'}) SET m.genre = 'Comedy'
Neo4j 前置条件#
在Liquibase 文档中了解有关前置条件的更多信息,特别是故障和错误处理部分。
内置前置条件支持#
自插件发布以来,该扩展已成功测试并支持以下内置前置条件
dbms
(目标为Neo4j
)sqlCheck
(别名为cypherCheck
,见下文)
其他前置条件可能也有效,但尚未经过测试。
版本检查#
[所需插件版本 : 4.9.0]
version
前置条件断言运行时 Neo4j 版本以指定的字符串开头。它可以与标准布尔运算符结合其他前置条件使用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-neo4j-44-deployment" author="fbiville">
<preConditions onFail="CONTINUE">
<neo4j:version matches="4.4"/>
</preConditions>
<neo4j:cypher>CREATE (:Neo4j {neo4j44: true})</neo4j:cypher>
</changeSet>
<changeSet id="my-neo4j-non44-deployment" author="fbiville">
<preConditions onFail="CONTINUE">
<not>
<neo4j:version matches="4.4"/>
</not>
</preConditions>
<neo4j:cypher>CREATE (:Neo4j {neo4j44: false})</neo4j:cypher>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-neo4j-44-deployment",
"author": "fbiville",
"preConditions": [
{
"onFail": "CONTINUE"
},
{
"version": {
"matches": "4.4"
}
}
],
"changes": [
{
"cypher": "CREATE (:Neo4j {neo4j44: true})"
}
]
}
},
{
"changeSet": {
"id": "my-neo4j-non44-deployment",
"author": "fbiville",
"preConditions": [
{
"onFail": "CONTINUE"
},
{
"not": {
"version": {
"matches": "4.4"
}
}
}
],
"changes": [
{
"cypher": "CREATE (:Neo4j {neo4j44: false})"
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-neo4j-44-deployment
author: fbiville
preConditions:
- onFail: 'CONTINUE'
- version:
matches: '4.4'
changes:
- cypher: 'CREATE (:Neo4j {neo4j44: true})'
- changeSet:
id: my-neo4j-non44-deployment
author: fbiville
preConditions:
- onFail: 'CONTINUE'
- not:
- version:
matches: '4.4'
changes:
- cypher: 'CREATE (:Neo4j {neo4j44: false})'
版本(Edition)检查#
[所需插件版本 : 4.9.0]
edition
检查断言目标 Neo4j 部署是社区版 (Community Edition) 还是企业版 (Enterprise Edition)。它可以与标准布尔运算符结合其他前置条件使用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-neo4j-ee-deployment" author="fbiville">
<preConditions onFail="CONTINUE">
<neo4j:edition enterprise="true"/>
</preConditions>
<neo4j:cypher>CREATE (:Neo4j {enterprise: true})</neo4j:cypher>
</changeSet>
<changeSet id="my-neo4j-ce-deployment" author="fbiville">
<preConditions onFail="CONTINUE">
<neo4j:edition enterprise="false"/>
</preConditions>
<neo4j:cypher>CREATE (:Neo4j {enterprise: false})</neo4j:cypher>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-neo4j-ee-deployment",
"author": "fbiville",
"preConditions": [
{
"onFail": "CONTINUE"
},
{
"edition": {
"enterprise": true
}
}
],
"changes": [
{
"cypher": "CREATE (:Neo4j {enterprise: true})"
}
]
}
},
{
"changeSet": {
"id": "my-neo4j-ce-deployment",
"author": "fbiville",
"preConditions": [
{
"onFail": "CONTINUE"
},
{
"edition": {
"enterprise": false
}
}
],
"changes": [
{
"cypher": "CREATE (:Neo4j {enterprise: false})"
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-neo4j-ee-deployment
author: fbiville
preConditions:
- edition:
enterprise: true
- onFail: 'CONTINUE'
changes:
- cypher: 'CREATE (:Neo4j {enterprise: true})'
- changeSet:
id: my-neo4j-ce-deployment
author: fbiville
preConditions:
- edition:
enterprise: false
- onFail: 'CONTINUE'
changes:
- cypher: 'CREATE (:Neo4j {enterprise: false})'
Cypher 检查别名#
[所需插件版本 : 4.9.0]
cypherCheck
是现有sqlCheck
前置条件的别名。目前,Cypher 格式的变更日志文件只能使用 sqlCheck
。cypherCheck
可以与标准布尔运算符结合其他前置条件使用。
警告
在 4.21.1.2 版本之前,JSON 和 YAML 变更日志必须指定 sql
属性而不是 cypher
。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-neo4j-deployment" author="fbiville">
<preConditions onFail="CONTINUE">
<neo4j:cypherCheck expectedResult="0">MATCH (n:Neo4j) RETURN count(n)</neo4j:cypherCheck>
</preConditions>
<neo4j:cypher>CREATE (:Neo4j)</neo4j:cypher>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-neo4j-deployment",
"author": "fbiville",
"preConditions": [
{
"onFail": "CONTINUE"
},
{
"cypherCheck": {
"expectedResult": "0",
"cypher": "MATCH (n:Neo4j) RETURN count(n)"
}
}
],
"changes": [
{
"cypher": {
"cypher": "CREATE (:Neo4j)"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-neo4j-deployment
author: fbiville
preConditions:
- onFail: 'CONTINUE'
- cypherCheck:
expectedResult: '0'
cypher: MATCH (n:Neo4j) RETURN count(n)
changes:
- cypher:
cypher: CREATE (:Neo4j)
插入变更#
[所需插件版本 : 4.21.1]
此变更允许定义创建单个节点,使用 labelName
指定单个标签。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet id="insert-node" author="fbiville">
<neo4j:insert labelName="Person">
<column name="id" value="8987212b-a6ff-48a1-901f-8c4b39bd6d9e" type="uuid"/>
<column name="age" valueNumeric="30" type="integer"/>
<column name="first_name" value="Florent"/>
<column name="last_name" value="Biville"/>
<column name="local_date" valueDate="2022-12-25" type="date"/>
<column name="local_time" valueDate="22:23:24" type="date"/>
<column name="local_date_time" valueDate="2018-02-01T12:13:14" type="date"/>
<column name="zoned_date_time" valueDate="2020-07-12T22:23:24+02:00" type="date"/>
<column name="polite" valueBoolean="true" type="boolean"/>
<column name="picture" value="DLxmEfVUC9CAmjiNyVphWw==" type="blob"/>
<column name="bio"
value="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nisi tellus, elementum id mi vitae, faucibus lacinia purus. Integer nec velit sit amet velit tincidunt ultrices eu eu massa. Vestibulum in libero vel neque interdum blandit in non libero. Aenean iaculis, erat ac molestie laoreet, risus ex faucibus odio, a fermentum turpis elit eget ex. Donec volutpat bibendum enim pretium pulvinar. Proin rutrum neque dui, a suscipit tellus semper suscipit. Praesent lobortis ut lorem vitae volutpat. Pellentesque a lorem eu lacus faucibus facilisis nec sed metus. Aenean lacinia luctus ultricies. Pellentesque cursus justo non iaculis tristique. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Duis tempor nisi ut turpis bibendum facilisis. Donec aliquet porttitor lacus, non rhoncus lectus laoreet et."
type="clob"/>
</neo4j:insert>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "insert-node",
"author": "fbiville",
"changes": [
{
"insert": {
"columns": [
{
"column": {
"name": "id",
"type": "uuid",
"value": "8987212b-a6ff-48a1-901f-8c4b39bd6d9e"
}
},
{
"column": {
"name": "age",
"type": "integer",
"valueNumeric": 30
}
},
{
"column": {
"name": "first_name",
"value": "Florent"
}
},
{
"column": {
"name": "last_name",
"value": "Biville"
}
},
{
"column": {
"name": "local_date",
"type": "date",
"valueDate": "2022-12-25"
}
},
{
"column": {
"name": "local_time",
"type": "date",
"valueDate": "22:23:24"
}
},
{
"column": {
"name": "local_date_time",
"type": "date",
"valueDate": "2018-02-01T12:13:14"
}
},
{
"column": {
"name": "zoned_date_time",
"type": "date",
"valueDate": "2020-07-12T22:23:24+02:00"
}
},
{
"column": {
"name": "polite",
"type": "boolean",
"valueBoolean": true
}
},
{
"column": {
"name": "picture",
"type": "blob",
"value": "DLxmEfVUC9CAmjiNyVphWw=="
}
},
{
"column": {
"name": "bio",
"type": "clob",
"value": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean nisi tellus, elementum id mi vitae, faucibus lacinia purus. Integer nec velit sit amet velit tincidunt ultrices eu eu massa. Vestibulum in libero vel neque interdum blandit in non libero. Aenean iaculis, erat ac molestie laoreet, risus ex faucibus odio, a fermentum turpis elit eget ex. Donec volutpat bibendum enim pretium pulvinar. Proin rutrum neque dui, a suscipit tellus semper suscipit. Praesent lobortis ut lorem vitae volutpat. Pellentesque a lorem eu lacus faucibus facilisis nec sed metus. Aenean lacinia luctus ultricies. Pellentesque cursus justo non iaculis tristique. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Duis tempor nisi ut turpis bibendum facilisis. Donec aliquet porttitor lacus, non rhoncus lectus laoreet et."
}
}
],
"labelName": "Person"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: insert-node
author: fbiville
changes:
- insert:
columns:
- column:
name: id
type: uuid
value: 8987212b-a6ff-48a1-901f-8c4b39bd6d9e
- column:
name: age
type: integer
valueNumeric: !!float '30'
- column:
name: first_name
value: Florent
- column:
name: last_name
value: Biville
- column:
name: local_date
type: date
valueDate: '2022-12-25'
- column:
name: local_time
type: date
valueDate: '22:23:24'
- column:
name: local_date_time
type: date
valueDate: '2018-02-01T12:13:14'
- column:
name: zoned_date_time
type: date
valueDate: '2020-07-12T22:23:24+02:00'
- column:
name: polite
type: boolean
valueBoolean: true
- column:
name: picture
type: blob
value: DLxmEfVUC9CAmjiNyVphWw==
- column:
name: bio
type: clob
value: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean
nisi tellus, elementum id mi vitae, faucibus lacinia purus. Integer
nec velit sit amet velit tincidunt ultrices eu eu massa. Vestibulum
in libero vel neque interdum blandit in non libero. Aenean iaculis,
erat ac molestie laoreet, risus ex faucibus odio, a fermentum turpis
elit eget ex. Donec volutpat bibendum enim pretium pulvinar. Proin rutrum
neque dui, a suscipit tellus semper suscipit. Praesent lobortis ut lorem
vitae volutpat. Pellentesque a lorem eu lacus faucibus facilisis nec
sed metus. Aenean lacinia luctus ultricies. Pellentesque cursus justo
non iaculis tristique. Vestibulum ante ipsum primis in faucibus orci
luctus et ultrices posuere cubilia curae; Duis tempor nisi ut turpis
bibendum facilisis. Donec aliquet porttitor lacus, non rhoncus lectus
laoreet et.
labelName: Person
有关每列支持的值类型,请参阅加载数据文档。
加载数据#
[所需 Liquibase 核心版本 : 4.11.0] [所需插件版本 : 4.16.1.1]
假设有以下 (S)CSV data.scsv
文件
name;age;some_date;ignored;uuid;is_polite;blob
Florent;30.5;2022-12-25;ignored;8d1208fc-f401-496c-9cb8-483fef121234;false;DLxmEfVUC9CAmjiNyVphWw==
Andrea;32;2020-07-12T22:23:24+02:00;ignored!;1bc59ddb-8d4d-41d0-9c9a-34e837de5678;true;NULL
Nathan;34;2018-02-01T12:13:14;ignored!;123e4567-e89b-12d3-a456-426614174000;true;NULL
Robert;36;22:23:24;ignored!;9986a49a-0cce-4982-b491-b8177fd0ef81;true;NULL
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="customer-import" author="asanturbano">
<loadData
file="e2e/load-data/data.scsv"
separator=";"
tableName="CsvPerson">
<column name="first_name" header="name" type="string"/>
<column name="wisdom_index" header="age" type="numeric"/>
<column name="some_date" index="2" type="date"/>
<column name="_" header="ignored" type="skip"/>
<column name="uuid" header="uuid" type="uuid"/>
<column name="polite" header="is_polite" type="boolean"/>
<column name="picture" header="blob" type="blob"/>
</loadData>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "customer-import",
"author": "asanturbano",
"changes": [
{
"loadData": {
"columns": [
{
"column": {
"header": "name",
"name": "first_name",
"type": "string"
}
},
{
"column": {
"header": "age",
"name": "wisdom_index",
"type": "numeric"
}
},
{
"column": {
"index": 2,
"name": "some_date",
"type": "date"
}
},
{
"column": {
"header": "ignored",
"name": "_",
"type": "skip"
}
},
{
"column": {
"header": "uuid",
"name": "uuid",
"type": "uuid"
}
},
{
"column": {
"header": "is_polite",
"name": "polite",
"type": "boolean"
}
},
{
"column": {
"header": "blob",
"name": "picture",
"type": "blob"
}
}
],
"file": "e2e/load-data/data.scsv",
"separator": ";",
"tableName": "CsvPerson"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: customer-import
author: asanturbano
changes:
- loadData:
columns:
- column:
header: name
name: first_name
type: string
- column:
header: age
name: wisdom_index
type: numeric
- column:
index: 2
name: some_date
type: date
- column:
header: ignored
name: _
type: skip
- column:
header: uuid
name: uuid
type: uuid
- column:
header: is_polite
name: polite
type: boolean
- column:
header: blob
name: picture
type: blob
file: e2e/load-data/data.scsv
separator: ;
tableName: CsvPerson
此变更的通用文档可在此处查看。
下表详细说明了每种支持的数据类型如何映射到其对应的 Neo4j 类型
加载数据类型 | Liquibase Java 类型 | 示例值 | 结果 Neo4j Java 类型 |
---|---|---|---|
BLOB |
String |
DLxmEfVUC9CAmjiNyVphWw== (base64 编码) |
byte[] |
BOOLEAN |
Boolean |
true 或 false |
Boolean |
CLOB |
String |
String |
|
DATE |
java.sql.Timestamp |
2018-02-01T12:13:14 |
java.time.LocalDateTime |
DATE |
java.sql.Date |
2018-02-01 |
java.time.LocalDate |
DATE |
java.sql.Time |
12:13:14 |
java.time.LocalTime |
DATE |
liquibase.statement.DatabaseFunction |
2018-02-01T12:13:14+02:00 |
java.time.ZonedDateTime |
NUMERIC |
liquibase.change.ColumnConfig.ValueNumeric |
42 或 42.0 |
Long 或 Double |
STRING |
String |
"a string" |
String |
UUID |
String |
1bc59ddb-8d4d-41d0-9c9a-34e837de5678 |
String |
还支持 SKIP
:该值将被忽略。
请确保使用正确的 valueXxx
属性
valueBoolean
用于布尔值valueDate
用于日期/时间值valueNumeric
用于数值value
用于其他所有类型
图重构#
节点合并#
[所需插件版本 : 4.13.0]
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Horror'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Documentary'})</neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:mergeNodes fragment="(m:Movie {title: 'My Life'}) WITH m ORDER BY m.genre ASC" outputVariable="m">
<neo4j:propertyPolicy nameMatcher=".*" mergeStrategy="KEEP_FIRST"/>
</neo4j:mergeNodes>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Horror'})"
},
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Documentary'})"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"mergeNodes": {
"fragment": "(m:Movie {title: 'My Life'}) WITH m ORDER BY m.genre ASC",
"outputVariable": "m",
"propertyPolicies": [
{
"propertyPolicy": {
"mergeStrategy": "KEEP_FIRST",
"nameMatcher": ".*"
}
}
]
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Horror''})'
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Documentary''})'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- mergeNodes:
fragment: '(m:Movie {title: ''My Life''}) WITH m ORDER BY m.genre ASC'
outputVariable: m
propertyPolicies:
- propertyPolicy:
mergeStrategy: 'KEEP_FIRST'
nameMatcher: .*
指定一个 Cypher 查询片段,该片段定义用于合并操作的匹配节点。如果匹配的节点少于两个,则合并操作不执行任何操作。
指定该片段中引用匹配节点的变量。这将重新用于创建要执行的内部合并 Cypher 查询。
最后,请确保为每个持久化属性定义合并策略。扩展将遍历每个唯一的属性名称,按声明顺序选择第一个匹配的合并策略。如果至少一个属性名称不匹配策略,则合并失败并取消。一旦属性名称的策略匹配,将发生以下操作之一
KEEP_FIRST
:保留该名称的第一个定义的属性值KEEP_LAST
:保留该名称的最后一个定义的属性值KEEP_ALL
:将所有定义的属性值聚合成一个数组(即使只找到一个值)
注意
“第一个”和“最后一个”由指定的 Cypher 查询片段的排序定义。强烈建议使用 ORDER BY
子句明确地对匹配的节点进行排序,如示例所示。
节点属性提取#
[所需插件版本 : 4.17.2]
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Movie {title: 'My Project', genre: 'Comedy'})</neo4j:cypher>
</changeSet>
<changeSet id="genre-extraction" author="marouane">
<neo4j:extractProperty property="genre" fromNodes="(m:Movie) WITH m ORDER BY id(m) ASC" nodesNamed="m">
<neo4j:toNodes withLabel="Genre" withProperty="genre">
<neo4j:linkedFromSource withType="HAS_GENRE" withDirection="OUTGOING" />
</neo4j:toNodes>
</neo4j:extractProperty>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Movie {title: 'My Project', genre: 'Comedy'})"
}
]
}
},
{
"changeSet": {
"id": "genre-extraction",
"author": "marouane",
"changes": [
{
"extractProperty": {
"fromNodes": "(m:Movie) WITH m ORDER BY id(m) ASC",
"nodesNamed": "m",
"property": "genre",
"toNodes": {
"withLabel": "Genre",
"withProperty": "genre",
"linkedFromSource": {
"withDirection": "OUTGOING",
"withType": "HAS_GENRE"
}
}
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Movie {title: ''My Project'', genre: ''Comedy''})'
- changeSet:
id: genre-extraction
author: marouane
changes:
- extractProperty:
fromNodes: '(m:Movie) WITH m ORDER BY id(m) ASC'
nodesNamed: 'm'
property: 'genre'
toNodes:
withLabel: 'Genre'
withProperty: 'genre'
linkedFromSource:
withDirection: 'OUTGOING'
withType: 'HAS_GENRE'
节点属性提取重构允许将节点属性提取到其自己的节点中。与节点合并重构类似,要提取属性的节点指定为 Cypher 片段(fromNodes
属性),并指定绑定到这些节点的变量名(nodesNamed
属性)。要提取的属性名使用 property
属性指定。
Cypher 片段匹配的源节点将移除其属性。该属性将设置到提取的节点上,名称由 withProperty
属性描述。提取节点的标签使用 withLabel
属性定义。将 merge
属性设置为 true
以避免与具有相同标签和属性的潜在现有节点重复。默认行为是每次都创建提取的节点。
可选地,提取的节点可以与源节点链接。在这种情况下,需要分别使用 withType
和 withDirection
属性指定类型和方向。
注意
关系方向是从源节点的角度来看的。在示例中,OUTGOING
表示关系从源节点开始并指向提取的节点。相反,INCOMING
表示关系从提取的节点进入源节点。
还可以通过设置相应的 merge
属性为 true
来避免关系重复。默认是总是创建关系。
警告
在节点上设置 merge=false
而在关系上设置 merge=true
将触发验证警告。事实上,创建提取的节点意味着也将创建新的关系。在这种情况下,在关系上设置 merge=true
会导致不必要的执行开销。
节点标签重命名#
[所需插件版本 : 4.25.0.1]
标签重命名重构允许将一个标签重命名为另一个标签,匹配其所有或部分节点,在单个事务或批量中执行。
如下图所示,重构的主要属性有
from
:现有标签的值to
:新标签的值,替换现有标签
全局重命名#
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Book {title: 'My Life', genre: 'Autobiography'})</neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameLabel from="Movie" to="Film" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Book {title: 'My Life', genre: 'Autobiography'})"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameLabel": {
"from": "Movie",
"to": "Film"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Book {title: ''My Life'', genre: ''Autobiography''})'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameLabel:
from: 'Movie'
to: 'Film'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Book {title: 'My Life', genre: 'Autobiography'})</neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameLabel from="Movie" to="Film" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Book {title: 'My Life', genre: 'Autobiography'})"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameLabel": {
"from": "Movie",
"to": "Film",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Book {title: ''My Life'', genre: ''Autobiography''})'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameLabel:
from: 'Movie'
to: 'Film'
enableBatchImport: true
batchSize: 1
部分重命名#
为了仅匹配 from
中指定的标签的节点子集,还可以设置以下属性
fragment
指定用于匹配节点的模式outputVariable
指定fragment
中定义的表示目标节点的 Cypher 变量名
注意
将要重命名的节点位于 fragment
中定义的与 from
指定的标签节点之间的交集处。换句话说,如果 fragment
中定义的节点都没有带有 from
中定义的标签,则重命名将不会修改任何这些节点。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Movie {title: 'My Birthday', genre: 'Musical'})</neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameLabel from="Movie" to="Film" fragment="(m:Movie {title: 'My Birthday'})" outputVariable="m" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Movie {title: 'My Birthday', genre: 'Musical'})"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameLabel": {
"from": "Movie",
"to": "Film",
"fragment": "(m:Movie {title: 'My Birthday'})",
"outputVariable": "m"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Movie {title: ''My Birthday'', genre: ''Musical''})'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameLabel:
from: 'Movie'
to: 'Film'
fragment: '(m:Movie {title: ''My Birthday''})'
outputVariable: 'm'
由于此操作可能影响大量节点,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher>CREATE (:Movie {title: 'My Life', genre: 'Comedy'})</neo4j:cypher>
<neo4j:cypher>CREATE (:Movie {title: 'My Birthday', genre: 'Musical'})</neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameLabel from="Movie" to="Film" fragment="(m:Movie {title: 'My Birthday'})" outputVariable="m" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {title: 'My Life', genre: 'Comedy'})"
},
{
"cypher": "CREATE (:Movie {title: 'My Birthday', genre: 'Musical'})"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameLabel": {
"from": "Movie",
"to": "Film",
"fragment": "(m:Movie {title: 'My Birthday'})",
"outputVariable": "m",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {title: ''My Life'', genre: ''Comedy''})'
- cypher: 'CREATE (:Movie {title: ''My Birthday'', genre: ''Musical''})'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameLabel:
from: 'Movie'
to: 'Film'
fragment: '(m:Movie {title: ''My Birthday''})'
outputVariable: 'm'
enableBatchImport: true
batchSize: 1
关系类型重命名#
[所需插件版本 : 4.25.0.1]
类型重命名重构允许将一个类型重命名为另一个类型,匹配其所有或部分关系,在单个事务或批量中执行。
如下图所示,重构的主要属性有
from
:现有类型的值to
:新类型的值,替换现有类型
全局重命名#
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameType from="SEEN_BY" to="VIEWED_BY" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameType": {
"from": "SEEN_BY",
"to": "VIEWED_BY"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''now''}]->(:Person)'
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameType:
from: 'SEEN_BY'
to: 'VIEWED_BY'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameType from="SEEN_BY" to="VIEWED_BY" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameType": {
"from": "SEEN_BY",
"to": "VIEWED_BY",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''now''}]->(:Person)'
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameType:
from: 'SEEN_BY'
to: 'VIEWED_BY'
enableBatchImport: true
batchSize: 1
部分重命名#
为了仅匹配 from
中指定的类型的关系子集,还可以设置以下属性
fragment
指定用于匹配关系的模式outputVariable
指定fragment
中定义的表示目标关系的 Cypher 变量名
注意
将要重命名的关系位于 fragment
中定义的与 from
指定的类型关系之间的交集处。换句话说,如果 fragment
中定义的关系都没有具有 from
中定义的类型,则重命名将不会修改任何这些关系。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameType from="SEEN_BY" to="VIEWED_BY" fragment="(:Person)<-[r:SEEN_BY]-()" outputVariable="r" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameType": {
"from": "SEEN_BY",
"to": "VIEWED_BY",
"fragment": "(:Person)<-[r:SEEN_BY]-()",
"outputVariable": "r"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''now''}]->(:Person)'
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameType:
from: 'SEEN_BY'
to: 'VIEWED_BY'
fragment: '(:Person)<-[r:SEEN_BY]-()'
outputVariable: 'r'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameType from="SEEN_BY" to="VIEWED_BY" fragment="(:Person)<-[r:SEEN_BY]-()" outputVariable="r" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'now'}]->(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:SEEN_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameType": {
"from": "SEEN_BY",
"to": "VIEWED_BY",
"fragment": "(:Person)<-[r:SEEN_BY]-()",
"outputVariable": "r",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''now''}]->(:Person)'
- cypher: 'CREATE (:Movie)-[:SEEN_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameType:
from: 'SEEN_BY'
to: 'VIEWED_BY'
fragment: '(:Person)<-[r:SEEN_BY]-()'
outputVariable: 'r'
enableBatchImport: true
batchSize: 1
关系方向反转#
[所需插件版本 : 4.25.1.1]
方向反转重构允许翻转指定类型关系的起始节点和结束节点,匹配所有或部分关系,在单个事务或批量中执行。
如下图所示,重构的主要属性有
type
:要反转的关系类型
全局反转#
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)<-[:VIEWED_BY {date: 'yesterday'}]-(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:invertDirection type="VIEWED_BY" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)"
},
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'yesterday'}]-(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"invertDirection": {
"type": "VIEWED_BY"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''now''}]-(:Person)'
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''yesterday''}]-(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- invertDirection:
type: 'VIEWED_BY'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)<-[:VIEWED_BY {date: 'yesterday'}]-(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:invertDirection type="VIEWED_BY" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)"
},
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'yesterday'}]-(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"invertDirection": {
"type": "VIEWED_BY",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''now''}]-(:Person)'
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''yesterday''}]-(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- invertDirection:
type: 'VIEWED_BY'
enableBatchImport: true
batchSize: 1
部分反转#
为了仅匹配 type
中指定的类型的关系子集,还可以设置以下属性
fragment
指定用于匹配关系的模式outputVariable
指定fragment
中定义的表示目标关系的 Cypher 变量名
注意
将要反转的关系位于 fragment
中定义的与 type
指定的类型关系之间的交集处。换句话说,如果 fragment
中定义的关系都没有具有 type
中定义的类型,则反转将不会修改任何这些关系。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:VIEWED_BY {date: 'now'}]->(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:VIEWED_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:invertDirection type="VIEWED_BY" fragment="(:Person)-[r:VIEWED_BY]->()" outputVariable="r" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:VIEWED_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"invertDirection": {
"type": "VIEWED_BY",
"fragment": "(:Person)-[r:VIEWED_BY]->()",
"outputVariable": "r"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''now''}]-(:Person)'
- cypher: 'CREATE (:Movie)-[:VIEWED_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- invertDirection:
type: 'VIEWED_BY'
fragment: '(:Person)-[r:VIEWED_BY]->()'
outputVariable: 'r'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)]]></neo4j:cypher>
<neo4j:cypher><![CDATA[CREATE (:Movie)-[:VIEWED_BY {date: 'yesterday'}]->(:Dog)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:invertDirection type="VIEWED_BY" fragment="(:Person)-[r:VIEWED_BY]->()" outputVariable="r" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie)<-[:VIEWED_BY {date: 'now'}]-(:Person)"
},
{
"cypher": "CREATE (:Movie)-[:VIEWED_BY {date: 'yesterday'}]->(:Dog)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"invertDirection": {
"type": "VIEWED_BY",
"fragment": "(:Person)-[r:VIEWED_BY]->()",
"outputVariable": "r",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie)<-[:VIEWED_BY {date: ''now''}]-(:Person)'
- cypher: 'CREATE (:Movie)-[:VIEWED_BY {date: ''yesterday''}]->(:Dog)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- invertDirection:
type: 'VIEWED_BY'
fragment: '(:Person)-[r:VIEWED_BY]->()'
outputVariable: 'r'
enableBatchImport: true
batchSize: 1
属性重命名#
[所需插件版本 : 4.25.1.1]
属性重命名重构允许重命名所有包含实体(或仅节点或关系)的属性。
如下图所示,重构的主要属性有
from
:现有属性的名称to
:属性的新名称,替换现有名称entityType
:要匹配的包含实体类型。之一为:ALL
(默认)、NODE
、RELATIONSHIP
。
全局重命名#
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameProperty from="calendar_date" to="date" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameProperty from="calendar_date" to="date" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
enableBatchImport: true
batchSize: 1
仅针对节点的属性重命名#
当设置 entityType
属性为 NODE
时,仅节点的匹配属性将被重命名
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameProperty from="calendar_date" to="date" entityType="NODE" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date",
"entityType": "NODE"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
entityType: 'NODE'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameProperty from="calendar_date" to="date" entityType="NODE" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date",
"entityType": "NODE",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
entityType: 'NODE'
enableBatchImport: true
batchSize: 1
仅针对关系的属性重命名#
当设置 entityType
属性为 RELATIONSHIP
时,仅关系的匹配属性将被重命名
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville">
<neo4j:renameProperty from="calendar_date" to="date" entityType="RELATIONSHIP" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date",
"entityType": "RELATIONSHIP"
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
entityType: 'RELATIONSHIP'
由于此操作可能影响大量数据,在单个事务中运行此变更可能不可行,因为事务可能运行得太慢,甚至会内存不足。
为了防止这种情况,必须将 enableBatchImport
设置为 true
。由于它底层依赖于 CALL {} IN TRANSACTIONS
,因此 enclosing change set 的 runInTransaction
也必须设置为 false
。这将导致变更以批量方式执行。
警告
此设置仅在目标 Neo4j 实例支持 CALL {} IN TRANSACTIONS
时有效(4.4 及更高版本)。如果不支持,Neo4j 插件将在单个自动提交事务中运行变更。
请务必阅读有关更改 runInTransaction
的后果。
batchSize
属性控制运行多少个事务。如果未设置该属性,则批量大小由 Neo4j 服务器端定义。
内部事务的错误策略,自 Neo4j 5.7 引入,可以使用 batchErrorPolicy
属性进行配置,接受以下值: - CONTINUE
- BREAK
- FAIL
自 Neo4j 5.21 以来,内部事务也可以配置为并行运行。布尔属性 concurrent
控制该行为。并发默认禁用。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:neo4j="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init-oops" author="fbiville">
<neo4j:cypher><![CDATA[CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)]]></neo4j:cypher>
</changeSet>
<changeSet id="my-movie-init-fixed" author="fbiville" runInTransaction="false">
<neo4j:renameProperty from="calendar_date" to="date" entityType="RELATIONSHIP" enableBatchImport="true" batchSize="1" />
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init-oops",
"author": "fbiville",
"changes": [
{
"cypher": "CREATE (:Movie {calendar_date: 'today'})-[:SEEN_BY {calendar_date: 'now'}]->(:Person)"
}
]
}
},
{
"changeSet": {
"id": "my-movie-init-fixed",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"renameProperty": {
"from": "calendar_date",
"to": "date",
"entityType": "RELATIONSHIP",
"enableBatchImport": true,
"batchSize": 1
}
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init-oops
author: fbiville
changes:
- cypher: 'CREATE (:Movie {calendar_date: ''today''})-[:SEEN_BY {calendar_date: ''now''}]->(:Person)'
- changeSet:
id: my-movie-init-fixed
author: fbiville
runInTransaction: false
changes:
- renameProperty:
from: 'calendar_date'
to: 'date'
entityType: 'RELATIONSHIP'
enableBatchImport: true
batchSize: 1
变更集的 runInTransaction
#
runInTransaction
的默认值为 true
。这意味着给定变更集的所有变更都在一个单独的显式事务中运行。
这是正确的默认值,仅当您需要以下两个 Cypher 构造之一时才应更改
- [自 Neo4j 4.4 起]
CALL {} IN TRANSACTIONS
- [直到 Neo4j 4.4]
PERIODIC COMMIT
事实上,在使用这些构造而未禁用 runInTransaction
时,会失败并出现类似错误消息
A query with 'CALL { ... } IN TRANSACTIONS' can only be executed in an implicit transaction, but tried to execute in an explicit transaction.
将变更集上的 runInTransaction
设置为 false
意味着其所有变更都将在各自的自动提交(或隐式)事务中运行。
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog https://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
<changeSet id="my-movie-init" author="fbiville" runInTransaction="false">
<sql>CALL { CREATE (:Movie {title: 'My Life', genre: 'Comedy'}) } IN TRANSACTIONS</sql>
</changeSet>
</databaseChangeLog>
{
"databaseChangeLog": [
{
"changeSet": {
"id": "my-movie-init",
"author": "fbiville",
"runInTransaction": false,
"changes": [
{
"cypher": "CALL { CREATE (:Movie {title: 'My Life', genre: 'Comedy'}) } IN TRANSACTIONS"
}
]
}
}
]
}
databaseChangeLog:
- changeSet:
id: my-movie-init
author: fbiville
runInTransaction: false
changes:
- cypher: 'CALL { CREATE (:Movie {title: ''My Life'', genre: ''Comedy''}) } IN TRANSACTIONS'
-- liquibase formatted sql
-- changeset fbiville:my-movie-init runInTransaction:false
CALL { CREATE (:Movie {title: 'My Life', genre: 'Comedy'}) } IN TRANSACTIONS
历史一致性#
runInTransaction
是一个锋利的工具,可能导致意想不到的后果。
如果 enclosing change set 的任何变更失败,则该变更集将不会存储在历史图中。
重新运行此变更集会导致所有变更再次运行,即使是之前已成功运行的变更。
在无法避免使用 runInTransactions="false"
的情况下,请确保受影响变更集的查询是幂等的。定义约束并使用 Cypher 的 MERGE
代替 CREATE
通常会有帮助。
Neo4j 隔离级别回顾#
CALL {} IN TRANSACTIONS
和 PERIODIC COMMIT
为每个批量启动一个新事务。由于Neo4j 的默认隔离级别是“读已提交”(read-committed),这些新事务可以读取由先前事务修改的数据,无论它们是来自同一语句还是完全不同的语句。
我们用一个简单的例子来说明这一点。
假设数据初始化为
CREATE (:Person {name: 'Alejandro'})
CREATE (:Person {name: 'Filipe'})
CREATE (:Person {name: 'Florent'})
CREATE (:Person {name: 'Marouane'})
CREATE (:Person {name: 'Nathan'})
Person
且带有 name
属性的节点。
运行 MATCH (p:Person) CALL { WITH p DELETE p } IN TRANSACTIONS OF 2 ROWS
可能会有不同的结果。此查询批量删除所有标签为 Person
的节点,每批删除 2 个。
如果在没有其他事务并发更改数据的情况下,执行可能会成功并运行 3 个批次。
如果并发事务创建更多 Person
节点,则可能需要更多批次。
如果并发事务删除 Person
节点,则可能需要更少批次。
如果并发事务创建了指向上述任何节点的关联,则 CALL {} IN TRANSACTIONS
也可能失败,因为 DELETE
假设节点是断开连接的(DETACH DELETE
删除节点及其关联)。