ranking

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package ranking provides query-weighted PageRank over the code graph.

Motivation: structural search (search_graph) and semantic search (find_similar_functions) surface candidates, but they don't rank by relevance to a query the way an agent needs for context assembly. PageRank with query-seeded personalization fills that gap — given a natural-language query, it returns the top-K graph entities most relevant to feed into an LLM's context window, typically reducing context tokens by 3-5x vs dumping the full graph.

Algorithm: bidirectional weighted PageRank with personalization.

  • Seed nodes are matched from the query via name + qualified-name tokens (simple tokenizer; embedding-augmented seeds are a future extension).
  • Forward PageRank: column-stochastic transition matrix over outbound edges; propagates rank from seeds to nodes they reference.
  • Reverse PageRank: same graph with edges reversed; propagates rank from seeds back to nodes that reference them.
  • Final score: sum of forward + reverse. Bidirectional fixes the pure-source-collapse behavior that single-direction PageRank exhibits (sources with no inbound personalization go to 0).

Reference: Aider's repo-map (https://aider.chat/2023/10/22/repomap.html) pioneered PageRank over tree-sitter tags as an agent-context primitive. code-review-graph (github.com/tirth8205/code-review-graph) reports 6.8x token reduction with the same pattern.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MatchSeedNodes

func MatchSeedNodes(st *store.Store, project, query string) ([]*store.Node, error)

MatchSeedNodes returns the seed nodes for a query — the subset of project nodes whose Name exactly matches any query token (case- insensitive) or whose QualifiedName contains any token (case- insensitive substring). Used by callers that need just the seeds without running the full PageRank propagation (e.g., the localize package's BFS-from-seeds pattern).

Returns the seed nodes themselves, not their indices. Empty slice if no node matched any token.

func MatchSeedNodesByEmbedding

func MatchSeedNodesByEmbedding(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)

MatchSeedNodesByEmbedding returns the top-K nodes whose embeddings are most cosine-similar to the embedded query. Returns an error wrapping ErrEmbeddingsUnavailable if VOYAGE_API_KEY is not set or the project has no embeddings populated.

func MatchSeedNodesByStrategy

func MatchSeedNodesByStrategy(ctx context.Context, st *store.Store, project, query string, strategy SeedStrategy) ([]*store.Node, error)

MatchSeedNodesByStrategy dispatches to the requested seed strategy. Empty/unknown strategy defaults to hybrid.

Phase B (2026-05-07): when a caller explicitly requests SeedStrategySubstring AND embeddings are available (project has a non-zero embedding count), we route to hybrid instead. Substring on a project with embeddings consistently surfaces PageRank-propagation noise (`Result`, `IntoHandlerError`, `AsCheckOpResult` from cradlepoint-seeded callers) — D1 word-boundary closed seed pollution but did not address propagation pollution. Hybrid's embedding- dominance threshold (>=3 embeddings → drop substring entirely) was measured 10/10 relevant on the same query that produced 4/10 noise on substring. Routing substring callers through hybrid when embeddings are present is strictly an improvement; substring stays available as the explicit fallback when no embeddings exist.

func MatchSeedNodesHybrid

func MatchSeedNodesHybrid(ctx context.Context, st *store.Store, project, query string) ([]*store.Node, error)

MatchSeedNodesHybrid runs both substring and embedding matching and merges the results.

Behavior (D1, 2026-05-07):

  • If embedding returns ≥hybridEmbeddingDominanceThreshold seeds, drop substring seeds entirely. The strong embedding signal is a better intent match; substring at that point is mostly noise.
  • Otherwise, merge: substring seeds first (preserving exact- identifier match priority), embedding seeds appended.

If embedding match fails (e.g., no VOYAGE_API_KEY or no embeddings), returns substring-only results with no error — graceful degradation is more useful than a hard failure for callers who don't know the project's embedding state in advance.

func SeedMatchScore

func SeedMatchScore(node *store.Node, query string) float64

SeedMatchScore preserves lexical seed quality when downstream graph traversal assigns its personalization weights. Exact-name matches retain precedence over qualified-name-only matches, while nodes matching more independent query tokens receive more weight. Embedding-only seeds receive the neutral score 1.

Types

type RankedNode

type RankedNode struct {
	ID            int64   `json:"id"`
	Label         string  `json:"label"`
	Name          string  `json:"name"`
	QualifiedName string  `json:"qualified_name"`
	FilePath      string  `json:"file_path"`
	Score         float64 `json:"score"`
}

RankedNode is one entry in the RankByQuery result.

func RankByQuery

func RankByQuery(st *store.Store, project, query string, topK int) ([]RankedNode, error)

RankByQuery computes query-weighted bidirectional PageRank over the project graph and returns the top-K nodes by relevance, using the substring seed strategy (legacy default — kept for backward compat).

New callers should prefer RankByQueryWithStrategy for the choice of substring / embedding / hybrid seed matching.

The topK parameter is clamped to [1, 200]. The returned slice is sorted by descending score.

func RankByQueryWithStrategy

func RankByQueryWithStrategy(ctx context.Context, st *store.Store, project, query string, topK int, strategy SeedStrategy) ([]RankedNode, error)

RankByQueryWithStrategy is RankByQuery with explicit seed-strategy selection (substring, embedding, or hybrid). Hybrid is the recommended default — it merges substring + embedding seeds, falling back to substring-only if embeddings are unavailable.

type SeedStrategy

type SeedStrategy string

SeedStrategy controls how query → seed-node matching is performed.

const (
	// SeedStrategySubstring is the original behavior: tokens substring-match
	// node Name/QualifiedName. Cheap, no API call, deterministic. Best for
	// queries that contain known identifiers.
	SeedStrategySubstring SeedStrategy = "substring"
	// SeedStrategyEmbedding embeds the query via Voyage and cosine-searches
	// against pre-computed node embeddings. Requires VOYAGE_API_KEY at query
	// time and embeddings populated at index time. Best for natural-language
	// queries that describe intent rather than name symbols.
	SeedStrategyEmbedding SeedStrategy = "embedding"
	// SeedStrategyHybrid runs both and merges the results, deduplicated. The
	// default; gives the union of identifier-exact and intent-similar matches.
	SeedStrategyHybrid SeedStrategy = "hybrid"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL