模式优化

本页中的所有示例都假定 `SparkSession` 已使用适当的身份验证选项进行初始化。有关更多详细信息,请参阅快速入门示例

尽管 Neo4j 不强制使用模式,但在写入数据之前添加索引和约束可以使写入过程更高效。在更新节点或关系时,设置约束也是避免重复的最佳方式。

连接器模式优化选项总结如下。

此处描述的模式优化选项不能与 `query` 选项一起使用。如果您正在使用自定义 Cypher® 查询,则需要使用`script` 选项手动创建索引和约束。

表 1. 模式优化选项
选项 描述 默认值

schema.optimization.type 在 5.3 中已弃用

使用 `node.keys` 选项定义的属性,在节点上创建索引属性唯一性约束。

(已弃用,建议改用 `schema.optimization.node.keys`、`schema.optimization.relationship.keys`、`schema.optimization`)

`NONE`、`INDEX`、`NODE_CONSTRAINTS` 之一

NONE

schema.optimization.node.keys 5.3 新增

使用 `node.keys` 选项定义的属性,在节点上创建属性唯一性约束。

`UNIQUE`、`KEY`、`NONE` 之一

NONE

schema.optimization.relationship.keys 5.3 新增

使用 `relationship.keys` 选项定义的属性,在关系上创建属性唯一性约束。

`UNIQUE`、`KEY`、`NONE` 之一

NONE

schema.optimization 5.3 新增

在节点和关系上创建属性类型和属性存在性约束,强制执行 DataFrame 模式中的类型和非空性。

`TYPE`、`EXISTS`、`NONE` 的逗号分隔列表

NONE

节点属性上的索引

Neo4j 中的索引通常用于提高搜索性能。

可以通过将 `schema.optimization.type` 选项设置为 `INDEX` 来创建索引。

示例
val df = List(
  "Product 1",
  "Product 2",
).toDF("name")

df.write
  .format("org.neo4j.spark.DataSource")
  .mode(SaveMode.Overwrite)
  .option("labels", ":Product")
  .option("node.keys", "name")
  .option("schema.optimization.type", "INDEX")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询

CREATE INDEX spark_INDEX_Product_name FOR (n:Product) ON (n.name)

索引名称的格式为 `spark_INDEX_

注意

  • 如果索引已存在,则不会重新创建。

  • 当有多个标签时,仅使用第一个标签来创建索引。

节点属性唯一性约束

节点属性唯一性约束确保具有特定标签的所有节点的属性值都是唯一的。对于多个属性上的属性唯一性约束,属性值的组合是唯一的。

可以通过将 `schema.optimization.node.keys` 选项设置为 `UNIQUE` 来创建约束。

示例
val df = List(
  "Product 1",
  "Product 2",
).toDF("name")

df.write
  .format("org.neo4j.spark.DataSource")
  .mode(SaveMode.Overwrite)
  .option("labels", ":Product")
  .option("node.keys", "name")
  .option("schema.optimization.node.keys", "UNIQUE")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_NODE_UNIQUE-CONSTRAINT_Product_name` IF NOT EXISTS FOR (e:Product) REQUIRE (e.name) IS UNIQUE

注意

  • 如果约束已存在,则不会重新创建。

  • 当有多个标签时,仅使用第一个标签来创建索引。

  • 如果节点属性上已存在键约束,则无法在该属性上创建唯一性约束。

  • 此模式优化仅适用于 `Overwrite` 保存模式。

5.3.0 版本之前,可以通过将 `schema.optimization.type` 选项设置为 `NODE_CONSTRAINTS` 来添加节点属性唯一性约束。

节点键约束

节点键约束确保对于给定的节点标签和一组属性,满足以下条件:

  • 所有属性都存在于具有该标签的所有节点上。

  • 属性值的组合是唯一的。

可以通过将 `schema.optimization.node.keys` 选项设置为 `KEY` 来创建约束。

示例
val df = List(
  "Product 1",
  "Product 2",
).toDF("name")

