查找具有精确边缘匹配的顶点遍历子项

时间:2016-12-21 23:35:31

标签: orientdb graph-databases tinkerpop tinkerpop3

我的设置:

我正在使用带有人物顶点的大图的OrientDB。我正在使用gremlin java驱动程序来访问这个数据库,因为我想最终切换到不同的图形数据库。

我的数据库:

每个人都有某些偏好顶点(通过标记边缘连接,描述与该偏好的关系)。然后将所有首选项连接到核心概念顶点。

我正试图解决的问题:

我正在尝试找到一种方法(如果它像Gremlin查询一样简单),从Person顶点开始,并通过核心概念遍历所有具有相同偏好的人。

以下是匹配案例的组成示例。当人物A开始时,B人将被返回到人们完美匹配的列表中。我忘了在这张照片上绘制到这些边缘的方向:/看看不匹配的情况,看看方向。

Matching Case

以下是不匹配案例的示例。 B人将不会在人员的完美比赛列表中退回。为什么?因为Person B上的所有传出边缘都不会解析为人员A上相同的边缘;在这种情况下,A人拒绝吃苹果,但B人没有列出他们拒绝吃的任何东西的类似偏好。

Non matching case

上述例子的另一个不匹配案例:如果A人拒绝吃苹果而B人拒绝吃香蕉 - 他们就不会匹配。

如果B人最喜欢Fries并且最不喜欢芝士汉堡,那么这也是一个不匹配的情况。

我最初的想法(我不确定如何实施)与查询

  1. 我会从A人开始
  2. 找到偏好顶点的所有外边,并存储某种“标记”或使用边标签映射到该偏好顶点。
  3. 遍历所有SimilarTo标记边缘的那些顶点。将这些标记从首选项顶点复制到概念顶点。
  4. 反转线:概念顶点 - >偏好顶点(从概念到偏好顶点的拷贝制造者)
  5. ...然后以某种方式将所有边缘与这些标记相匹配......
  6. 从结果中排除人a
  7. 有什么想法吗?

1 个答案:

答案 0 :(得分:2)

让我们从创建示例图开始:

gremlin> g = TinkerGraph.open().traversal()
==>graphtraversalsource[tinkergraph[vertices:0 edges:0], standard]
gremlin> g.addV("person").property("name", "Person A").as("pa").
......1>   addV("person").property("name", "Person B").as("pb").
......2>   addV("food").property("name", "Hamburgers").as("hb").
......3>   addV("food").property("name", "Chips").as("c").
......4>   addV("food").property("name", "Cheeseburgers").as("cb").
......5>   addV("food").property("name", "Fries").as("f").
......6>   addV("category").property("name", "Burgers").as("b").
......7>   addV("category").property("name", "Appetizers").as("a").
......8>   addE("most").from("pa").to("hb").
......9>   addE("most").from("pb").to("cb").
.....10>   addE("least").from("pa").to("c").
.....11>   addE("least").from("pb").to("f").
.....12>   addE("similar").from("hb").to("b").
.....13>   addE("similar").from("cb").to("b").
.....14>   addE("similar").from("c").to("a").
.....15>   addE("similar").from("f").to("a").iterate()

您正在寻找的查询如下(我将在稍后解释每一步):

gremlin> g.V().has("person", "name", "Person A").as("p").
......1>   outE("most","least","refuses").as("e").inV().out("similar").
......2>   store("x").by(constant(1)).
......3>   in("similar").inE().where(eq("e")).by(label).outV().where(neq("p")).
......4>   groupCount().as("m").
......5>   select("x").by(count(local)).as("c").
......6>   select("m").unfold().
......7>   where(select(values).as("c")).select(keys).values("name")
==>Person B

现在,当我们添加"拒绝吃苹果"关系:

gremlin> g.V().has("person", "name", "Person A").as("p").
......1>   addV("food").property("name", "Apples").as("a").
......2>   addV("category").property("name", "Fruits").as("f").
......3>   addE("refuses").from("p").to("a").
......4>   addE("similar").from("a").to("f").iterate()

...... B人不再匹配:

gremlin> g.V().has("person", "name", "Person A").as("p").
......1>   outE("most","least","refuses").as("e").inV().out("similar").
......2>   store("x").by(constant(1)).
......3>   in("similar").inE().where(eq("e")).by(label).outV().where(neq("p")).
......4>   groupCount().as("m").
......5>   select("x").by(count(local)).as("c").
......6>   select("m").unfold().
......7>   where(select(values).as("c")).select(keys).values("name")
gremlin>

让我们一步一步地逐行查询:

g.V().has("person", "name", "Person A").as("p").

这应该很清楚:从人A开始。

outE("most","least","refuses").as("e").inV().out("similar").

遍历边缘并设置标记,以便我们稍后可以引用边缘。然后遍历我所谓的category顶点。

store("x").by(constant(1)).

对于每个category顶点,将1添加到内部集合。你也可以存储顶点本身,但这会浪费内存,因为我们不需要顶点的任何信息。

in("similar").inE().where(eq("e")).by(label).outV().where(neq("p")).

沿着similar边缘向food移动另一个方向,然后沿着与开头标记边缘具有相同标签的边缘。最后忽略遍历开始的人(人A)。

groupCount().as("m").

计算进入每个人顶点的遍历数。

select("x").by(count(local)).as("c").

计算Category个顶点的数量(1 s)。

select("m").unfold().

展开人物计数器,因此键将是人物顶点,值将是进入此顶点的遍历者数量。

where(select(values).as("c")).select(keys).values("name")

最终,交叉category顶点的数量必须与person顶点上的遍历数相匹配。如果是这样的话,我们就匹配了。

请注意,similar顶点发生Apples边缘事件是必要的。