Azure CosmosDB 上的 Gremlin:如何投影相关顶点的属性?
Gremlin on Azure CosmosDB: how to project the related vertices' properties?
我使用 Microsoft.Azure.Graphs 库连接到 Cosmos DB 实例并查询图形数据库。
我正在尝试优化我的 Gremlin 查询,以便仅 select 我只需要的那些属性。但是,我不知道如何从边和顶点中选择 select 的属性。
假设我们从这个查询开始:
gremlin> g.V().hasLabel('user').
project('user', 'edges', 'relatedVertices')
.by()
.by(bothE().fold())
.by(both().fold())
这将 return 类似于:
{
"user": {
"id": "<userId>",
"type": "vertex",
"label": "user",
"properties": [
// all vertex properties
]
},
"edges": [{
"id": "<edgeId>",
"type": "edge",
"label": "<edgeName>",
"inV": <relatedVertexId>,
"inVLabel": "<relatedVertexLabel>",
"outV": "<relatedVertexId>",
"outVLabel": "<relatedVertexLabel>"
"properties": [
// edge properties, if any
]
}],
"relatedVertices": [{
"id": "<vertexId>",
"type": "vertex",
"label": "<relatedVertexLabel>",
"properties": [
// all related vertex properties
]
}]
}
现在假设我们只从我们命名为 "User":
的根顶点获取几个属性
gremlin> g.V().hasLabel('user').
project('id', 'prop1', 'prop2', 'edges', 'relatedVertices')
.by(id)
.by('prop1')
.by('prop2')
.by(bothE().fold())
.by(both().fold())
这将为我们带来一些进展,并产生一些类似的东西:
{
"id": "<userId>",
"prop1": "value1",
"prop2": "value2",
"edges": [{
"id": "<edgeId>",
"type": "edge",
"label": "<edgeName>",
"inV": <relatedVertexId>,
"inVLabel": "<relatedVertexLabel>",
"outV": "<relatedVertexId>",
"outVLabel": "<relatedVertexLabel>"
"properties": [
// edge properties, if any
]
}],
"relatedVertices": [{
"id": "<vertexId>",
"type": "vertex",
"label": "<relatedVertexLabel>",
"properties": [
// all related vertex properties
]
}]
}
现在可以做一些类似边和相关顶点的事情吗?比如说,类似于:
gremlin> g.V().hasLabel('user').
project('id', 'prop1', 'prop2', 'edges', 'relatedVertices')
.by(id)
.by('prop1')
.by('prop2')
.by(bothE().fold()
.project('edgeId', 'edgeLabel', 'edgeInV', 'edgeOutV')
.by(id)
.by(label)
.by(inV)
.by(outV))
.by(both().fold()
.project('vertexId', 'someProp1', 'someProp2')
.by(id)
.by('someProp1')
.by('someProp2'))
我的目标是得到这样的输出:
{
"id": "<userId>",
"prop1": "value1",
"prop2": "value2",
"edges": [{
"edgeId": "<edgeId>",
"edgeLabel": "<edgeName>",
"edgeInV": <relatedVertexId>,
"edgeOutV": "<relatedVertexId>"
}],
"relatedVertices": [{
"vertexId": "<vertexId>",
"someProp1": "someValue1",
"someProp2": "someValue2"
}]
}
你们非常接近:
gremlin> g.V().hasLabel('person').
......1> project('name','age','edges','relatedVertices').
......2> by('name').
......3> by('age').
......4> by(bothE().
......5> project('id','inV','outV').
......6> by(id).
......7> by(inV().id()).
......8> by(outV().id()).
......9> fold()).
.....10> by(both().
.....11> project('id','name').
.....12> by(id).
.....13> by('name').
.....14> fold())
==>[name:marko,age:29,edges:[[id:9,inV:3,outV:1],[id:7,inV:2,outV:1],[id:8,inV:4,outV:1]],relatedVertices:[[id:3,name:lop],[id:2,name:vadas],[id:4,name:josh]]]
==>[name:vadas,age:27,edges:[[id:7,inV:2,outV:1]],relatedVertices:[[id:1,name:marko]]]
==>[name:josh,age:32,edges:[[id:10,inV:5,outV:4],[id:11,inV:3,outV:4],[id:8,inV:4,outV:1]],relatedVertices:[[id:5,name:ripple],[id:3,name:lop],[id:1,name:marko]]]
==>[name:peter,age:35,edges:[[id:12,inV:3,outV:6]],relatedVertices:[[id:3,name:lop]]]
编写 Gremlin 时应考虑的两点:
- 上一步的输出输入到下一个步骤的输入,如果您没有清楚地看到特定步骤的结果,那么接下来的步骤可能不会是正确的。在您的示例中,在第一个
by()
中,您在 fold()
之后添加了 project()
,这基本上是说 "Hey, Gremlin, project that List
of edges for me." 但是在 by()
调制器中 project()
您将投影的输入视为不是 List
而是可能导致错误的单个边缘。在 Java 中,错误是:"java.util.ArrayList cannot be cast to org.apache.tinkerpop.gremlin.structure.Element"。类似这样的错误表明您在 Gremlin 中的某处没有正确遵循步骤的输出和输入。
fold()
获取遍历流中的所有元素并将它们转换为 List
。因此,在您拥有许多对象的地方,现在您将在 fold()
之后拥有一个对象。要再次将它们作为流处理,您将需要 unfold()
它们以获取单独操作它们的步骤。在这种情况下,我们只需要在为每个 edge/vertex 执行 sub-project()
之后将 fold()
移动到语句的末尾。但是为什么我们需要 fold()
呢?答案是传递给 by()
调制器的遍历不会完全由它修改的步骤迭代(在本例中为 project()
)。该步骤仅调用 next()
以获取流中的第一个元素 - 这是设计使然。因此,在您希望处理 by()
的整个流的情况下,您必须将流缩减为单个对象。您可以使用 fold()
执行此操作,但其他示例包括 sum()
、count()
、mean()
等
我使用 Microsoft.Azure.Graphs 库连接到 Cosmos DB 实例并查询图形数据库。
我正在尝试优化我的 Gremlin 查询,以便仅 select 我只需要的那些属性。但是,我不知道如何从边和顶点中选择 select 的属性。
假设我们从这个查询开始:
gremlin> g.V().hasLabel('user').
project('user', 'edges', 'relatedVertices')
.by()
.by(bothE().fold())
.by(both().fold())
这将 return 类似于:
{
"user": {
"id": "<userId>",
"type": "vertex",
"label": "user",
"properties": [
// all vertex properties
]
},
"edges": [{
"id": "<edgeId>",
"type": "edge",
"label": "<edgeName>",
"inV": <relatedVertexId>,
"inVLabel": "<relatedVertexLabel>",
"outV": "<relatedVertexId>",
"outVLabel": "<relatedVertexLabel>"
"properties": [
// edge properties, if any
]
}],
"relatedVertices": [{
"id": "<vertexId>",
"type": "vertex",
"label": "<relatedVertexLabel>",
"properties": [
// all related vertex properties
]
}]
}
现在假设我们只从我们命名为 "User":
的根顶点获取几个属性gremlin> g.V().hasLabel('user').
project('id', 'prop1', 'prop2', 'edges', 'relatedVertices')
.by(id)
.by('prop1')
.by('prop2')
.by(bothE().fold())
.by(both().fold())
这将为我们带来一些进展,并产生一些类似的东西:
{
"id": "<userId>",
"prop1": "value1",
"prop2": "value2",
"edges": [{
"id": "<edgeId>",
"type": "edge",
"label": "<edgeName>",
"inV": <relatedVertexId>,
"inVLabel": "<relatedVertexLabel>",
"outV": "<relatedVertexId>",
"outVLabel": "<relatedVertexLabel>"
"properties": [
// edge properties, if any
]
}],
"relatedVertices": [{
"id": "<vertexId>",
"type": "vertex",
"label": "<relatedVertexLabel>",
"properties": [
// all related vertex properties
]
}]
}
现在可以做一些类似边和相关顶点的事情吗?比如说,类似于:
gremlin> g.V().hasLabel('user').
project('id', 'prop1', 'prop2', 'edges', 'relatedVertices')
.by(id)
.by('prop1')
.by('prop2')
.by(bothE().fold()
.project('edgeId', 'edgeLabel', 'edgeInV', 'edgeOutV')
.by(id)
.by(label)
.by(inV)
.by(outV))
.by(both().fold()
.project('vertexId', 'someProp1', 'someProp2')
.by(id)
.by('someProp1')
.by('someProp2'))
我的目标是得到这样的输出:
{
"id": "<userId>",
"prop1": "value1",
"prop2": "value2",
"edges": [{
"edgeId": "<edgeId>",
"edgeLabel": "<edgeName>",
"edgeInV": <relatedVertexId>,
"edgeOutV": "<relatedVertexId>"
}],
"relatedVertices": [{
"vertexId": "<vertexId>",
"someProp1": "someValue1",
"someProp2": "someValue2"
}]
}
你们非常接近:
gremlin> g.V().hasLabel('person').
......1> project('name','age','edges','relatedVertices').
......2> by('name').
......3> by('age').
......4> by(bothE().
......5> project('id','inV','outV').
......6> by(id).
......7> by(inV().id()).
......8> by(outV().id()).
......9> fold()).
.....10> by(both().
.....11> project('id','name').
.....12> by(id).
.....13> by('name').
.....14> fold())
==>[name:marko,age:29,edges:[[id:9,inV:3,outV:1],[id:7,inV:2,outV:1],[id:8,inV:4,outV:1]],relatedVertices:[[id:3,name:lop],[id:2,name:vadas],[id:4,name:josh]]]
==>[name:vadas,age:27,edges:[[id:7,inV:2,outV:1]],relatedVertices:[[id:1,name:marko]]]
==>[name:josh,age:32,edges:[[id:10,inV:5,outV:4],[id:11,inV:3,outV:4],[id:8,inV:4,outV:1]],relatedVertices:[[id:5,name:ripple],[id:3,name:lop],[id:1,name:marko]]]
==>[name:peter,age:35,edges:[[id:12,inV:3,outV:6]],relatedVertices:[[id:3,name:lop]]]
编写 Gremlin 时应考虑的两点:
- 上一步的输出输入到下一个步骤的输入,如果您没有清楚地看到特定步骤的结果,那么接下来的步骤可能不会是正确的。在您的示例中,在第一个
by()
中,您在fold()
之后添加了project()
,这基本上是说 "Hey, Gremlin, project thatList
of edges for me." 但是在by()
调制器中project()
您将投影的输入视为不是List
而是可能导致错误的单个边缘。在 Java 中,错误是:"java.util.ArrayList cannot be cast to org.apache.tinkerpop.gremlin.structure.Element"。类似这样的错误表明您在 Gremlin 中的某处没有正确遵循步骤的输出和输入。 fold()
获取遍历流中的所有元素并将它们转换为List
。因此,在您拥有许多对象的地方,现在您将在fold()
之后拥有一个对象。要再次将它们作为流处理,您将需要unfold()
它们以获取单独操作它们的步骤。在这种情况下,我们只需要在为每个 edge/vertex 执行 sub-project()
之后将fold()
移动到语句的末尾。但是为什么我们需要fold()
呢?答案是传递给by()
调制器的遍历不会完全由它修改的步骤迭代(在本例中为project()
)。该步骤仅调用next()
以获取流中的第一个元素 - 这是设计使然。因此,在您希望处理by()
的整个流的情况下,您必须将流缩减为单个对象。您可以使用fold()
执行此操作,但其他示例包括sum()
、count()
、mean()
等