the-algorithm/pushservice/src/main/scala/com/twitter/frigate/pushservice/model/ibis/Ibis2Hydrator.scala

128 lines
4.4 KiB
Scala

package com.twitter.frigate.pushservice.model.ibis
import com.twitter.frigate.common.rec_types.RecTypes
import com.twitter.frigate.common.util.MRPushCopy
import com.twitter.frigate.common.util.MrPushCopyObjects
import com.twitter.frigate.pushservice.model.PushTypes.PushCandidate
import com.twitter.frigate.pushservice.params.{PushFeatureSwitchParams => FS}
import com.twitter.ibis2.service.thriftscala.Flags
import com.twitter.ibis2.service.thriftscala.Ibis2Request
import com.twitter.ibis2.service.thriftscala.RecipientSelector
import com.twitter.ibis2.service.thriftscala.ResponseFlags
import com.twitter.util.Future
import scala.util.control.NoStackTrace
import com.twitter.ni.lib.logged_out_transform.Ibis2RequestTransform
class PushCopyIdNotFoundException(private val message: String)
extends Exception(message)
with NoStackTrace
class InvalidPushCopyIdException(private val message: String)
extends Exception(message)
with NoStackTrace
trait Ibis2HydratorForCandidate
extends CandidatePushCopy
with OverrideForIbis2Request
with CustomConfigurationMapForIbis {
self: PushCandidate =>
lazy val silentPushModelValue: Map[String, String] =
if (RecTypes.silentPushDefaultEnabledCrts.contains(commonRecType)) {
Map.empty
} else {
Map("is_silent_push" -> "true")
}
private def transformRelevanceScore(
mlScore: Double,
scoreRange: Seq[Double]
): Double = {
val (lowerBound, upperBound) = (scoreRange.head, scoreRange.last)
(mlScore * (upperBound - lowerBound)) + lowerBound
}
private def getBoundedMlScore(mlScore: Double): Double = {
if (RecTypes.isMagicFanoutEventType(commonRecType)) {
val mfScoreRange = target.params(FS.MagicFanoutRelevanceScoreRange)
transformRelevanceScore(mlScore, mfScoreRange)
} else {
val mrScoreRange = target.params(FS.MagicRecsRelevanceScoreRange)
transformRelevanceScore(mlScore, mrScoreRange)
}
}
lazy val relevanceScoreMapFut: Future[Map[String, String]] = {
mrWeightedOpenOrNtabClickRankingProbability.map {
case Some(mlScore) if target.params(FS.IncludeRelevanceScoreInIbis2Payload) =>
val boundedMlScore = getBoundedMlScore(mlScore)
Map("relevance_score" -> boundedMlScore.toString)
case _ => Map.empty[String, String]
}
}
def customFieldsMapFut: Future[Map[String, String]] = relevanceScoreMapFut
//override is only enabled for RFPH CRT
def modelValues: Future[Map[String, String]] = {
Future.join(overrideModelValueFut, customConfigMapsFut).map {
case (overrideModelValue, customConfig) =>
overrideModelValue ++ silentPushModelValue ++ customConfig
}
}
def modelName: String = pushCopy.ibisPushModelName
def senderId: Option[Long] = None
def ibis2Request: Future[Option[Ibis2Request]] = {
Future.join(self.target.loggedOutMetadata, modelValues).map {
case (Some(metadata), modelVals) =>
Some(
Ibis2RequestTransform
.apply(metadata, modelName, modelVals).copy(
senderId = senderId,
flags = Some(Flags(
darkWrite = Some(target.isDarkWrite),
skipDupcheck = target.pushContext.flatMap(_.useDebugHandler),
responseFlags = Some(ResponseFlags(stringTelemetry = Some(true)))
))
))
case (None, modelVals) =>
Some(
Ibis2Request(
recipientSelector = RecipientSelector(Some(target.targetId)),
modelName = modelName,
modelValues = Some(modelVals),
senderId = senderId,
flags = Some(
Flags(
darkWrite = Some(target.isDarkWrite),
skipDupcheck = target.pushContext.flatMap(_.useDebugHandler),
responseFlags = Some(ResponseFlags(stringTelemetry = Some(true)))
)
)
))
}
}
}
trait CandidatePushCopy {
self: PushCandidate =>
final lazy val pushCopy: MRPushCopy =
pushCopyId match {
case Some(pushCopyId) =>
MrPushCopyObjects
.getCopyFromId(pushCopyId)
.getOrElse(
throw new InvalidPushCopyIdException(
s"Invalid push copy id: $pushCopyId for ${self.commonRecType}"))
case None =>
throw new PushCopyIdNotFoundException(
s"PushCopy not found in frigateNotification for ${self.commonRecType}"
)
}
}