105 lines
2.2 KiB
Go
105 lines
2.2 KiB
Go
package main
|
|
|
|
type termKey struct {
|
|
termType string
|
|
key string
|
|
}
|
|
|
|
type edgeKey struct {
|
|
source uint32
|
|
target uint32
|
|
predicateID uint32
|
|
}
|
|
|
|
type graphAccumulator struct {
|
|
includeBNodes bool
|
|
nodeLimit int
|
|
nodeIDByKey map[termKey]uint32
|
|
seenEdges map[edgeKey]struct{}
|
|
nodes []Node
|
|
edges []Edge
|
|
preds *PredicateDict
|
|
}
|
|
|
|
func newGraphAccumulator(nodeLimit int, includeBNodes bool, edgeCapHint int, preds *PredicateDict) *graphAccumulator {
|
|
if preds == nil {
|
|
preds = NewPredicateDict(nil)
|
|
}
|
|
return &graphAccumulator{
|
|
includeBNodes: includeBNodes,
|
|
nodeLimit: nodeLimit,
|
|
nodeIDByKey: make(map[termKey]uint32),
|
|
seenEdges: make(map[edgeKey]struct{}, min(edgeCapHint, 4096)),
|
|
nodes: make([]Node, 0, min(nodeLimit, 4096)),
|
|
edges: make([]Edge, 0, min(edgeCapHint, 4096)),
|
|
preds: preds,
|
|
}
|
|
}
|
|
|
|
func (g *graphAccumulator) getOrAddNode(term sparqlTerm) (uint32, bool) {
|
|
if term.Type == "" || term.Value == "" {
|
|
return 0, false
|
|
}
|
|
if term.Type == "literal" {
|
|
return 0, false
|
|
}
|
|
|
|
var key termKey
|
|
var node Node
|
|
|
|
if term.Type == "bnode" {
|
|
if !g.includeBNodes {
|
|
return 0, false
|
|
}
|
|
key = termKey{termType: "bnode", key: term.Value}
|
|
node = Node{ID: 0, TermType: "bnode", IRI: "_:" + term.Value, Label: nil, X: 0, Y: 0}
|
|
} else {
|
|
key = termKey{termType: "uri", key: term.Value}
|
|
node = Node{ID: 0, TermType: "uri", IRI: term.Value, Label: nil, X: 0, Y: 0}
|
|
}
|
|
|
|
if existing, ok := g.nodeIDByKey[key]; ok {
|
|
return existing, true
|
|
}
|
|
if len(g.nodes) >= g.nodeLimit {
|
|
return 0, false
|
|
}
|
|
nid := uint32(len(g.nodes))
|
|
g.nodeIDByKey[key] = nid
|
|
node.ID = nid
|
|
g.nodes = append(g.nodes, node)
|
|
return nid, true
|
|
}
|
|
|
|
func (g *graphAccumulator) addTripleBinding(binding sparqlTripleBinding) {
|
|
sid, okS := g.getOrAddNode(binding.S)
|
|
oid, okO := g.getOrAddNode(binding.O)
|
|
if !okS || !okO {
|
|
return
|
|
}
|
|
|
|
predID, ok := g.preds.GetOrAdd(binding.P.Value)
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
key := edgeKey{source: sid, target: oid, predicateID: predID}
|
|
if _, seen := g.seenEdges[key]; seen {
|
|
return
|
|
}
|
|
g.seenEdges[key] = struct{}{}
|
|
|
|
g.edges = append(g.edges, Edge{
|
|
Source: sid,
|
|
Target: oid,
|
|
PredicateID: predID,
|
|
})
|
|
}
|
|
|
|
func min(a, b int) int {
|
|
if a < b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|