mirror of
https://github.com/twitter/the-algorithm.git
synced 2024-06-13 06:38:52 +02:00
![twitter-team](/assets/img/avatar_default.png)
Topic Social Proof Service (TSPS) delivers highly relevant topics tailored to a user's interests by analyzing topic preferences, such as following or unfollowing, and employing semantic annotations and other machine learning models.
183 lines
6.7 KiB
Scala
183 lines
6.7 KiB
Scala
package com.twitter.tsp.service
|
|
|
|
import com.twitter.abdecider.ABDeciderFactory
|
|
import com.twitter.abdecider.LoggingABDecider
|
|
import com.twitter.tsp.thriftscala.TspTweetInfo
|
|
import com.twitter.discovery.common.configapi.FeatureContextBuilder
|
|
import com.twitter.finagle.mtls.authentication.ServiceIdentifier
|
|
import com.twitter.finagle.stats.StatsReceiver
|
|
import com.twitter.gizmoduck.thriftscala.LookupContext
|
|
import com.twitter.gizmoduck.thriftscala.QueryFields
|
|
import com.twitter.gizmoduck.thriftscala.User
|
|
import com.twitter.gizmoduck.thriftscala.UserService
|
|
import com.twitter.hermit.store.gizmoduck.GizmoduckUserStore
|
|
import com.twitter.logging.Logger
|
|
import com.twitter.simclusters_v2.common.SemanticCoreEntityId
|
|
import com.twitter.simclusters_v2.common.TweetId
|
|
import com.twitter.simclusters_v2.common.UserId
|
|
import com.twitter.spam.rtf.thriftscala.SafetyLevel
|
|
import com.twitter.stitch.storehaus.StitchOfReadableStore
|
|
import com.twitter.storehaus.ReadableStore
|
|
import com.twitter.strato.client.{Client => StratoClient}
|
|
import com.twitter.timelines.configapi
|
|
import com.twitter.timelines.configapi.CompositeConfig
|
|
import com.twitter.tsp.common.FeatureSwitchConfig
|
|
import com.twitter.tsp.common.FeatureSwitchesBuilder
|
|
import com.twitter.tsp.common.LoadShedder
|
|
import com.twitter.tsp.common.ParamsBuilder
|
|
import com.twitter.tsp.common.RecTargetFactory
|
|
import com.twitter.tsp.common.TopicSocialProofDecider
|
|
import com.twitter.tsp.handlers.TopicSocialProofHandler
|
|
import com.twitter.tsp.stores.LocalizedUttRecommendableTopicsStore
|
|
import com.twitter.tsp.stores.LocalizedUttTopicNameRequest
|
|
import com.twitter.tsp.stores.TopicResponses
|
|
import com.twitter.tsp.stores.TopicSocialProofStore
|
|
import com.twitter.tsp.stores.TopicSocialProofStore.TopicSocialProof
|
|
import com.twitter.tsp.stores.TopicStore
|
|
import com.twitter.tsp.stores.UttTopicFilterStore
|
|
import com.twitter.tsp.thriftscala.TopicSocialProofRequest
|
|
import com.twitter.tsp.thriftscala.TopicSocialProofResponse
|
|
import com.twitter.util.JavaTimer
|
|
import com.twitter.util.Timer
|
|
import javax.inject.Inject
|
|
import javax.inject.Singleton
|
|
import com.twitter.topiclisting.TopicListing
|
|
import com.twitter.topiclisting.utt.UttLocalization
|
|
|
|
@Singleton
|
|
class TopicSocialProofService @Inject() (
|
|
topicSocialProofStore: ReadableStore[TopicSocialProofStore.Query, Seq[TopicSocialProof]],
|
|
tweetInfoStore: ReadableStore[TweetId, TspTweetInfo],
|
|
serviceIdentifier: ServiceIdentifier,
|
|
stratoClient: StratoClient,
|
|
gizmoduck: UserService.MethodPerEndpoint,
|
|
topicListing: TopicListing,
|
|
uttLocalization: UttLocalization,
|
|
decider: TopicSocialProofDecider,
|
|
loadShedder: LoadShedder,
|
|
stats: StatsReceiver) {
|
|
|
|
import TopicSocialProofService._
|
|
|
|
private val statsReceiver = stats.scope("topic-social-proof-management")
|
|
|
|
private val isProd: Boolean = serviceIdentifier.environment == "prod"
|
|
|
|
private val optOutStratoStorePath: String =
|
|
if (isProd) "interests/optOutInterests" else "interests/staging/optOutInterests"
|
|
|
|
private val notInterestedInStorePath: String =
|
|
if (isProd) "interests/notInterestedTopicsGetter"
|
|
else "interests/staging/notInterestedTopicsGetter"
|
|
|
|
private val userOptOutTopicsStore: ReadableStore[UserId, TopicResponses] =
|
|
TopicStore.userOptOutTopicStore(stratoClient, optOutStratoStorePath)(
|
|
statsReceiver.scope("ints_interests_opt_out_store"))
|
|
private val explicitFollowingTopicsStore: ReadableStore[UserId, TopicResponses] =
|
|
TopicStore.explicitFollowingTopicStore(stratoClient)(
|
|
statsReceiver.scope("ints_explicit_following_interests_store"))
|
|
private val userNotInterestedInTopicsStore: ReadableStore[UserId, TopicResponses] =
|
|
TopicStore.notInterestedInTopicsStore(stratoClient, notInterestedInStorePath)(
|
|
statsReceiver.scope("ints_not_interested_in_store"))
|
|
|
|
private lazy val localizedUttRecommendableTopicsStore: ReadableStore[
|
|
LocalizedUttTopicNameRequest,
|
|
Set[
|
|
SemanticCoreEntityId
|
|
]
|
|
] = new LocalizedUttRecommendableTopicsStore(uttLocalization)
|
|
|
|
implicit val timer: Timer = new JavaTimer(true)
|
|
|
|
private lazy val uttTopicFilterStore = new UttTopicFilterStore(
|
|
topicListing = topicListing,
|
|
userOptOutTopicsStore = userOptOutTopicsStore,
|
|
explicitFollowingTopicsStore = explicitFollowingTopicsStore,
|
|
notInterestedTopicsStore = userNotInterestedInTopicsStore,
|
|
localizedUttRecommendableTopicsStore = localizedUttRecommendableTopicsStore,
|
|
timer = timer,
|
|
stats = statsReceiver.scope("UttTopicFilterStore")
|
|
)
|
|
|
|
private lazy val scribeLogger: Option[Logger] = Some(Logger.get("client_event"))
|
|
|
|
private lazy val abDecider: LoggingABDecider =
|
|
ABDeciderFactory(
|
|
abDeciderYmlPath = configRepoDirectory + "/abdecider/abdecider.yml",
|
|
scribeLogger = scribeLogger,
|
|
decider = None,
|
|
environment = Some("production"),
|
|
).buildWithLogging()
|
|
|
|
private val builder: FeatureSwitchesBuilder = FeatureSwitchesBuilder(
|
|
statsReceiver = statsReceiver.scope("featureswitches-v2"),
|
|
abDecider = abDecider,
|
|
featuresDirectory = "features/topic-social-proof/main",
|
|
configRepoDirectory = configRepoDirectory,
|
|
addServiceDetailsFromAurora = !serviceIdentifier.isLocal,
|
|
fastRefresh = !isProd
|
|
)
|
|
|
|
private lazy val overridesConfig: configapi.Config = {
|
|
new CompositeConfig(
|
|
Seq(
|
|
FeatureSwitchConfig.config
|
|
)
|
|
)
|
|
}
|
|
|
|
private val featureContextBuilder: FeatureContextBuilder = FeatureContextBuilder(builder.build())
|
|
|
|
private val paramsBuilder: ParamsBuilder = ParamsBuilder(
|
|
featureContextBuilder,
|
|
abDecider,
|
|
overridesConfig,
|
|
statsReceiver.scope("params")
|
|
)
|
|
|
|
private val userStore: ReadableStore[UserId, User] = {
|
|
val queryFields: Set[QueryFields] = Set(
|
|
QueryFields.Profile,
|
|
QueryFields.Account,
|
|
QueryFields.Roles,
|
|
QueryFields.Discoverability,
|
|
QueryFields.Safety,
|
|
QueryFields.Takedowns
|
|
)
|
|
val context: LookupContext = LookupContext(safetyLevel = Some(SafetyLevel.Recommendations))
|
|
|
|
GizmoduckUserStore(
|
|
client = gizmoduck,
|
|
queryFields = queryFields,
|
|
context = context,
|
|
statsReceiver = statsReceiver.scope("gizmoduck")
|
|
)
|
|
}
|
|
|
|
private val recTargetFactory: RecTargetFactory = RecTargetFactory(
|
|
abDecider,
|
|
userStore,
|
|
paramsBuilder,
|
|
statsReceiver
|
|
)
|
|
|
|
private val topicSocialProofHandler =
|
|
new TopicSocialProofHandler(
|
|
topicSocialProofStore,
|
|
tweetInfoStore,
|
|
uttTopicFilterStore,
|
|
recTargetFactory,
|
|
decider,
|
|
statsReceiver.scope("TopicSocialProofHandler"),
|
|
loadShedder,
|
|
timer)
|
|
|
|
val topicSocialProofHandlerStoreStitch: TopicSocialProofRequest => com.twitter.stitch.Stitch[
|
|
TopicSocialProofResponse
|
|
] = StitchOfReadableStore(topicSocialProofHandler.toReadableStore)
|
|
}
|
|
|
|
object TopicSocialProofService {
|
|
private val configRepoDirectory = "/usr/local/config"
|
|
}
|