属性图

概述

根据维基百科的定义,属性图、带标签的属性图或带属性图是一种数据模型,其中实体对通过关系相互关联,且实体和关系都可以具有属性。

An example of the property graph with different kinds of edges and vertices

为了具体说明,让我们想象一个“影迷社交网络”的例子。上图展示了它作为属性图的样子。图中包含人物和电影——两种类型的顶点,每种顶点都有各自的属性。人物可以喜欢电影(无向边)、互相发送消息(有向边)以及关注导演。还存在作为独立顶点类型的演员和导演。电影可以通过续集关系相互连接。如图所示,所有这些关系和实体都很容易在属性图中表示。

属性图模型非常通用。以银行支付网络为例:存在法人实体、政府服务、个人、交易所和商品。每种都是不同的顶点类型。支付是具有日期和金额等属性的有向加权边。两个共享董事会成员的法人实体形成无向无权边,并将董事详细信息作为属性。这种结构非常适合合规性、KYC和反欺诈。它有助于查看谁与谁相关联以及关联的紧密程度。

或者考虑一个在线市场。有买家、卖家和产品。买家从卖家处购买产品。卖家提供多种产品。所有这些都很自然地适用于属性图。这种结构非常适合推荐系统。推荐产品本质上是图中的链接预测问题。

另一个例子是组织网络分析(ONA)。公司拥有部门、团队和人员,这些都以不同方式相互连接。团队之间相互分配任务。人员既有正式关系也有非正式关系。存在官方层级和实际层级。ONA可以揭示关键员工、流程瓶颈,甚至预测冲突。它还有助于改善整个组织的知识共享。

GraphFrames中的属性图

GraphFrames 将属性图表示为多个名为顶点属性组的逻辑结构与多个名为边属性组的逻辑结构相互连接而成的组合。

顶点属性组

有关API详情请参阅org.graphframes.propertygraph.property.VertexPropertyGroup。它包含属性组的名称,例如movies,ID列的名称以及以DataFrame形式存储的基础数据。

下面的简单示例创建了两个属性组:peoplemovies

import org.graphframes.propertygraph.property.VertexPropertyGroup

val peopleData = spark
  .createDataFrame(
    Seq((1L, "Alice"), (2L, "Bob"), (3L, "Charlie"), (4L, "David"), (5L, "Eve")))
  .toDF("id", "name")

val peopleGroup = VertexPropertyGroup("people", peopleData, "id")

val moviesData = spark
  .createDataFrame(Seq((1L, "Matrix"), (2L, "Inception"), (3L, "Interstellar")))
  .toDF("id", "title")

val moviesGroup = VertexPropertyGroup("movies", moviesData, "id")

边属性组

有关API详情请参阅org.graphframes.propertygraph.property.EdgePropertyGroup。它包含属性组的名称、指向源顶点和目标顶点属性组的链接、边的方向(directedundirected),以及以DataFrame形式存储的基础数据。此外,它还可以包含带边权重的列以及源顶点和目标顶点ID列的名称。

下面的简单示例创建了一个名为 likes 的边属性组,并链接到 peoplemovies 顶点属性组,以及将人与人链接的 messages 属性组。

import org.graphframes.propertygraph.property.EdgePropertyGroup

val likesData = spark
  .createDataFrame(Seq((1L, 1L), (1L, 2L), (2L, 1L), (3L, 2L), (4L, 3L), (5L, 2L)))
  .toDF("src", "dst")

val likesGroup = EdgePropertyGroup(
  "likes",
  likesData,
  peopleGroup,
  moviesGroup,
  isDirected = false,
  "src",
  "dst",
  lit(1.0))

val messagesData = spark
  .createDataFrame(
    Seq((1L, 2L, 5.0), (2L, 3L, 8.0), (3L, 4L, 3.0), (4L, 5L, 6.0), (5L, 1L, 9.0)))
  .toDF("src", "dst", "weight")

val messagesGroup = EdgePropertyGroup(
  "messages",
  messagesData,
  peopleGroup,
  peopleGroup,
  isDirected = true,
  "src",
  "dst",
  col("weight"))

属性图框架

定义完属性组后,我们可以通过将属性组传递给构造函数来创建一个 PropertyGraphFrame

import org.graphframes.propertygraph.PropertyGraphFrame

peopleMoviesGraph =
  PropertyGraphFrame(Seq(peopleGroup, moviesGroup), Seq(likesGroup, messagesGroup))

转换为 GraphFrames

PropertyGraphFrame 可通过调用 toGraphFrame 转换为 GraphFrame。用户可选择顶点和边属性组的子集以包含在生成的 GraphFrame 中。在底层,该转换将通过应用哈希处理顶点和边ID来处理潜在的顶点和边ID冲突。

val graph = peopleMoviesGraph.toGraphFrame(
  Seq("people"),
  Seq("messages"),
  Map("messages" -> lit(true)),
  Map("people" -> lit(true)))

更多详情请参阅 org.graphframes.propertygraph.PropertyGraphFrame

此操作并非无代价,因此用户也可以为每个 VertexGroup 显式指定是否需要哈希处理。

val moviesData = spark
  .createDataFrame(Seq((1L, "Matrix"), (2L, "Inception"), (3L, "Interstellar")))
  .toDF("id", "title")

val moviesGroup = VertexPropertyGroup("movies", moviesData, "id", applyMaskOnId = false)

投影

PropertyGraphFrame 支持将边组投影到新的边组。例如,如果我们有一个属性图,其中人们可以喜欢电影,我们可以将这样的二分图投影到一个仅包含人的图中,如果两个人喜欢同一部电影,则他们之间会建立连接。此操作会创建一个新的 PropertyGraphFrame,其中包含一个新的边组,并且不包含用于进行投影的原始边组。

val projectedGraph = peopleMoviesGraph.projectionBy("people", "movies", "likes")