数据建模
将数据从 DataFrames 转换为图
当处理任何复杂的 DataFrames 集合并准备将其加载到 Neo4j 时,你有两种选择
-
规范化加载
-
Cypher® 解构
本节将介绍这两种方式,并提供关于它们在性能和复杂度方面的优势与潜在缺点的信息。
| 在可能的情况下,使用规范化加载方法以获得最佳性能和可维护性。 |
规范化加载
假设你想将名为 purchases 的单个 DataFrame 加载到 Neo4j,内容如下
product_id,product,customer_id,customer,quantity
1,Socks,10,David,2
2,Pants,11,Andrea,1
这些数据表示一个简单的 (:Customer)-[:BOUGHT]→(:Product) 图模型。
规范化加载方法要求你创建多个不同的 DataFrame:为目标图中的每个节点标签和关系类型各创建一个。例如,在本例中,你可能会创建三个 DataFrame
-
val products = spark.sql("SELECT product_id, product FROM purchases") -
val customers = spark.sql("SELECT customer_id, customer FROM purchases") -
val bought = spark.sql("SELECT product_id, customer_id, quantity FROM purchases")
一旦这些简单的 DataFrame 构成了“标签表”的规范化视图(即每个节点标签或关系类型对应一个 DataFrame/表),就可以直接使用连接器提供的写入节点和关系的实用工具,而无需额外的 Cypher。此外——如果这些表已经按标识符唯一化,那么数据已经为最大并行度做好了准备。(参见下文的并行度说明。)
Cypher 解构
Cypher 解构是指使用单条 Cypher 语句将复杂记录处理为完整的图模式。我们再次来看上面的数据示例。
product_id,product,customer_id,customer,quantity
1,Socks,10,David,2
2,Pants,11,Andrea,1
要将其存储到 Neo4j,你可以使用如下的 Cypher 查询
MERGE (p:Product { id: event.product_id })
ON CREATE SET p.name = event.product
WITH p
MERGE (c:Customer { id: event.customer_id })
ON CREATE SET c.name = event.customer
MERGE (c)-[:BOUGHT { quantity: event.quantity }]->(p);
在这种情况下,整个工作可以通过一条 Cypher 语句完成。随着 DataFrame 的复杂化,Cypher 语句也可能变得非常复杂。
将图中的数据转换回 DataFrames
一般来说,始终使用显式的 RETURN 语句并对结果进行解构。
|
常见的做法是编写一条复杂的 Cypher 语句(可能会遍历许多关系),将数据集返回给 Spark。由于 Spark 并不理解图的原语,几乎没有办法在 Spark 中有效地表示原始的节点、关系或路径。因此,强烈建议不要将这些类型从 Cypher 返回给 Spark,而是聚焦于具体的属性值或函数结果,这些可以在 Spark 中表示为简单类型。
例如,下面的 Cypher 查询会产生一个尴尬的 DataFrame,难以进行后续操作
MATCH path=(p:Person { name: "Andrea" })-[r:KNOWS*]->(o:Person)
RETURN path;
更好的做法是使用下面的 Cypher 查询,它会生成一个更清晰的 DataFrame
MATCH path=(p:Person { name: "Andrea" })-[r:KNOWS*]->(o:Person)
RETURN length(path) as pathLength, p.name as p1Name, o.name as p2Name