How the User User Graph (UUG) Leverages the Follow Graph for Recommendations
The User User Graph generates "who-to-follow" recommendations by using a user's recent follow actions as weighted seeds for collaborative-filtering traversals through Twitter's in-memory GraphJet engine.
The User User Graph (UUG) is a critical recommendation service within the twitter/the-algorithm repository designed to surface relevant accounts based on social graph connectivity. By analyzing recent follow patterns as high-signal starting points, UUG performs real-time traversals over the follow graph to identify candidates with strong social proof connections to the requesting user.
Seed Selection from the Follow Graph
UUG initiates its recommendation pipeline by extracting seed user IDs directly from the requester’s recent follow activity. When the UserUserGraphCandidateSource receives a recommendation request, it accesses target.recentFollowedUserIds to build the initial traversal set.
In follow-recommendations-service/common/src/main/scala/com/twitter/follow_recommendations/common/candidate_sources/user_user_graph/UserUserGraphCandidateSource.scala (lines 65-73), the candidate source constructs a RecommendUserRequest using these recent follows as the foundation for collaborative filtering. This approach treats accounts the user has recently chosen to follow as implicit interest indicators, creating a personalized subgraph for exploration.
Weighted Seed Mapping and Social Proof
Before traversal begins, UUG converts the raw list of followed users into a weighted map that influences downstream scoring. The source code assigns each seed a DefaultSeedWeight, creating a seedsWithWeights parameter that controls how much influence each starting node exerts during graph propagation.
As shown in lines 68-71 of UserUserGraphCandidateSource.scala, this weighting mechanism ensures that recent follows contribute proportionally to the aggregation of "social proof"—the metric that counts how many of the seed’s followers also engage with candidate users. Higher weights amplify the significance of specific follow relationships during the candidate scoring phase.
GraphJet Traversal and Scoring
Once the weighted seeds are prepared, UUG delegates to the GraphJet in-memory graph engine for high-performance traversal. The service entry point in src/scala/com/twitter/recos/user_user_graph/UserUserGraph.scala (lines 13-18) exposes a Finagle Thrift endpoint that forwards requests to the RecommendUsersHandler.
GraphJet traverses the user-user relationship graph—which encodes follow, favorite, and interaction edges—starting from the weighted seeds. It aggregates scores for candidate users based on the number and cumulative weight of paths connecting the seeds to each candidate. Accounts that appear frequently in the follow networks of the seed users receive higher relevance scores.
After traversal completes, UUG returns RecommendedUser objects sorted by descending score. The candidate source performs final ranking using -_.score (lines 50-53 of UserUserGraphCandidateSource.scala), surfacing users with the strongest follow-graph connectivity to the requester’s recent activity.
Implementation Example
The following Scala code demonstrates how UUG constructs a recommendation request from recent follow data:
import com.twitter.recos.user_user_graph.thriftscala._
import com.twitter.follow_recommendations.common.candidate_sources.user_user_graph._
def buildUugRequest(
requesterId: Long,
recentFollowedIds: Seq[Long],
excludedIds: Set[Long],
maxResults: Int
): RecommendUserRequest = {
val seeds = recentFollowedIds.map(_ -> UserUserGraphCandidateSource.DefaultSeedWeight).toMap
RecommendUserRequest(
requesterId = requesterId,
displayLocation = RecommendUserDisplayLocation.TimelineHome,
seedsWithWeights = seeds,
excludedUserIds = Some(excludedIds),
maxNumResults = Some(maxResults),
maxNumSocialProofs = Some(UserUserGraphCandidateSource.MaxNumSocialProofs),
minUserPerSocialProof = Some(UserUserGraphCandidateSource.MinUserPerSocialProof),
socialProofTypes = Some(Seq(UserUserGraphCandidateSource.SocialProofType))
)
}
To fetch recommendations via the candidate source pipeline:
val candidateSource = inject[UserUserGraphCandidateSource]
val target = UserUserGraphCandidateSource.Target(
userId = Some(requesterId),
recentFollowedUserIds = Some(recentFollowedIds),
excludedUserIds = excludedIds,
params = requestParams
)
val candidatesFut = candidateSource(target) // Returns Stitch[Seq[CandidateUser]]
Key Source Files
-
UserUserGraph.scala(src/scala/com/twitter/recos/user_user_graph/): The Thrift service wrapper that exposes therecommendUsersRPC and delegates toRecommendUsersHandler. -
UserUserGraphCandidateSource.scala(follow-recommendations-service/common/src/main/scala/com/twitter/follow_recommendations/common/candidate_sources/user_user_graph/): Builds theRecommendUserRequestfrom recent follow activity, invokes the UUG fetcher, and converts responses toCandidateUserobjects. -
GraphJet repository: The external high-performance in-memory graph engine linked in the UUG README that powers the actual traversal and scoring logic.
Summary
- UUG uses
recentFollowedUserIdsas weighted traversal seeds to personalize the recommendation space. - The follow graph provides the foundational edge data for seed selection and social proof calculation.
- GraphJet performs fast in-memory traversals over the user-user relationship graph using the weighted seed map.
- Results are ranked by connection strength, prioritizing candidates with multiple high-weight paths from the user's recent follows.
Frequently Asked Questions
How does UUG differ from other candidate sources in the follow recommendations service?
While other candidate sources might rely on content similarity or popularity metrics, UUG specifically leverages the structural properties of the follow graph. It performs collaborative filtering by assuming that users who recently followed similar accounts share interests, making it particularly effective for "who-to-follow" suggestions based on social proximity rather than content analysis.
What determines the weight assigned to each seed user in the follow graph?
UUG assigns a DefaultSeedWeight to every recent follow uniformly during request construction. This weight influences how much each seed contributes to the social proof aggregation during GraphJet traversal. The uniform weighting ensures all recent follows contribute equally to the candidate scoring, though the underlying GraphJet algorithm may apply additional edge-specific weights during traversal.
Can UUG recommendations exclude specific users or account types?
Yes. The RecommendUserRequest accepts an excludedUserIds parameter that prevents specific accounts from appearing in results. The UserUserGraphCandidateSource passes these exclusions directly to the UUG service, ensuring filtered candidates are removed from the final ranked list before returning recommendations to the user.
How does the GraphJet engine handle real-time updates to the follow graph?
GraphJet operates as an in-memory graph engine that ingests real-time interaction edges, including follows and favorites. While the UUG service itself focuses on the traversal logic, GraphJet's architecture supports rapid edge ingestion, allowing the follow graph used for seed selection and traversal to reflect recent user activity with minimal latency.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →