// CALL procedure kernels: dispatch to the engine's analytics and index // kernels through the Native capability (the per-row crossing sink lives // in stream.go). Per-node procedures cross each input row with one row per // node id (NodeSlot = the node, ValueSlot = its scalar); the index-backed // search procedures yield one row per hit node in ascending id order.
package exec import ( chickpeas ) // perNodeValues is the per-node scalar vector for a node-analytics // procedure, indexed by node id; ok is false for the search procedures. // Value kinds mirror the Rust engine exactly: components as Int, scores // and distances-with-weights as Float, BFS hop distances as Int with // MaxInt64 for unreachable nodes. func perNodeValues( *plan.CallProc, *chickpeas.Snapshot) ([]value.Value, bool) { switch .Kind { case plan.ProcWcc: return intValues(.WCCVia(.Match(.RelType), .Direction)), true case plan.ProcWccAll: return intValues(.WCC()), true case plan.ProcBfs: := chickpeas.Both if .Directed { = chickpeas.Outgoing } := .BFSDistances(.Source, , chickpeas.MatchAll(), chickpeas.NoMaxDepth) := make([]value.Value, .CSRIDSpace()) for := range { if , := [graph.NodeID()]; { [] = value.Int(int64()) } else { // An unreachable node has no distance entry. [] = value.Int(math.MaxInt64) } } return , true case plan.ProcPageRank: return floatValues(.PageRank(.Directed, .Damping, int(.Iters))), true case plan.ProcCdlp: := cdlpInit(, .SeedProp) return intValues(.CDLPSeeded(.Directed, int(.Iters), )), true case plan.ProcLcc: return floatValues(.LCC(.Directed)), true case plan.ProcSssp: := "" if .Weighted { = "weight" } return floatValues(.SSSP(.Source, .Directed, )), true } return nil, false } func intValues( []uint32) []value.Value { := make([]value.Value, len()) for , := range { [] = value.Int(int64()) } return } func floatValues( []float64) []value.Value { := make([]value.Value, len()) for , := range { [] = value.Float() } return } // cdlpInit seeds each node's initial CDLP label from its seedProp integer // property (a missing value falls back to the dense id); no seed property // (or a non-integer column) seeds with dense node ids. func cdlpInit( *chickpeas.Snapshot, string) []uint32 { := .CSRIDSpace() := make([]uint32, ) var chickpeas.I64Col := false if != "" { if , := .Col(); && .Dtype() == chickpeas.DtypeI64 { = .I64() = true } } for := uint32(0); < ; ++ { [] = if { if , := .Get(); { [] = uint32() } } } return } // callSearchHits is the node hit-set for an index-backed search procedure. func callSearchHits( *plan.CallProc, *chickpeas.Snapshot) *nodeset.Set { switch .Kind { case plan.ProcFtsSearch: return .FullTextSearch(.Label, .Field, .Query) case plan.ProcGeoWithinRadius: return .GeoWithinRadius(.Label, .LatField, .LonField, .Lat, .Lon, .Km) default: // plan.ProcGeoWithinBBox return .GeoWithinBBox(.Label, .LatField, .LonField, .MinLat, .MinLon, .MaxLat, .MaxLon) } } // callResults computes a resolved procedure's result set in the shape its // kind emits: propagation rows, a per-node scalar vector, or a search // hit-set iteration. func callResults( *plan.CallProc, *chickpeas.Snapshot) ([]value.Value, func(func(graph.NodeID) bool), []chickpeas.PropagateResult) { if .Kind == plan.ProcPropagate { return nil, nil, callPropagateRows(, ) } if , := perNodeValues(, ); { return , nil, nil } if := callSearchHits(, ); != nil { return nil, .Iter(), nil } return nil, nil, nil } // callPropagateRows runs first-claim value propagation for a resolved // algo.propagate call; one output row per reached node. func callPropagateRows( *plan.CallProc, *chickpeas.Snapshot) []chickpeas.PropagateResult { := make([]chickpeas.PropagateSeed, len(.Seeds)) for , := range .Seeds { [] = chickpeas.PropagateSeed{Node: , Value: .SeedVals[]} } return .PropagateBFS(, chickpeas.PropagateOpts{ RelTypes: .RelTypes, Direction: .Direction, MaxDepth: .MaxDepth, ValueProp: .ValueProp, Desc: .Desc, TruncLimit: .TruncLimit, MinValue: .MinValue, FilterProp: .FilterProp, FilterMin: .FilterMin, FilterMax: .FilterMax, }) }