32bit Node ID

This commit is contained in:
Oxy8
2026-03-06 16:10:52 -03:00
parent 3c487d088b
commit a0c5bec19f
11 changed files with 46 additions and 51 deletions

View File

@@ -1,4 +1,5 @@
FROM golang:1.22-alpine AS builder ARG GO_VERSION=1.24
FROM golang:${GO_VERSION}-alpine AS builder
WORKDIR /src WORKDIR /src

View File

@@ -15,10 +15,10 @@ func graphFromSparqlBindings(
nodeLimit int, nodeLimit int,
includeBNodes bool, includeBNodes bool,
) (nodes []Node, edges []Edge) { ) (nodes []Node, edges []Edge) {
nodeIDByKey := map[termKey]int{} nodeIDByKey := map[termKey]uint32{}
nodeMeta := make([]termMeta, 0, min(nodeLimit, 4096)) nodeMeta := make([]termMeta, 0, min(nodeLimit, 4096))
getOrAdd := func(term sparqlTerm) (int, bool) { getOrAdd := func(term sparqlTerm) (uint32, bool) {
if term.Type == "" || term.Value == "" { if term.Type == "" || term.Value == "" {
return 0, false return 0, false
} }
@@ -46,7 +46,7 @@ func graphFromSparqlBindings(
if len(nodeMeta) >= nodeLimit { if len(nodeMeta) >= nodeLimit {
return 0, false return 0, false
} }
nid := len(nodeMeta) nid := uint32(len(nodeMeta))
nodeIDByKey[key] = nid nodeIDByKey[key] = nid
nodeMeta = append(nodeMeta, meta) nodeMeta = append(nodeMeta, meta)
return nid, true return nid, true
@@ -78,7 +78,7 @@ func graphFromSparqlBindings(
nodes = make([]Node, len(nodeMeta)) nodes = make([]Node, len(nodeMeta))
for i, m := range nodeMeta { for i, m := range nodeMeta {
nodes[i] = Node{ nodes[i] = Node{
ID: i, ID: uint32(i),
TermType: m.termType, TermType: m.termType,
IRI: m.iri, IRI: m.iri,
Label: nil, Label: nil,

View File

@@ -40,7 +40,7 @@ func fetchGraphSnapshot(
// Layout: invert edges for hierarchy (target -> source). // Layout: invert edges for hierarchy (target -> source).
hierEdges := make([][2]int, 0, len(edges)) hierEdges := make([][2]int, 0, len(edges))
for _, e := range edges { for _, e := range edges {
hierEdges = append(hierEdges, [2]int{e.Target, e.Source}) hierEdges = append(hierEdges, [2]int{int(e.Target), int(e.Source)})
} }
layers, cycleErr := levelSynchronousKahnLayers(len(nodes), hierEdges) layers, cycleErr := levelSynchronousKahnLayers(len(nodes), hierEdges)

View File

@@ -9,7 +9,7 @@ type HealthResponse struct {
} }
type Node struct { type Node struct {
ID int `json:"id"` ID uint32 `json:"id"`
TermType string `json:"termType"` // "uri" | "bnode" TermType string `json:"termType"` // "uri" | "bnode"
IRI string `json:"iri"` IRI string `json:"iri"`
Label *string `json:"label"` Label *string `json:"label"`
@@ -18,8 +18,8 @@ type Node struct {
} }
type Edge struct { type Edge struct {
Source int `json:"source"` Source uint32 `json:"source"`
Target int `json:"target"` Target uint32 `json:"target"`
Predicate string `json:"predicate"` Predicate string `json:"predicate"`
} }
@@ -55,27 +55,27 @@ type SparqlQueryRequest struct {
} }
type NeighborsRequest struct { type NeighborsRequest struct {
SelectedIDs []int `json:"selected_ids"` SelectedIDs []uint32 `json:"selected_ids"`
NodeLimit *int `json:"node_limit,omitempty"` NodeLimit *int `json:"node_limit,omitempty"`
EdgeLimit *int `json:"edge_limit,omitempty"` EdgeLimit *int `json:"edge_limit,omitempty"`
GraphQueryID *string `json:"graph_query_id,omitempty"` GraphQueryID *string `json:"graph_query_id,omitempty"`
} }
type NeighborsResponse struct { type NeighborsResponse struct {
SelectedIDs []int `json:"selected_ids"` SelectedIDs []uint32 `json:"selected_ids"`
NeighborIDs []int `json:"neighbor_ids"` NeighborIDs []uint32 `json:"neighbor_ids"`
} }
type SelectionQueryRequest struct { type SelectionQueryRequest struct {
QueryID string `json:"query_id"` QueryID string `json:"query_id"`
SelectedIDs []int `json:"selected_ids"` SelectedIDs []uint32 `json:"selected_ids"`
NodeLimit *int `json:"node_limit,omitempty"` NodeLimit *int `json:"node_limit,omitempty"`
EdgeLimit *int `json:"edge_limit,omitempty"` EdgeLimit *int `json:"edge_limit,omitempty"`
GraphQueryID *string `json:"graph_query_id,omitempty"` GraphQueryID *string `json:"graph_query_id,omitempty"`
} }
type SelectionQueryResponse struct { type SelectionQueryResponse struct {
QueryID string `json:"query_id"` QueryID string `json:"query_id"`
SelectedIDs []int `json:"selected_ids"` SelectedIDs []uint32 `json:"selected_ids"`
NeighborIDs []int `json:"neighbor_ids"` NeighborIDs []uint32 `json:"neighbor_ids"`
} }

View File

@@ -49,9 +49,9 @@ func termKeyFromSparqlTerm(term sparqlTerm, includeBNodes bool) (string, bool) {
return "", false return "", false
} }
func selectedNodesFromIDs(idx Index, selectedIDs []int, includeBNodes bool) ([]NodeRef, map[int]struct{}) { func selectedNodesFromIDs(idx Index, selectedIDs []uint32, includeBNodes bool) ([]NodeRef, map[uint32]struct{}) {
out := make([]NodeRef, 0, len(selectedIDs)) out := make([]NodeRef, 0, len(selectedIDs))
set := make(map[int]struct{}, len(selectedIDs)) set := make(map[uint32]struct{}, len(selectedIDs))
for _, nid := range selectedIDs { for _, nid := range selectedIDs {
n, ok := idx.IDToNode[nid] n, ok := idx.IDToNode[nid]
if !ok { if !ok {
@@ -66,13 +66,13 @@ func selectedNodesFromIDs(idx Index, selectedIDs []int, includeBNodes bool) ([]N
return out, set return out, set
} }
func idsFromBindings(raw []byte, varName string, idx Index, selectedSet map[int]struct{}, includeBNodes bool) ([]int, error) { func idsFromBindings(raw []byte, varName string, idx Index, selectedSet map[uint32]struct{}, includeBNodes bool) ([]uint32, error) {
var res sparqlResponse var res sparqlResponse
if err := json.Unmarshal(raw, &res); err != nil { if err := json.Unmarshal(raw, &res); err != nil {
return nil, fmt.Errorf("failed to parse SPARQL JSON: %w", err) return nil, fmt.Errorf("failed to parse SPARQL JSON: %w", err)
} }
neighborSet := make(map[int]struct{}) neighborSet := make(map[uint32]struct{})
for _, b := range res.Results.Bindings { for _, b := range res.Results.Bindings {
term, ok := b[varName] term, ok := b[varName]
if !ok { if !ok {
@@ -92,11 +92,10 @@ func idsFromBindings(raw []byte, varName string, idx Index, selectedSet map[int]
neighborSet[nid] = struct{}{} neighborSet[nid] = struct{}{}
} }
ids := make([]int, 0, len(neighborSet)) ids := make([]uint32, 0, len(neighborSet))
for nid := range neighborSet { for nid := range neighborSet {
ids = append(ids, nid) ids = append(ids, nid)
} }
sort.Ints(ids) sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] })
return ids, nil return ids, nil
} }

View File

@@ -62,10 +62,10 @@ WHERE {
`, values, bnodeFilter) `, values, bnodeFilter)
} }
func runNeighbors(ctx context.Context, q Querier, idx Index, selectedIDs []int, includeBNodes bool) ([]int, error) { func runNeighbors(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes) selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
if len(selectedNodes) == 0 { if len(selectedNodes) == 0 {
return []int{}, nil return []uint32{}, nil
} }
raw, err := q.Query(ctx, neighborsQuery(selectedNodes, includeBNodes)) raw, err := q.Query(ctx, neighborsQuery(selectedNodes, includeBNodes))
@@ -74,4 +74,3 @@ func runNeighbors(ctx context.Context, q Querier, idx Index, selectedIDs []int,
} }
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes) return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
} }

View File

@@ -40,10 +40,10 @@ WHERE {
`, values, bnodeFilter) `, values, bnodeFilter)
} }
func runSubclasses(ctx context.Context, q Querier, idx Index, selectedIDs []int, includeBNodes bool) ([]int, error) { func runSubclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes) selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
if len(selectedNodes) == 0 { if len(selectedNodes) == 0 {
return []int{}, nil return []uint32{}, nil
} }
raw, err := q.Query(ctx, subclassesQuery(selectedNodes, includeBNodes)) raw, err := q.Query(ctx, subclassesQuery(selectedNodes, includeBNodes))
@@ -52,4 +52,3 @@ func runSubclasses(ctx context.Context, q Querier, idx Index, selectedIDs []int,
} }
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes) return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
} }

View File

@@ -40,10 +40,10 @@ WHERE {
`, values, bnodeFilter) `, values, bnodeFilter)
} }
func runSuperclasses(ctx context.Context, q Querier, idx Index, selectedIDs []int, includeBNodes bool) ([]int, error) { func runSuperclasses(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error) {
selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes) selectedNodes, selectedSet := selectedNodesFromIDs(idx, selectedIDs, includeBNodes)
if len(selectedNodes) == 0 { if len(selectedNodes) == 0 {
return []int{}, nil return []uint32{}, nil
} }
raw, err := q.Query(ctx, superclassesQuery(selectedNodes, includeBNodes)) raw, err := q.Query(ctx, superclassesQuery(selectedNodes, includeBNodes))
@@ -52,4 +52,3 @@ func runSuperclasses(ctx context.Context, q Querier, idx Index, selectedIDs []in
} }
return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes) return idsFromBindings(raw, "nbr", idx, selectedSet, includeBNodes)
} }

