功能特性#
Cypher 变更日志格式#
[所需插件版本 : 4.9.0.1]
该扩展支持 多语言 (polyglot) 变更日志(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>
警告
cypherXML 标签前需要添加相应的扩展命名空间前缀。- 如果查询包含
<或>等 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 部署是社区版还是企业版。它可以与标准布尔运算符结合使用,与其他前置条件组合。
<?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
有关每一列支持的值类型,请参阅 加载数据 (Load Data) 文档。
加载数据#
[所需 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 |
字符串 |
DLxmEfVUC9CAmjiNyVphWw== (base64 编码) |
byte[] |
布尔值 (BOOLEAN) |
布尔值 |
true 或 false |
布尔值 |
CLOB |
字符串 |
字符串 |
|
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 |
字符串 |
"a string" |
字符串 |
UUID |
字符串 |
1bc59ddb-8d4d-41d0-9c9a-34e837de5678 |
字符串 |
也支持 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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,因此所包含 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
Change Set 的 runInTransaction#
runInTransaction 的默认值为 true。这意味着给定 Change Set 的所有变更都在一个显式的、单一的事务中运行。
这是正确的默认设置,只有在需要以下两种 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.
在 Change Set 上将 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 是一个强大的工具,如果使用不当,可能会导致意外后果。
如果所包含 Change Set 的任何变更失败,则该 Change Set 不会存储在历史图中。
重新运行此 Change Set 会导致所有变更再次运行,即使是之前已经成功运行的变更也会再次执行。
在无法避免 runInTransactions="false" 的情况下,请确保受影响的 Change Set 查询是幂等的。定义 约束 并使用 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'})
name 属性的 Person 标签节点。
运行 MATCH (p:Person) CALL { WITH p DELETE p } IN TRANSACTIONS OF 2 ROWS 可能会有不同的结果。该查询以每批 2 行的方式删除所有 Person 标签的节点。
如果数据未被其他并发事务修改,执行可能会成功并以 3 个批次运行。
如果并发事务创建了更多的 Person 节点,则可能需要更多的批次。
如果并发事务删除了 Person 节点,则可能需要更少的批次。
如果并发事务创建了指向上述任何节点的关系,CALL {} IN TRANSACTIONS 也可能会失败,因为 DELETE 假定节点是断开连接的(DETACH DELETE 会删除节点及其关系)。