查找具有精确边缘匹配遍历子项的顶点
Finding vertices with exact edge matches traversing through children
我的设置:
我正在使用带有大量人物顶点图的 OrientDB。我正在使用 gremlin java 驱动程序来访问这个数据库,因为我想最终切换到另一个图形数据库。
我的数据库:
每个人都有特定的偏好顶点(通过描述与该偏好的关系的标记边连接)。然后将所有偏好连接到核心概念顶点。
我要解决的问题:
我正在尝试找到一种方法(如果它像 Gremlin 查询一样简单,那就太好了)从一个人的顶点开始,然后通过一个核心概念向下遍历到所有具有相同偏好的人。
这是一个匹配案例的虚构示例。当从 A 开始时,B 将在一个完美匹配的人列表中返回。我忘了在这张图片上画出这些边缘的方向:/看看不匹配的情况以查看方向。
这是一个不匹配案例的例子。 Person B 不会返回到 People 的完美匹配列表中。为什么?因为 Person B 上的所有传出边都不会解析为 Person A 上的相同匹配边;在这种情况下,A 拒绝吃苹果,但 B 没有列出与他们拒绝吃的任何东西相似的偏好。
上面例子中的另一个不匹配的情况:如果 A 拒绝吃苹果而 B 拒绝吃香蕉——他们将不匹配。
如果 B 最喜欢薯条,最不喜欢芝士汉堡,那也是不匹配的情况。
我最初的想法(我不确定如何实现)与查询
- 我会从 A 开始
- 找到所有到偏好顶点的出边并存储某种 "marker" 或映射到带有边标签的偏好顶点。
- 从这些顶点向下遍历所有 SimilarTo 标记的边。将那些标记从偏好顶点复制到概念顶点。
- 反转线:概念顶点 -> 偏好顶点(将制造商从概念复制到偏好顶点)
- ...然后以某种方式将所有边与这些标记匹配...
- 从结果中排除 a 人
有什么想法吗?
让我们从创建示例图开始:
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
现在,当我们添加 "refuses to eat Apples" 关系时:
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
)。
select("m").unfold().
展开人员计数器,因此键将是人员顶点,值将是到达该顶点的遍历器的数量。
where(select(values).as("c")).select(keys).values("name")
最终交叉 category
个顶点的数量必须与 person
个顶点上的遍历器数量相匹配。如果是这样的话,我们就有了比赛。
请注意,similar
边必须与 Apples
顶点相交。
我的设置:
我正在使用带有大量人物顶点图的 OrientDB。我正在使用 gremlin java 驱动程序来访问这个数据库,因为我想最终切换到另一个图形数据库。
我的数据库:
每个人都有特定的偏好顶点(通过描述与该偏好的关系的标记边连接)。然后将所有偏好连接到核心概念顶点。
我要解决的问题:
我正在尝试找到一种方法(如果它像 Gremlin 查询一样简单,那就太好了)从一个人的顶点开始,然后通过一个核心概念向下遍历到所有具有相同偏好的人。
这是一个匹配案例的虚构示例。当从 A 开始时,B 将在一个完美匹配的人列表中返回。我忘了在这张图片上画出这些边缘的方向:/看看不匹配的情况以查看方向。
这是一个不匹配案例的例子。 Person B 不会返回到 People 的完美匹配列表中。为什么?因为 Person B 上的所有传出边都不会解析为 Person A 上的相同匹配边;在这种情况下,A 拒绝吃苹果,但 B 没有列出与他们拒绝吃的任何东西相似的偏好。
上面例子中的另一个不匹配的情况:如果 A 拒绝吃苹果而 B 拒绝吃香蕉——他们将不匹配。
如果 B 最喜欢薯条,最不喜欢芝士汉堡,那也是不匹配的情况。
我最初的想法(我不确定如何实现)与查询
- 我会从 A 开始
- 找到所有到偏好顶点的出边并存储某种 "marker" 或映射到带有边标签的偏好顶点。
- 从这些顶点向下遍历所有 SimilarTo 标记的边。将那些标记从偏好顶点复制到概念顶点。
- 反转线:概念顶点 -> 偏好顶点(将制造商从概念复制到偏好顶点)
- ...然后以某种方式将所有边与这些标记匹配...
- 从结果中排除 a 人
有什么想法吗?
让我们从创建示例图开始:
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
现在,当我们添加 "refuses to eat Apples" 关系时:
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
)。
select("m").unfold().
展开人员计数器,因此键将是人员顶点,值将是到达该顶点的遍历器的数量。
where(select(values).as("c")).select(keys).values("name")
最终交叉 category
个顶点的数量必须与 person
个顶点上的遍历器数量相匹配。如果是这样的话,我们就有了比赛。
请注意,similar
边必须与 Apples
顶点相交。