the-algorithm/home-mixer/server/src/main/scala/com/twitter/home_mixer/functional_component/feature_hydrator/UtegFeatureHydrator.scala
twitter-team ef4c5eb65e Twitter Recommendation Algorithm
Please note we have force-pushed a new initial commit in order to remove some publicly-available Twitter user information. Note that this process may be required in the future.
2023-03-31 17:36:31 -05:00

89 lines
3.9 KiB
Scala

package com.twitter.home_mixer.functional_component.feature_hydrator
import com.twitter.home_mixer.model.HomeFeatures.FavoritedByUserIdsFeature
import com.twitter.home_mixer.model.HomeFeatures.InReplyToTweetIdFeature
import com.twitter.home_mixer.model.HomeFeatures.RealGraphInNetworkScoresFeature
import com.twitter.home_mixer.model.HomeFeatures.RepliedByEngagerIdsFeature
import com.twitter.home_mixer.model.HomeFeatures.RetweetedByEngagerIdsFeature
import com.twitter.home_mixer.model.HomeFeatures.SourceTweetIdFeature
import com.twitter.home_mixer.param.HomeMixerInjectionNames.UtegSocialProofRepository
import com.twitter.product_mixer.component_library.model.candidate.TweetCandidate
import com.twitter.product_mixer.core.feature.Feature
import com.twitter.product_mixer.core.feature.featuremap.FeatureMap
import com.twitter.product_mixer.core.feature.featuremap.FeatureMapBuilder
import com.twitter.product_mixer.core.functional_component.feature_hydrator.BulkCandidateFeatureHydrator
import com.twitter.product_mixer.core.model.common.CandidateWithFeatures
import com.twitter.product_mixer.core.model.common.Conditionally
import com.twitter.product_mixer.core.model.common.identifier.FeatureHydratorIdentifier
import com.twitter.product_mixer.core.pipeline.PipelineQuery
import com.twitter.recos.recos_common.{thriftscala => rc}
import com.twitter.recos.user_tweet_entity_graph.{thriftscala => uteg}
import com.twitter.servo.keyvalue.KeyValueResult
import com.twitter.servo.repository.KeyValueRepository
import com.twitter.stitch.Stitch
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@Singleton
class UtegFeatureHydrator @Inject() (
@Named(UtegSocialProofRepository) client: KeyValueRepository[
(Seq[Long], (Long, Map[Long, Double])),
Long,
uteg.TweetRecommendation
]) extends BulkCandidateFeatureHydrator[PipelineQuery, TweetCandidate]
with Conditionally[PipelineQuery] {
override val identifier: FeatureHydratorIdentifier = FeatureHydratorIdentifier("Uteg")
override val features: Set[Feature[_, _]] = Set(
FavoritedByUserIdsFeature,
RetweetedByEngagerIdsFeature,
RepliedByEngagerIdsFeature
)
override def onlyIf(query: PipelineQuery): Boolean = query.features
.exists(_.getOrElse(RealGraphInNetworkScoresFeature, Map.empty[Long, Double]).nonEmpty)
override def apply(
query: PipelineQuery,
candidates: Seq[CandidateWithFeatures[TweetCandidate]]
): Stitch[Seq[FeatureMap]] = {
val seedUserWeights = query.features.map(_.get(RealGraphInNetworkScoresFeature)).get
val sourceTweetIds = candidates.flatMap(_.features.getOrElse(SourceTweetIdFeature, None))
val inReplyToTweetIds = candidates.flatMap(_.features.getOrElse(InReplyToTweetIdFeature, None))
val tweetIds = candidates.map(_.candidate.id)
val tweetIdsToSend = (tweetIds ++ sourceTweetIds ++ inReplyToTweetIds).distinct
val utegQuery = (tweetIdsToSend, (query.getRequiredUserId, seedUserWeights))
Stitch
.callFuture(client(utegQuery))
.map(handleResponse(candidates, _))
}
private def handleResponse(
candidates: Seq[CandidateWithFeatures[TweetCandidate]],
results: KeyValueResult[Long, uteg.TweetRecommendation],
): Seq[FeatureMap] = {
candidates.map { candidate =>
val candidateProof = results(candidate.candidate.id).toOption.flatten
val sourceProof = candidate.features
.getOrElse(SourceTweetIdFeature, None).flatMap(results(_).toOption.flatten)
val proofs = Seq(candidateProof, sourceProof).flatten.map(_.socialProofByType)
val favoritedBy = proofs.flatMap(_.get(rc.SocialProofType.Favorite)).flatten
val retweetedBy = proofs.flatMap(_.get(rc.SocialProofType.Retweet)).flatten
val repliedBy = proofs.flatMap(_.get(rc.SocialProofType.Reply)).flatten
FeatureMapBuilder()
.add(FavoritedByUserIdsFeature, favoritedBy)
.add(RetweetedByEngagerIdsFeature, retweetedBy)
.add(RepliedByEngagerIdsFeature, repliedBy)
.build()
}
}
}