package main type termKey struct { termType string key string } type graphAccumulator struct { includeBNodes bool nodeLimit int nodeIDByKey map[termKey]uint32 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), 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) addBindings(bindings []map[string]sparqlTerm) { for _, b := range bindings { sTerm := b["s"] oTerm := b["o"] pTerm := b["p"] sid, okS := g.getOrAddNode(sTerm) oid, okO := g.getOrAddNode(oTerm) if !okS || !okO { continue } predID, ok := g.preds.GetOrAdd(pTerm.Value) if !ok { continue } 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 }