自从提出这个问题以来,图数据库已经取得了长足的进步,但问题的答案是,绝对是的,图数据库可以用来找到更好的性能模式。
免责声明:我是 Objectiveivity, Inc. 的现场运营总监。
这不是产品插头。市场上的很多产品都可以解决这个问题。您特别提到将问题扩大化,这很可能是某些产品的限制因素。
为了解决这个问题,我使用了 Objectivity/DB 数据库,它是一个大规模可扩展的对象/图形数据库,具有称为 DO for Declarative Objectiveivity 的全功能图形导航查询语言。
这是我用来解决该问题的模式:
CREATE CLASS Season {
year : Integer,
games : List { Element: Reference { referenced: Game }, CollectionTypeName: TreeListOfReferences }
}
CREATE CLASS Game {
date : DateTime,
homeTeam : Reference { referenced: Team, inverse: homeGames },
awayTeam : Reference { referenced: Team, inverse: awayGames },
from : Reference { referenced: Season, inverse: games },
innings : Reference { referenced: Inning, inverse: game }
}
CREATE CLASS Inning {
number : Integer,
game : Reference { referenced: Game, inverse: innings },
batters : Reference { referenced: AtBat, inverse: inning }
}
CREATE CLASS AtBat {
result : String,
inning : Reference { referenced: Inning, inverse: batters },
batter : Reference { referenced: Player, inverse: atBats },
nextAtBat : Reference { referenced: AtBat, inverse: prevAtBat },
prevAtBat : Reference { referenced: AtBat, inverse: nextAtBat },
nextBatter : Reference { referenced: AtBat, inverse: prevBatter },
prevBatter : Reference { referenced: AtBat, inverse: nextBatter }
}
CREATE CLASS Player {
name : String,
teams : List { Element: Reference { EdgeClass: PlayedFor, EdgeAttribute: team }, CollectionTypeName: TreeListOfReferences },
atBats : List { Element: Reference { referenced: AtBat, inverse: batter }, CollectionTypeName: TreeListOfReferences }
}
CREATE CLASS PlayedFor {
player : Reference { referenced: Player, inverse: teams },
team : Reference { referenced: Team, inverse: players },
start : DateTime,
end : DateTime
}
CREATE CLASS Team {
name : String,
homeGames : Reference { referenced: Game, inverse: homeTeam },
awayGames : Reference { referenced: Game, inverse: awayTeam },
players : List { Element: Reference { EdgeClass: PlayedFor, EdgeAttribute: team }, CollectionTypeName: TreeListOfReferences }
}
以下是该架构的摘要。每个玩家都连接到他们自己的每一个 AtBat 对象。每个玩家的 AtBat 对象以双向链表的形式存在。每个 AtBat 对象都指向拥有它的 Player。
A sample dataset might look like this:
这个想法是找到用户定义的 AtBat 对象序列,然后找到拥有该序列的 Player。在下面的查询中,我们正在寻找“三振出局”、“击中”和“三振出局”模式。当我们找到该模式时,我们需要知道与该模式关联的玩家。因为所有 AtBat 对象都链接回所属的 Player,所以我们在查询中所要做的就是表达所需的 AtBat 对象序列,然后从最后一个 AtBat 对象导航到它所连接的 Player 对象。查询如下:
match path = (a1:AtBat {result == "Strike Out"})
-[:nextAtBat]->(a2:AtBat {result == "Hit"})
-[:nextAtBat]->(a3:AtBat {result == "Strike Out"})
-->(p:Player)
group by p.name
return a1.result, a2.result, a3.result, p.name;
结果示例如下所示:
{
_Projection
{
a1.result:'Strike Out',
a2.result:'Hit',
a3.result:'Strike Out',
p.name:'Player0_TeamA'
},
_Projection
{
a1.result:'Strike Out',
a2.result:'Hit',
a3.result:'Strike Out',
p.name:'Player0_TeamB'
},
_Projection
{
a1.result:'Strike Out',
a2.result:'Hit',
a3.result:'Strike Out',
p.name:'Player10_TeamA'
},
此图描述了查找模式,然后从最后一个 AtBat 导航到关联的 Player: