Is there a mechanism by which an Edge can be addressed and used as if it is a Vertex?

26 views
Skip to first unread message

Jack Park

unread,
Feb 1, 2020, 4:05:35 PM2/1/20
to ArangoDB
That may sound like a strange question, but here's a somewhat trivial example:

Suppose this triple
{ A, cause, B  }
And suppose this triple
{ D, cause, B  }

Suppose it is determined that the first triple contradicts the second one.
One approach is to (somehow) reify each triple as Vertex objects, then link them with a "contradicts" Edge.

But, what if, in some architecture, it is agreed that the Edge itself, since it references both of its vertices, and has its own "type", in fact, stands as if it is a Vertex representing the entire triple. In that context, you simply wire an Edge between the two Edges.

N'est-ce pas?

Kerry Hormann

unread,
Feb 1, 2020, 6:25:42 PM2/1/20
to ArangoDB
Unfortunately, the DB engine does not let you treat edges as nodes.  I suspect it breaks the math used for traversal and shortest path negotiation.

However, there might be several ways to solve this problem, although it's hard to say for sure without knowing more about your data model.  I did a few tests, and although it might not be possible to solve with a single traversal, there are options.

My data set includes two collections, appropriately named "nodes" and "edges", and a named graph called "nodegraph" that includes these.  Since edges are documents just like nodes but with two special attributes ("_from" and "_to"), I added a "cause" attribute to each edge:
{
"nodes": [
{ "_id": "nodes/a" },
{ "_id": "nodes/b" },
{ "_id": "nodes/c" },
{ "_id": "nodes/d" }
],
"edges": [
{ "_from": "nodes/a", "_to": "nodes/b", "cause": "x" },
{ "_from": "nodes/d", "_to": "nodes/b", "cause": "NOT x" }
]
}

One option would be to find an OUTBOUND path from A, then look up other INCOMING paths from the end vertex ("nodes/b" in this case), filtering-out nodes that also have a conflicting cause ("NOT x" in this example).

FOR v,e IN 1 OUTBOUND 'nodes/a'
    GRAPH 'nodegraph'
    LET myCause = [ e.cause ]
    LET otherCauses = UNIQUE(
        FOR vv,ee IN 1 INBOUND v
            GRAPH 'nodegraph'
            RETURN ee.cause
    )
    FILTER 'NOT x' not in OUTERSECTION(myCause, otherCauses)
    RETURN v


You could also filter out nodes that have multiple causes:

FOR v,e IN 1 OUTBOUND 'nodes/a'
    GRAPH 'nodegraph'
    LET myCause = [ e.cause ]
    LET otherCauses = UNIQUE(
        FOR vv,ee IN 1 INBOUND v
            GRAPH 'nodegraph'
            RETURN ee.cause
    )
    FILTER LENGTH(
        OUTERSECTION(myCause, otherCauses)
    ) == 0
    RETURN v


If this doesn't quite fit, you could insert another "causes" collection in the middle of the edge.  So, instead of a single hop from A to B:

   --edge { cause }-->  B

it would become two hops, with a "cause" node between:

   --edge-->  cause  --edge-->  B


The real trick depends on how you determine that a given node has multiple causes.  The examples here are one way, but maybe you could do it with SHORTEST_PATH and using weights, or even calculating the total weight for a given path (cause "x" has weight "5" whereas cause "NOT x" has an opposite value of "-5").

Jack Park

unread,
Feb 1, 2020, 6:35:42 PM2/1/20
to ArangoDB
Your second approach: make the predicate (Edge) a Vertex and link it with silent links to its actors would, of course, work, but that then demands that there are subject identity properties assigned to that Vertex which make clear its meaning.

I was hoping it could be simpler.
Many thanks
-Jack
Reply all
Reply to author
Forward
0 new messages