View File

@@ -7,14 +7,14 @@ type Querier interface {
} }
type NodeRef struct { type NodeRef struct {
ID int ID uint32
TermType string // "uri" | "bnode" TermType string // "uri" | "bnode"
IRI string IRI string
} }
type Index struct { type Index struct {
IDToNode map[int]NodeRef IDToNode map[uint32]NodeRef
KeyToID map[string]int KeyToID map[string]uint32
} }
type Meta struct { type Meta struct {
@@ -24,6 +24,5 @@ type Meta struct {
type Definition struct { type Definition struct {
Meta Meta Meta Meta
Run func(ctx context.Context, q Querier, idx Index, selectedIDs []int, includeBNodes bool) ([]int, error) Run func(ctx context.Context, q Querier, idx Index, selectedIDs []uint32, includeBNodes bool) ([]uint32, error)
} }

View File

@@ -12,16 +12,16 @@ func runSelectionQuery(
sparql *AnzoGraphClient, sparql *AnzoGraphClient,
snapshot GraphResponse, snapshot GraphResponse,
queryID string, queryID string,
selectedIDs []int, selectedIDs []uint32,
includeBNodes bool, includeBNodes bool,
) ([]int, error) { ) ([]uint32, error) {
def, ok := selectionqueries.Get(queryID) def, ok := selectionqueries.Get(queryID)
if !ok { if !ok {
return nil, fmt.Errorf("unknown query_id: %s", queryID) return nil, fmt.Errorf("unknown query_id: %s", queryID)
} }
idToNode := make(map[int]selectionqueries.NodeRef, len(snapshot.Nodes)) idToNode := make(map[uint32]selectionqueries.NodeRef, len(snapshot.Nodes))
keyToID := make(map[string]int, len(snapshot.Nodes)) keyToID := make(map[string]uint32, len(snapshot.Nodes))
for _, n := range snapshot.Nodes { for _, n := range snapshot.Nodes {
nr := selectionqueries.NodeRef{ID: n.ID, TermType: n.TermType, IRI: n.IRI} nr := selectionqueries.NodeRef{ID: n.ID, TermType: n.TermType, IRI: n.IRI}
idToNode[n.ID] = nr idToNode[n.ID] = nr
@@ -30,4 +30,3 @@ func runSelectionQuery(
return def.Run(ctx, sparql, selectionqueries.Index{IDToNode: idToNode, KeyToID: keyToID}, selectedIDs, includeBNodes) return def.Run(ctx, sparql, selectionqueries.Index{IDToNode: idToNode, KeyToID: keyToID}, selectedIDs, includeBNodes)
} }

View File

@@ -189,7 +189,7 @@ func (s *APIServer) handleSelectionQuery(w http.ResponseWriter, r *http.Request)
writeJSON(w, http.StatusOK, SelectionQueryResponse{ writeJSON(w, http.StatusOK, SelectionQueryResponse{
QueryID: req.QueryID, QueryID: req.QueryID,
SelectedIDs: req.SelectedIDs, SelectedIDs: req.SelectedIDs,
NeighborIDs: []int{}, NeighborIDs: []uint32{},
}) })
return return
} }
@@ -247,7 +247,7 @@ func (s *APIServer) handleNeighbors(w http.ResponseWriter, r *http.Request) {
return return
} }
if len(req.SelectedIDs) == 0 { if len(req.SelectedIDs) == 0 {
writeJSON(w, http.StatusOK, NeighborsResponse{SelectedIDs: req.SelectedIDs, NeighborIDs: []int{}}) writeJSON(w, http.StatusOK, NeighborsResponse{SelectedIDs: req.SelectedIDs, NeighborIDs: []uint32{}})
return return
} }