gigl.distributed.dist_ppr_sampler#
Attributes#
Classes#
Personalized PageRank (PPR) based distributed neighbor sampler. |
Module Contents#
- class gigl.distributed.dist_ppr_sampler.DistPPRNeighborSampler(*args, alpha=0.5, eps=0.0001, max_ppr_nodes=50, enable_residual_topup=True, num_neighbors_per_hop=100000, degree_tensors, max_fetch_iterations=None, typed_channel_ratios=None, **kwargs)[source]#
Bases:
gigl.distributed.base_sampler.BaseDistNeighborSamplerPersonalized PageRank (PPR) based distributed neighbor sampler.
Extends BaseGiGLSampler (which provides shared input preparation utilities) and overrides _sample_from_nodes with PPR-based neighbor selection.
Instead of uniform random sampling, this sampler uses Personalized PageRank (PPR) scores to select the most relevant neighbors for each seed node. PPR scores are approximated here using the Forward Push algorithm (Andersen et al., 2006).
Residual top-up provides a cheaper way to increase returned sequence volume without lowering
eps. Lowerepsthresholds re-enqueue more low-residual nodes, but also increase push iterations and neighbor-fetch work. Top-up instead fills unused output slots with positive-residual nodes already discovered during Forward Push; these are the nodes that are closest to being re-enqueued if the threshold were lower.This sampler supports both homogeneous and heterogeneous graphs. For heterogeneous graphs, the PPR algorithm traverses across all edge types, switching edge types based on the current node type and the configured edge direction.
Internal execution follows the same shape for regular and typed PPR. Regular PPR owns one C++
PPRForwardPushstate per seed type:drain_queueexposes the next frontier, Python performs the distributed neighbor fetch,push_residualsupdates the state, and C++ extraction emits the final top-k plus residual top-up output. Typed PPR runs onePPRForwardPushtraversal per configured channel. Its typed drain step unions the channel frontiers before the same distributed fetch, pushes results back into the active channel states, and then uses one typed C++ extraction step to apply channel target counts, deduplicate shared candidates, and emit the final typed edge-attribute features.The
edge_indexandedge_attrfields on the output Data/HeteroData objects are populated with PPR seed-to-neighbor relationships (not edges in the original graph).Nis the total number of (seed, neighbor) pairs across all seeds in the batch.- Homogeneous (Data):
data.edge_index:[2, N]int64 — row 0 is local seed indices, row 1 is local neighbor indices.data.edge_attr:[N]float — PPR score for each pair.
Heterogeneous (HeteroData) — one PPR edge type per
(seed_type, neighbor_type)pair, with"ppr"as the relation:data[(seed_type, "ppr", neighbor_type)].edge_index: same format as above.data[(seed_type, "ppr", neighbor_type)].edge_attr: scalar PPR score for regular PPR. For typed PPR, edge attrs are multi-column:[best_score, channel_scores..., channel_presence_bits...]. Scores use the same PPR mass scale as regular scalar PPR output. Channel columns follow the insertion order oftyped_channel_ratios. Column 0 is the scalar best score for consumers that need a single PPR weight.
- Parameters:
alpha (float) – Restart probability (teleport probability back to seed). Higher values keep samples closer to seeds. Typical values: 0.15-0.25.
eps (float) – Convergence threshold. Smaller values give more accurate PPR scores but require more computation. Typical values: 1e-4 to 1e-6.
max_ppr_nodes (int) – Maximum number of nodes to return per seed. If finalized PPR scores produce fewer than this cap and residual top-up is enabled, discovered residual candidates fill the remaining slots with score
ppr_score + residual. Returned nodes are sorted by emitted score, but residual candidates do not displace finalized PPR nodes when finalized scores already fill the cap.enable_residual_topup (bool) – Whether to include residual candidates discovered during Forward Push when fewer than
max_ppr_nodesfinalized PPR scores are available.num_neighbors_per_hop (int) – Maximum number of neighbors to fetch per hop.
typed_channel_ratios (Optional[dict[gigl.distributed.utils.dist_typed_sampler.TypedPPRChannelKey, float]]) –
Optional target proportions for typed PPR traversal channels. If not provided, PPR treats all eligible edge types as one shared traversal space and emits a single scalar PPR score per output row. Keys may be either a single canonical edge type
(src_type, relation, dst_type)or a tuple of canonical edge types. Each key defines one traversal channel that may use only those exact edge types. Edge types may appear in multiple channels when those channels intentionally overlap. Channel order follows the insertion order of this mapping, and typededge_attrchannel columns use that same order. If the mapping is produced from an unordered config source, construct it deterministically before passing it to the sampler. Values are positive ratios that must sum to1.0. The sampler converts ratios to per-channel target counts frommax_ppr_nodes. Finalized PPR candidates and residual top-up candidates both obey these target counts. If the same node appears in multiple channels, it is attributed to the channel where it has the highest emitted PPR score for that seed. If sparse channels or duplicate nodes leave unused target slots, the remaining slots are redistributed globally by score so the returned sequence can still fill up to, but never exceed,max_ppr_nodes. Example:typed_channel_ratios = { ("user", "views", "item"): 0.6, ( ("user", "likes", "item"), ("user", "shares", "item"), ): 0.4, }
With
max_ppr_nodes=200, this example targets 120 nodes attributed to the views channel and 80 nodes attributed to the grouped likes/shares channel. The views channel traverses only("user", "views", "item")edges. The grouped likes/shares channel traverses either likes or shares edges as one channel. Both finalized PPR rows and residual top-up rows fill those same targets. The targets are best-effort rather than strict per-seed guarantees: if a channel cannot provide enough unique candidates, unused slots are filled by the remaining highest-scoring candidates from any channel, up tomax_ppr_nodestotal rows.degree_tensors (Union[torch.Tensor, dict[graphlearn_torch.typing.NodeType, torch.Tensor]]) – Pre-computed total-degree tensors (int32). Homogeneous graphs use a single tensor; heterogeneous graphs use tensors keyed by NodeType. The colocated and graph-store loader paths retrieve these through
DistDataset.degree_tensorand move them to shared memory before worker handoff.max_fetch_iterations (Optional[int])
Initialize the sampler and the one-time sampling-error guard.
GLTDistNeighborSamplerhas no GiGL-owned state; we only add_sampling_error_sentso_send_adaptercan forward at most one poison pill per sampler instance. Initializing it here (rather than lazily) guarantees the failure handler never raisesAttributeError, which GLT’s event loop would swallow the same way it swallows the original sampling exception.