the-algorithm/home-mixer/server/src/main/scala/com/twitter/home_mixer/functional_component/feature_hydrator/RetweetSourceTweetFeatureHy...

77 lines
3.1 KiB
Scala

package com.twitter.home_mixer.functional_component.feature_hydrator
import com.twitter.home_mixer.model.HomeFeatures._
import com.twitter.product_mixer.component_library.candidate_source.timeline_ranker.TimelineRankerInNetworkSourceTweetsByTweetIdMapFeature
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.identifier.FeatureHydratorIdentifier
import com.twitter.product_mixer.core.pipeline.PipelineQuery
import com.twitter.search.common.features.thriftscala.ThriftTweetFeatures
import com.twitter.stitch.Stitch
import com.twitter.timelineranker.thriftscala.CandidateTweet
object SourceTweetEarlybirdFeature extends Feature[TweetCandidate, Option[ThriftTweetFeatures]]
/**
* Feature Hydrator that bulk hydrates source tweets' features to retweet candidates
*/
object RetweetSourceTweetFeatureHydrator
extends BulkCandidateFeatureHydrator[PipelineQuery, TweetCandidate] {
override val identifier: FeatureHydratorIdentifier = FeatureHydratorIdentifier(
"RetweetSourceTweet")
override val features: Set[Feature[_, _]] = Set(
SourceTweetEarlybirdFeature,
)
private val DefaultFeatureMap = FeatureMapBuilder()
.add(SourceTweetEarlybirdFeature, None)
.build()
override def apply(
query: PipelineQuery,
candidates: Seq[CandidateWithFeatures[TweetCandidate]]
): Stitch[Seq[FeatureMap]] = {
val sourceTweetsByTweetId: Option[Map[Long, CandidateTweet]] = {
query.features.map(
_.getOrElse(
TimelineRankerInNetworkSourceTweetsByTweetIdMapFeature,
Map.empty[Long, CandidateTweet]))
}
/**
* Return DefaultFeatureMap (no-op to candidate) when it is unfeasible to hydrate the
* source tweet's feature to the current candidate: early bird does not return source
* tweets info / candidate is not a retweet / sourceTweetId is not found
*/
Stitch.value {
if (sourceTweetsByTweetId.exists(_.nonEmpty)) {
candidates.map { candidate =>
val candidateIsRetweet = candidate.features.getOrElse(IsRetweetFeature, false)
val sourceTweetId = candidate.features.getOrElse(SourceTweetIdFeature, None)
if (!candidateIsRetweet || sourceTweetId.isEmpty) {
DefaultFeatureMap
} else {
val sourceTweet = sourceTweetsByTweetId.flatMap(_.get(sourceTweetId.get))
if (sourceTweet.nonEmpty) {
val source = sourceTweet.get
FeatureMapBuilder()
.add(SourceTweetEarlybirdFeature, source.features)
.build()
} else {
DefaultFeatureMap
}
}
}
} else {
candidates.map(_ => DefaultFeatureMap)
}
}
}
}