【问题标题】:Gremlin on Azure CosmosDB: how to project the related vertices' properties?Azure CosmosDB 上的 Gremlin:如何投影相关顶点的属性?
【发布时间】:2018-01-16 08:53:38
【问题描述】:

我使用 Microsoft.Azure.Graphs 库连接到 Cosmos DB 实例并查询图形数据库。

我正在尝试优化我的 Gremlin 查询,以便仅选择我只需要的那些属性。但是,我不知道如何从边和顶点中选择要选择的属性。

假设我们从这个查询开始:

gremlin> g.V().hasLabel('user').
   project('user', 'edges', 'relatedVertices')
     .by()
     .by(bothE().fold())
     .by(both().fold())

这将返回类似以下内容的内容:

{
    "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
        ]
    }]
}

现在假设我们只从我们命名为“用户”的根顶点获取几个属性:

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"
    }]
}

【问题讨论】:

    标签: azure-cosmosdb graph-databases gremlin


    【解决方案1】:

    你已经很接近了:

    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 时应考虑的两点:

    1. 上一步的输出反馈到下一步的输入中,如果您不能清楚地看到特定步骤的结果,那么随后的步骤可能最终不会是正确的。在您的示例中,在第一个 by() 中,您在 fold() 之后添加了 project(),这基本上是在说“嘿,Gremlin,为我投射 List 的边缘。”但是在by()by() 调制器@ 中,您将要投影的输入不是List,而是作为可能导致错误的单个边缘。在 Java 中,该错误是:“java.util.ArrayList 无法转换为 org.apache.tinkerpop.gremlin.structure.Element”。像这样的错误提示您在 Gremlin 的某个地方没有正确遵循步骤的输出和输入。
    2. fold() 获取遍历流中的所有元素并将它们转换为List。因此,在您有很多对象的地方,您现在将在fold() 之后拥有一个。要再次将它们作为流处理,您需要unfold() 它们以获取单独操作它们的步骤。在这种情况下,我们只需要在为每个边/顶点执行 sub-project() 之后将fold() 移动到语句的末尾。但是为什么我们需要fold()呢?答案是传递给by() 调制器的遍历并没有被它修改的步骤完全迭代(在本例中为project())。该步骤仅调用next() 来获取流中的第一个元素——这是设计使然。因此,如果您希望处理 by() 的整个流,则必须将流缩减为单个对象。您可以使用 fold() 来实现,但其他示例包括 sum()count()mean() 等。

    【讨论】:

    • 谢谢,感谢您的宝贵时间。这是解决方案,但不幸的是它在调用堆栈深处的某个地方失败,导致空引用异常。失败是由最后一个by(id) 在投影相关顶点的ID 时引起的。如果我删除 Id 并只留下 project('name').by('name') 那么它工作正常。稍后我将尝试使用 Gremlin.Net 连接到 CosmosDB,看看它是否也会发生这种情况,或者它只是 Microsoft.Azure.Graphs.dll 中的一个错误。太糟糕了 Gremlin.Net 无法连接到本地 CosmosDB 模拟器...
    • ...有趣的是,在检索边缘 ID 时不会崩溃!
    • 是的,这绝对是 CosmosDB 的东西 - Gremlin.Net.Driver.Exceptions.ResponseException: ServerError: Object reference not set to an instance of an object. ExceptionType : NullReferenceException Source : Microsoft.Azure.Graphs HResult : 0x80004003 at Microsoft.Azure.Graphs.Runtime.Operators.TraversalOperator.&lt;NextAsync&gt;d__11.MoveNext()
    • @DejanJanjušević 您能否提供您运行的复制查询,该查询出现异常?在 Stephen 的示例中,我没有看到对 by(id()) 的引用,只有 by(id),但从表面上看,这听起来像是 CosmosDB Graph 中的一个错误。
    • @DejanJanjušević 谢谢,我会调查的。
    猜你喜欢
    • 1970-01-01
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多