Bi-directional Relations #
Problem #
If I have a graph: A <-1-> B <-2-> C
where A
, B
, C
are subjects and objects linked with predicates 1
, 2
(bidirectional).
How can I get C
using a path?
Test data #

Fig 1.: Graph diagram of test data
Show the test data in nquads format
<A> <predicate-1> <B> .
<B> <predicate-1> <A> .
<B> <predicate-2> <C> .
<C> <predicate-2> <B> .
<A1> <predicate-1> <B1> .
<B1> <predicate-1> <A1> .
<B1> <predicate-2> <C1> .
<C1> <predicate-2> <B1> .
<A2> <predicate-1> <B2> .
<B2> <predicate-1> <A2> .
<B2> <predicate-2> <C2> .
<C2> <predicate-2> <B2> .
Gizmo Query #
Simple query #
g.V().Tag("source").Out("<predicate-1>").Out("<predicate-2>").Tag('target').Out("<predicate-2>").Out("<predicate-1>").All()
Results:
{"id":"A","source":"A","target":"C"}
{"id":"A1","source":"A1","target":"C1"}
{"id":"A2","source":"A2","target":"C2"}
Query with bidirectional predicate #
g.V().Tag("source").Both("<predicate-1>").Both("<predicate-2>").Tag('target').All()
Results:
{"id":"C","source":"A","target":"C"}
{"id":"C1","source":"A1","target":"C1"}
{"id":"C2","source":"A2","target":"C2"}
{"id":"C","source":"A","target":"C"}
{"id":"C1","source":"A1","target":"C1"}
{"id":"C2","source":"A2","target":"C2"}
Query with morphism #
// with morphism
forth = g.V().Tag("source").Out("<predicate-1>").Out("<predicate-2>").Tag("target");
back = g.M().Out("<predicate-2>").Out("<predicate-1>")
forth.Follow(back).All()
Results:
{"id":"A","source":"A","target":"C"}
{"id":"A1","source":"A1","target":"C1"}
{"id":"A2","source":"A2","target":"C2"}
Golang Implementation #
Show the source code
package main
import (
"context"
"fmt"
"github.com/cayleygraph/cayley"
"github.com/cayleygraph/quad"
)
func main() {
// Create an in-memory store
store := InitStore()
// Create Quads and uploads to the store
quads := makeQuads()
AddQuadsToStore(store, quads)
// Execute the query
doQuery(store)
}
// Create a mem-store for testing
func InitStore() *cayley.Handle {
store, err := cayley.NewMemoryGraph()
if err != nil {
panic(err)
}
return store
}
func makeQuads() []quad.Quad {
quads := []quad.Quad{}
quads = append(quads, quad.Make("A", "1", "B", ""))
quads = append(quads, quad.Make("B", "1", "A", ""))
quads = append(quads, quad.Make("B", "2", "C", ""))
quads = append(quads, quad.Make("C", "2", "B", ""))
quads = append(quads, quad.Make("A1", "1", "B1", ""))
quads = append(quads, quad.Make("B1", "1", "A1", ""))
quads = append(quads, quad.Make("B1", "2", "C1", ""))
quads = append(quads, quad.Make("C1", "2", "B1", ""))
quads = append(quads, quad.Make("A2", "1", "B2", ""))
quads = append(quads, quad.Make("B2", "1", "A2", ""))
quads = append(quads, quad.Make("B2", "2", "C2", ""))
quads = append(quads, quad.Make("C2", "2", "B2", ""))
return quads
}
func AddQuadsToStore(store *cayley.Handle, quads []quad.Quad) {
for _, q := range quads {
store.AddQuad(q)
}
}
func doQuery(store *cayley.Handle) {
p := cayley.StartPath(store).Tag("source").Out("1").Out("2").Tag("target").Out("2").Out("1")
p.Iterate(context.Background()).EachValue(nil, func(value quad.Value) {
fmt.Printf("%v\n", value)
})
p.Iterate(context.Background()).TagValues(store, func(t map[string]quad.Value) {
fmt.Printf("%v\n", t)
})
}
Results:
"A"
"A1"
"A2"
map[source:"A" target:"C"]
map[source:"A1" target:"C1"]
map[source:"A2" target:"C2"]