feat: 知识图谱测试api

This commit is contained in:
hhs
2026-04-05 15:03:56 +08:00
parent a7675458a1
commit c500d75b12
11 changed files with 843 additions and 1 deletions
+161
View File
@@ -0,0 +1,161 @@
package services
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
"sync"
"knowledge-graph-backend/models"
)
type DataService struct {
data models.GraphData
mutex sync.RWMutex
filePath string
}
func NewDataService(filePath string) (*DataService, error) {
ds := &DataService{
filePath: filePath,
mutex: sync.RWMutex{},
}
if err := ds.loadData(); err != nil {
return nil, fmt.Errorf("failed to load data: %w", err)
}
return ds, nil
}
func (ds *DataService) loadData() error {
ds.mutex.Lock()
defer ds.mutex.Unlock()
file, err := os.Open(ds.filePath)
if err != nil {
return fmt.Errorf("failed to open data file: %w", err)
}
defer file.Close()
byteValue, err := ioutil.ReadAll(file)
if err != nil {
return fmt.Errorf("failed to read data file: %w", err)
}
if err := json.Unmarshal(byteValue, &ds.data); err != nil {
return fmt.Errorf("failed to parse data file: %w", err)
}
log.Printf("Loaded %d nodes and %d edges from %s",
len(ds.data.Nodes), len(ds.data.Edges), ds.filePath)
return nil
}
func (ds *DataService) GetGraphData() models.GraphData {
ds.mutex.RLock()
defer ds.mutex.RUnlock()
return ds.data
}
func (ds *DataService) GetNodeByID(id string) (models.Node, bool) {
ds.mutex.RLock()
defer ds.mutex.RUnlock()
for _, node := range ds.data.Nodes {
if node.ID == id {
return node, true
}
}
return models.Node{}, false
}
func (ds *DataService) SearchNodes(query string) []models.Node {
ds.mutex.RLock()
defer ds.mutex.RUnlock()
if query == "" {
return []models.Node{}
}
searchLower := strings.ToLower(query)
var results []models.Node
for _, node := range ds.data.Nodes {
labelMatch := strings.Contains(strings.ToLower(node.Label), searchLower)
idMatch := strings.Contains(strings.ToLower(node.ID), searchLower)
typeMatch := node.Type != "" && strings.Contains(strings.ToLower(node.Type), searchLower)
if labelMatch || idMatch || typeMatch {
results = append(results, node)
}
}
return results
}
func (ds *DataService) GetNeighbors(nodeID string) (models.NeighborResponse, bool) {
ds.mutex.RLock()
defer ds.mutex.RUnlock()
_, exists := ds.GetNodeByID(nodeID)
if !exists {
return models.NeighborResponse{}, false
}
var neighborIDs []string
var relatedEdges []models.Edge
for _, edge := range ds.data.Edges {
if edge.Source == nodeID {
neighborIDs = append(neighborIDs, edge.Target)
relatedEdges = append(relatedEdges, edge)
} else if edge.Target == nodeID {
neighborIDs = append(neighborIDs, edge.Source)
relatedEdges = append(relatedEdges, edge)
}
}
var neighborNodes []models.Node
for _, node := range ds.data.Nodes {
for _, neighborID := range neighborIDs {
if node.ID == neighborID {
neighborNodes = append(neighborNodes, node)
break
}
}
}
return models.NeighborResponse{
Nodes: neighborNodes,
Edges: relatedEdges,
}, true
}
func (ds *DataService) ReloadData() error {
return ds.loadData()
}
func (ds *DataService) GetStats() map[string]int {
ds.mutex.RLock()
defer ds.mutex.RUnlock()
typeCounts := make(map[string]int)
for _, node := range ds.data.Nodes {
if node.Type != "" {
typeCounts[node.Type]++
}
}
return map[string]int{
"totalNodes": len(ds.data.Nodes),
"totalEdges": len(ds.data.Edges),
"conceptNodes": typeCounts["概念"],
"toolNodes": typeCounts["工具"],
"applicationNodes": typeCounts["应用"],
}
}