Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

49 lines
1.8 KiB
Go

package mcp
import (
"github.com/zzet/gortex/internal/analysis"
)
// personalizedPageRank runs a Random-Walk-with-Restart (Personalized
// PageRank) from the given seed node IDs over the adjacency snapshot
// and returns each reachable node's proximity score. It is the seam the
// rerank pipeline's ProximitySignal (and context_closure's proximity
// mode) reach centrality through.
//
// Walks flow through a Merkle-keyed cache (see ppr_cache.go) so repeated
// walks on an unchanged graph — or on packages that did not change
// between snapshots — return instantly instead of re-iterating the whole
// CSR. The cache is bypassed when disabled (GORTEX_PPR_CACHE_DISABLE) or
// when the snapshot has no package roots.
func (s *Server) personalizedPageRank(snap *analysis.AdjacencySnapshot, seeds []string) map[string]float64 {
if snap == nil || len(seeds) == 0 {
return nil
}
cache := s.pprCache
// topK caps the walk to its highest-scoring nodes before it is cached,
// so a single retained entry stays a few hundred KB instead of a full-
// graph-sized map. Applied on both paths so a cached and an uncached
// walk return the same result.
topK := pprCacheDefaultTopK
if cache != nil {
topK = cache.topK
}
if cache == nil || !cache.enabled {
return snap.PersonalizedPageRankTopK(seeds, 0, topK)
}
// Merkle-keyed walk cache: the key embeds the per-package content
// roots the walk depends on, so an unchanged walk hits even across
// a snapshot rebuild, and only a walk touching a changed package
// recomputes. An empty key (no package roots, or no seed resolves)
// falls through to an uncached walk.
key := snap.WalkCacheKey(seeds, 0)
if key != "" {
if scores, ok := cache.get(key); ok {
return scores
}
}
scores := snap.PersonalizedPageRankTopK(seeds, 0, topK)
cache.put(key, scores)
return scores
}