feat: 知识图谱测试api
This commit is contained in:
@@ -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["应用"],
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user