Files
fuzzygraph/search.go
T

107 lines
2.4 KiB
Go

package main
import (
"fmt"
"math"
"math/rand/v2"
ops "fn-registry/fn_operations"
)
// searchEntitiesFTS searches entities using FTS and returns matching entities.
func searchEntitiesFTS(db *ops.DB, query string) ([]ops.Entity, error) {
if query == "" {
return db.ListEntities("", "")
}
return db.SearchEntities(query, "")
}
// searchGraph returns a GraphData subgraph containing matching entities and their direct relations.
func searchGraph(db *ops.DB, query string) (GraphData, error) {
matches, err := searchEntitiesFTS(db, query)
if err != nil {
return GraphData{}, fmt.Errorf("searching entities: %w", err)
}
if len(matches) == 0 {
return GraphData{}, nil
}
matchIDs := map[string]bool{}
for _, e := range matches {
matchIDs[e.ID] = true
}
// Get all relations and filter to those touching matched entities
allRelations, err := db.ListRelations("")
if err != nil {
return GraphData{}, err
}
// Collect neighbor IDs
neighborIDs := map[string]bool{}
var subRels []ops.Relation
for _, r := range allRelations {
if matchIDs[r.FromEntity] || matchIDs[r.ToEntity] {
subRels = append(subRels, r)
neighborIDs[r.FromEntity] = true
neighborIDs[r.ToEntity] = true
}
}
// Merge match IDs and neighbor IDs
for id := range matchIDs {
neighborIDs[id] = true
}
// Get all entities in the subgraph
allEntities, err := db.ListEntities("", "")
if err != nil {
return GraphData{}, err
}
degree := map[string]int{}
for _, r := range subRels {
degree[r.FromEntity]++
degree[r.ToEntity]++
}
nodes := make([]GraphNode, 0)
for _, e := range allEntities {
if !neighborIDs[e.ID] {
continue
}
color, ok := entityTypeColors[e.TypeRef]
if !ok {
color = "#95a5a6"
}
size := 8.0 + math.Min(float64(degree[e.ID])*2.0, 20.0)
if rs, ok := e.Metadata["risk_score"]; ok {
if v, ok := toFloat64(rs); ok {
size += v * 0.1
}
}
nodes = append(nodes, GraphNode{
ID: e.ID, Label: e.Name, Type: e.TypeRef,
Color: color, Size: size,
X: rand.Float64()*100 - 50, Y: rand.Float64()*100 - 50,
Extra: e.Metadata,
})
}
edges := make([]GraphEdge, 0)
for _, r := range subRels {
w := 1.0
if r.Weight != nil {
w = *r.Weight
}
edges = append(edges, GraphEdge{
ID: r.ID, Source: r.FromEntity, Target: r.ToEntity,
Label: r.Name, Color: "#ffffff30",
Size: math.Max(w*3, 0.5), Type: "arrow",
})
}
return GraphData{Nodes: nodes, Edges: edges}, nil
}