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

148 lines
5.3 KiB
Scala

package com.twitter.frigate.pushservice.model
import com.twitter.escherbird.common.thriftscala.QualifiedId
import com.twitter.escherbird.metadata.thriftscala.BasicMetadata
import com.twitter.escherbird.metadata.thriftscala.EntityIndexFields
import com.twitter.escherbird.metadata.thriftscala.EntityMegadata
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.frigate.common.base.MagicFanoutCandidate
import com.twitter.frigate.common.base.MagicFanoutEventCandidate
import com.twitter.frigate.common.base.RichEventFutCandidate
import com.twitter.frigate.magic_events.thriftscala
import com.twitter.frigate.magic_events.thriftscala.AnnotationAlg
import com.twitter.frigate.magic_events.thriftscala.FanoutEvent
import com.twitter.frigate.magic_events.thriftscala.MagicEventsReason
import com.twitter.frigate.magic_events.thriftscala.SemanticCoreID
import com.twitter.frigate.magic_events.thriftscala.SimClusterID
import com.twitter.frigate.magic_events.thriftscala.TargetID
import com.twitter.frigate.pushservice.model.PushTypes.PushCandidate
import com.twitter.hermit.store.semantic_core.SemanticEntityForQuery
import com.twitter.livevideo.timeline.domain.v2.Event
import com.twitter.topiclisting.utt.LocalizedEntity
import com.twitter.util.Future
case class FanoutReasonEntities(
userIds: Set[Long],
placeIds: Set[Long],
semanticCoreIds: Set[SemanticCoreID],
simclusterIds: Set[SimClusterID]) {
val qualifiedIds: Set[QualifiedId] =
semanticCoreIds.map(e => QualifiedId(e.domainId, e.entityId))
}
object FanoutReasonEntities {
val empty = FanoutReasonEntities(
userIds = Set.empty,
placeIds = Set.empty,
semanticCoreIds = Set.empty,
simclusterIds = Set.empty
)
def from(reasons: Seq[TargetID]): FanoutReasonEntities = {
val userIds: Set[Long] = reasons.collect {
case TargetID.UserID(userId) => userId.id
}.toSet
val placeIds: Set[Long] = reasons.collect {
case TargetID.PlaceID(placeId) => placeId.id
}.toSet
val semanticCoreIds: Set[SemanticCoreID] = reasons.collect {
case TargetID.SemanticCoreID(semanticCoreID) => semanticCoreID
}.toSet
val simclusterIds: Set[SimClusterID] = reasons.collect {
case TargetID.SimClusterID(simClusterID) => simClusterID
}.toSet
FanoutReasonEntities(
userIds = userIds,
placeIds,
semanticCoreIds = semanticCoreIds,
simclusterIds = simclusterIds
)
}
}
trait MagicFanoutHydratedCandidate extends PushCandidate with MagicFanoutCandidate {
lazy val fanoutReasonEntities: FanoutReasonEntities =
FanoutReasonEntities.from(candidateMagicEventsReasons.map(_.reason))
}
trait MagicFanoutEventHydratedCandidate
extends MagicFanoutHydratedCandidate
with MagicFanoutEventCandidate
with RichEventFutCandidate {
def target: PushTypes.Target
def stats: StatsReceiver
def fanoutEvent: Option[FanoutEvent]
def eventFut: Future[Option[Event]]
def semanticEntityResults: Map[SemanticEntityForQuery, Option[EntityMegadata]]
def effectiveMagicEventsReasons: Option[Seq[MagicEventsReason]]
def followedTopicLocalizedEntities: Future[Set[LocalizedEntity]]
def ergLocalizedEntities: Future[Set[LocalizedEntity]]
lazy val entityAnnotationAlg: Map[TargetID, Set[AnnotationAlg]] =
fanoutEvent
.flatMap { metadata =>
metadata.eventAnnotationInfo.map { eventAnnotationInfo =>
eventAnnotationInfo.map {
case (target, annotationInfoSet) => target -> annotationInfoSet.map(_.alg).toSet
}.toMap
}
}.getOrElse(Map.empty)
lazy val eventSource: Option[String] = fanoutEvent.map { metadata =>
val source = metadata.eventSource.getOrElse("undefined")
stats.scope("eventSource").counter(source).incr()
source
}
lazy val semanticCoreEntityTags: Map[(Long, Long), Set[String]] =
semanticEntityResults.flatMap {
case (semanticEntityForQuery, entityMegadataOpt: Option[EntityMegadata]) =>
for {
entityMegadata <- entityMegadataOpt
basicMetadata: BasicMetadata <- entityMegadata.basicMetadata
indexableFields: EntityIndexFields <- basicMetadata.indexableFields
tags <- indexableFields.tags
} yield {
((semanticEntityForQuery.domainId, semanticEntityForQuery.entityId), tags.toSet)
}
}
lazy val owningTwitterUserIds: Seq[Long] = semanticEntityResults.values.flatten
.flatMap {
_.basicMetadata.flatMap(_.twitter.flatMap(_.owningTwitterUserIds))
}.flatten
.toSeq
.distinct
lazy val eventFanoutReasonEntities: FanoutReasonEntities =
fanoutEvent match {
case Some(fanout) =>
fanout.targets
.map { targets: Seq[thriftscala.Target] =>
FanoutReasonEntities.from(targets.flatMap(_.whitelist).flatten)
}.getOrElse(FanoutReasonEntities.empty)
case _ => FanoutReasonEntities.empty
}
override lazy val eventResultFut: Future[Event] = eventFut.map {
case Some(eventResult) => eventResult
case _ =>
throw new IllegalArgumentException("event is None for MagicFanoutEventHydratedCandidate")
}
override val rankScore: Option[Double] = None
override val predictionScore: Option[Double] = None
}
case class MagicFanoutEventHydratedInfo(
fanoutEvent: Option[FanoutEvent],
semanticEntityResults: Map[SemanticEntityForQuery, Option[EntityMegadata]])