模式优化

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

虽然 Neo4j 不强制要求使用模式(Schema),但在写入数据之前添加索引和约束可以提高写入过程的效率。在更新节点或关系时,应用约束也是避免重复数据的最佳方式。

下面总结了用于模式优化的连接器选项。

此处描述的模式优化选项不能与 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_<LABEL>_<NODE_KEYS>,其中 <LABEL> 是来自 labels 选项的第一个标签,<NODE_KEYS> 是 node.keys 选项中指定的一个或多个属性的短横线分隔序列。

说明

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

  • 对于多个标签,仅使用第一个标签来创建索引。

节点属性唯一性约束

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

您可以通过将 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 模式来强制执行类型(使用 数据类型映射 中描述的映射),并使用每列的 nullable 标志来决定是否强制执行存在性。

您可以创建:

  • 通过将 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

© . This site is unofficial and not affiliated with Neo4j, Inc.