df.write
  .format("org.neo4j.spark.DataSource")
  .mode(SaveMode.Overwrite)
  .option("labels", ":Product")
  .option("node.keys", "name")
  .option("schema.optimization.node.keys", "KEY")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_NODE_KEY-CONSTRAINT_Product_name` IF NOT EXISTS FOR (e:Product) REQUIRE (e.name) IS NODE KEY

注意

  • 如果约束已存在,则不会重新创建。

  • 如果节点属性上已存在唯一性约束,则无法在该属性上创建键约束。

  • 此模式优化仅适用于 `Overwrite` 保存模式。

关系属性唯一性约束

关系属性唯一性约束确保具有特定类型的所有关系的属性值都是唯一的。对于多个属性上的属性唯一性约束,属性值的组合是唯一的。

可以通过将 `schema.optimization.relationship.keys` 选项设置为 `UNIQUE` 来创建约束。

示例
val df = Seq(
  ("John", "Doe", 1, "Product 1", 200, "ABC100"),
  ("Jane", "Doe", 2, "Product 2", 100, "ABC200")
).toDF("name", "surname", "customerID", "product", "quantity", "order")

df.write
  .mode(SaveMode.Overwrite)
  .format("org.neo4j.spark.DataSource")
  .option("relationship", "BOUGHT")
  .option("relationship.save.strategy", "keys")
  .option("relationship.source.save.mode", "Overwrite")
  .option("relationship.source.labels", ":Customer")
  .option("relationship.source.node.properties", "name,surname,customerID:id")
  .option("relationship.source.node.keys", "customerID:id")
  .option("relationship.target.save.mode", "Overwrite")
  .option("relationship.target.labels", ":Product")
  .option("relationship.target.node.properties", "product:name")
  .option("relationship.target.node.keys", "product:name")
  .option("relationship.properties", "quantity,order")
  .option("schema.optimization.relationship.keys", "UNIQUE")
  .option("relationship.keys", "order")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_RELATIONSHIP_UNIQUE-CONSTRAINT_BOUGHT_order` IF NOT EXISTS FOR ()-[e:BOUGHT]->() REQUIRE (e.order) IS UNIQUE

注意

  • 如果约束已存在,则不会重新创建。

  • 如果关系属性上已存在键约束,则无法在该属性上创建唯一性约束。

  • 此模式优化仅适用于 `Overwrite` 保存模式。

关系键约束

关系键约束确保对于给定的关系类型和一组属性,满足以下条件:

  • 所有属性都存在于具有该类型的所有关系上。

  • 属性值的组合是唯一的。

可以通过将 `schema.optimization.relationship.keys` 选项设置为 `KEY` 来创建约束。

示例
val df = Seq(
  ("John", "Doe", 1, "Product 1", 200, "ABC100"),
  ("Jane", "Doe", 2, "Product 2", 100, "ABC200")
).toDF("name", "surname", "customerID", "product", "quantity", "order")

df.write
  .mode(SaveMode.Overwrite)
  .format("org.neo4j.spark.DataSource")
  .option("relationship", "BOUGHT")
  .option("relationship.save.strategy", "keys")
  .option("relationship.source.save.mode", "Overwrite")
  .option("relationship.source.labels", ":Customer")
  .option("relationship.source.node.properties", "name,surname,customerID:id")
  .option("relationship.source.node.keys", "customerID:id")
  .option("relationship.target.save.mode", "Overwrite")
  .option("relationship.target.labels", ":Product")
  .option("relationship.target.node.properties", "product:name")
  .option("relationship.target.node.keys", "product:name")
  .option("relationship.properties", "quantity,order")
  .option("schema.optimization.relationship.keys", "KEY")
  .option("relationship.keys", "order")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_RELATIONSHIP_KEY-CONSTRAINT_BOUGHT_order` IF NOT EXISTS FOR ()-[e:BOUGHT]->() REQUIRE (e.order) IS RELATIONSHIP KEY

注意

  • 如果约束已存在,则不会重新创建。

  • 如果关系属性上已存在唯一性约束,则无法在该属性上创建键约束。

  • 此模式优化仅适用于 `Overwrite` 保存模式。

属性类型和属性存在性约束

属性类型约束确保属性具有特定标签的所有节点(节点属性类型约束)或特定类型的所有关系(关系属性类型约束)都具有所需的属性类型。

属性存在性约束确保属性对于具有特定标签的所有节点(节点属性存在性约束)或特定类型的所有关系(关系属性存在性约束)都存在(即 `IS NOT NULL`)。

连接器使用 DataFrame 模式来强制执行类型(使用数据类型映射中描述的映射)以及每个列的可为空标志来确定是否强制执行存在性。

您可以创建:

  • 通过将 `schema.optimization` 选项设置为 `TYPE`,为节点和关系创建属性类型约束。

  • 通过将 `schema.optimization` 选项设置为 `EXISTS`,为节点和关系创建属性存在性约束。

  • 通过将 `schema.optimization` 选项设置为 `TYPE,EXISTS`,同时创建这两种约束。

注意

  • 如果约束已存在,则不会重新创建。

在节点上

示例
df.write
  .format("org.neo4j.spark.DataSource")
  .mode(SaveMode.Overwrite)
  .option("labels", ":Person")
  .option("node.keys", "surname")
  .option("schema.optimization", "TYPE,EXISTS")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询(每个 DataFrame 列一个查询)

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Person-name` IF NOT EXISTS FOR (e:Person) REQUIRE e.name IS :: STRING

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Person-surname` IF NOT EXISTS FOR (e:Person) REQUIRE e.surname IS :: STRING

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Person-age` IF NOT EXISTS FOR (e:Person) REQUIRE e.age IS :: INTEGER

如果 DataFrame 列不可为空,连接器会运行额外的模式查询。例如,如果 `age` 列不可为空,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_NODE-NOT_NULL-CONSTRAINT-Person-age` IF NOT EXISTS FOR (e:Person) REQUIRE e.age IS NOT NULL

在关系上

示例
val df = Seq(
  ("John", "Doe", 1, "Product 1", 200, "ABC100"),
  ("Jane", "Doe", 2, "Product 2", 100, "ABC200")
).toDF("name", "surname", "customerID", "product", "quantity", "order")

df.write
  .mode(SaveMode.Overwrite)
  .format("org.neo4j.spark.DataSource")
  .option("relationship", "BOUGHT")
  .option("relationship.save.strategy", "keys")
  .option("relationship.source.save.mode", "Overwrite")
  .option("relationship.source.labels", ":Customer")
  .option("relationship.source.node.properties", "name,surname,customerID:id")
  .option("relationship.source.node.keys", "customerID:id")
  .option("relationship.target.save.mode", "Overwrite")
  .option("relationship.target.labels", ":Product")
  .option("relationship.target.node.properties", "product:name")
  .option("relationship.target.node.keys", "product:name")
  .option("relationship.properties", "quantity,order")
  .option("schema.optimization", "TYPE,EXISTS")
  .save()
模式查询

在写入过程开始之前,连接器会运行以下模式查询(针对源节点和目标节点属性的属性类型约束查询,然后是代表关系属性的每个 DataFrame 列的一个属性类型约束查询)

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Customer-name` IF NOT EXISTS FOR (e:Customer) REQUIRE e.name IS :: STRING

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Customer-surname` IF NOT EXISTS FOR (e:Customer) REQUIRE e.surname IS :: STRING

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Customer-id` IF NOT EXISTS FOR (e:Customer) REQUIRE e.id IS :: INTEGER

CREATE CONSTRAINT `spark_NODE-TYPE-CONSTRAINT-Product-name` IF NOT EXISTS FOR (e:Product) REQUIRE e.name IS :: STRING

CREATE CONSTRAINT `spark_RELATIONSHIP-TYPE-CONSTRAINT-BOUGHT-quantity` IF NOT EXISTS FOR ()-[e:BOUGHT]->() REQUIRE e.quantity IS :: INTEGER

CREATE CONSTRAINT `spark_RELATIONSHIP-TYPE-CONSTRAINT-BOUGHT-order` IF NOT EXISTS FOR ()-[e:BOUGHT]->() REQUIRE e.order IS :: STRING

如果 DataFrame 列不可为空,连接器会运行额外的模式查询。例如,如果 `experience` 列不可为空,连接器会运行以下模式查询

CREATE CONSTRAINT `spark_NODE-NOT_NULL-CONSTRAINT-Customer-id` IF NOT EXISTS FOR (e:Customer) REQUIRE e.id IS NOT NULL

CREATE CONSTRAINT `spark_RELATIONSHIP-NOT_NULL-CONSTRAINT-BOUGHT-quantity` IF NOT EXISTS FOR ()-[e:BOUGHT]->() REQUIRE e.quantity IS NOT NULL
© . All rights reserved.