docs/getting-involved/glossary.md
Note: this definitions in this glossary are sequenced so that they build on each other, one to the next, rather than alphabetically.
where triples have the form {subject, predicate, object}, quads would have a form along the lines of {subject, predicate, object, context} source
You can add context or extra values to triples that identifies them and makes it easy to define subgraphs, or named properties. source
From Cayley godoc:
type Quad struct {
Subject Value `json:“subject”`
Predicate Value `json:“predicate”`
Object Value `json:“object”`
Label Value `json:“label,omitempty”`
}
{A, knows, C} you would say in graph terminology that A and C are "vertices" while knows is an "edge". You would also say that A, knows, and C are all "nodes", and they are "linked" to one another by the triple..v() is for "Vertex" in Gizmo, and it is used like pathObject = graph.Vertex([nodeId],[nodeId]...) (see [[path|#path]])Inbound/outbound refers to the direction of a relation via a predicate. In the case of the triple "A follows B", "follows" is an outbound predicate for A and an inbound predicate for B.
In/out predicates can be expressed in a query language, for example using the format resultSet = subject.out(predicate) to discover matching Objects. In the case of the triple "A follows B", A.out(“follows”) would return a set of nodes which contains B. An excellent example of this sort of query format is given in the Gremlin/TinkerPop homepage example:
What are the names of projects that were created by two friends?
g.V().match(
as(“a”).out(“knows”).as(“b”),
as(“a”).out(“created”).as(“c”),
as(“b”).out(“created”).as(“c”),
as(“c”).in(“created”).count().is(2)).
select(“c”).by(“name”)
Direction specifies a node's position within a quad. source
const (
Any Direction = iota
Subject
Predicate
Object
Label
)
Direction is passed to the Get method of a quad to access one of its four parts, see quad.Get(d Direction) Value
The term "Direction" comes about from the concept of traversing a graph. Take for example the triple {A, follows, B} and supposing you "select" the predicate follows. Now you want to traverse the graph, so you move in the Object direction, and you now have B selected. Whereas the high-level path abstraction for queries uses inbound/outbound predicates to represent movement on the graph, the bottom-level iterator mechanic uses Direction.
Paths are just a set of helpers to build a query, but they are not that good for building something more complex. You can try using Shapes for this - it will give you a full control of what the query actually does. source
Path represents either a morphism (a pre-defined path stored for later use), or a concrete path, consisting of a morphism and an underlying QuadStore. source
Underlying code:
type Path struct {
stack []morphism
qs graph.QuadStore
baseContext pathContext
}
type morphism struct {
IsTag bool
Reversal func(*pathContext) (morphism, *pathContext)
Apply applyMorphism
tags []string
}
type applyMorphism func(shape.Shape, *pathContext) (shape.Shape, *pathContext)
So, as previously stated, the path package is just helper methods on top of the shape package.
Morphism is basically a path that is not attached to any particular quadstore or a particular starting point in the graph. Morphisms are meant to be used as a query part that can be applied to other queries to follow a path specified in the Morphism.
A good example will be a FollowRecursive function that will apply a single morphism multiple times to get to all nodes that can be traversed recursively. source
So a graph query is roughly represented as a tree of iterators – things
that implement graph.Iterator. An iterator is (loosely) a stand-in for a
set of things that match a particular portion of the graph. source
g.V(“B”).In(“follows”).All() into an iterator tree:
To restate in pseudo-code; results is what would be returned in successive Next() calls:
var results []quad.Quad
for _, node := range linkTo.subIterator {
for _, quad := range allQuads {
if quad.Get(linkTo.direction) == node {
results = append(results, quad)
}
}
}
To restate in pseudo-code:
for _, node := range linkTo.subIterator {
if theLink.Get(linkTo.direction) == node {
return true
}
}
return false
var results []quad.Value
for _, quad := range hasA.subIterator {
results = append(results, quad.Get(hasA.direction))
}
Contains()
for _, quad := range hasA.subIterator {
if quad.Get(hasA.direction) == theNode {
return true
}
}
return false
Shape represent a query tree shape. source
type Shape interface {
BuildIterator(qs graph.QuadStore) graph.Iterator
Optimize(r Optimizer) (Shape, bool)
}
This is the most interesting part of the query system - it describes how exactly the query looks like. ... This package also describes different query optimizations that are not specific to a backend. ... You can write a query using either Paths, Shapes or raw Iterators... source
A Shape seems to be an abstract representation of a query, a level above Iterators and a level below Paths. You can perform various operations on it (traverse inbound/outbound predicates, find unions and intersections, etc.) and most importantly build a tree of Iterators from it, which will do the mechanical act of processing quads to find results.
In the context of a quad store, a graph.Value. However the backend wishes to implement it, a Value is merely a token to a quad or a node that the backing store itself understands, and the base iterators pass around.
For example, in a very traditional, graphd-style graph, these are int64s (guids of the primitives). In a very direct sort of graph, these could be pointers to structs, or merely quads, or whatever works best for the backing store.
“With reification, we create a metagraph on top of our graph that represents the statement that we have here. We create a new node that represents a statement and points at the subject...” source
Reifying a relationship means viewing it as an entity. The purpose of reifying a relationship is to make it explicit, when additional information needs to be added to it.
Viewing a relationship as an entity, one can say that the entity reifies the relationship. This is called reification of a relationship. Like any other entity, it must be an instance of an entity type. source