2323import org .apache .commons .lang3 .BooleanUtils ;
2424import org .apache .commons .lang3 .ObjectUtils ;
2525import org .apache .commons .lang3 .StringUtils ;
26+ import org .apache .commons .lang3 .tuple .Pair ;
2627import org .prebid .server .auction .categorymapping .CategoryMappingService ;
2728import org .prebid .server .auction .model .AuctionContext ;
2829import org .prebid .server .auction .model .AuctionParticipation ;
115116import java .util .ArrayList ;
116117import java .util .Collection ;
117118import java .util .Collections ;
119+ import java .util .Comparator ;
118120import java .util .EnumMap ;
119121import java .util .HashMap ;
120- import java .util .HashSet ;
121122import java .util .List ;
122123import java .util .Map ;
123124import java .util .Objects ;
@@ -645,11 +646,10 @@ private Future<BidResponse> cacheBidsAndCreateResponse(List<BidderResponseInfo>
645646
646647 final ExtRequestTargeting targeting = targeting (bidRequest );
647648
648- final List <BidderResponseInfo > bidderResponseInfos = injectWithTargetingAndBidRanking (
649+ final List <BidderResponseInfo > bidderResponseInfos = toBidderResponseWithTargetingBidInfos (
649650 bidderResponses ,
650651 bidderToMultiBids ,
651- preferDeals (targeting ),
652- isBidRankingEnabled (auctionContext .getAccount ()));
652+ preferDeals (targeting ));
653653
654654 final Set <BidInfo > bidInfos = bidderResponseInfos .stream ()
655655 .map (BidderResponseInfo ::getSeatBid )
@@ -687,96 +687,86 @@ private static boolean preferDeals(ExtRequestTargeting targeting) {
687687 return BooleanUtils .toBooleanDefaultIfNull (targeting != null ? targeting .getPreferdeals () : null , false );
688688 }
689689
690- private static boolean isBidRankingEnabled (Account account ) {
691- return Optional .ofNullable (account .getAuction ())
692- .map (AccountAuctionConfig ::getRanking )
693- .map (AccountBidRankingConfig ::getEnabled )
694- .orElse (false );
695- }
696-
697- private List <BidderResponseInfo > injectWithTargetingAndBidRanking (
690+ private List <BidderResponseInfo > toBidderResponseWithTargetingBidInfos (
698691 List <BidderResponseInfo > bidderResponses ,
699692 Map <String , MultiBidConfig > bidderToMultiBids ,
700- boolean preferDeals ,
701- boolean isBidRankingEnabled ) {
693+ boolean preferDeals ) {
702694
703- final Map <BidderResponseInfo , List <BidInfo >> bidderResponseToReducedBidInfos = bidderResponses .stream ()
704- .collect (Collectors .toMap (
705- Function .identity (),
706- bidderResponse -> toSortedMultiBidInfo (bidderResponse , bidderToMultiBids , preferDeals )));
695+ final Comparator <BidInfo > comparator = winningBidComparatorFactory .create (preferDeals ).reversed ();
707696
708- final Map <String , List <BidInfo >> impIdToBidInfos = bidderResponseToReducedBidInfos .values ()
709- .stream ()
710- .flatMap (Collection ::stream )
711- .collect (Collectors .groupingBy (
712- bidInfo -> bidInfo .getCorrespondingImp ().getId (),
713- Collectors .collectingAndThen (Collectors .toList (), bidInfos -> bidInfos .stream ()
714- .sorted (winningBidComparatorFactory .create (preferDeals ).reversed ())
715- .toList ())));
716-
717- final Set <BidInfo > winningBids = new HashSet <>();
718- final Map <String , Map <String , List <BidInfo >>> seatToBidderToBids = new HashMap <>();
719-
720- for (final List <BidInfo > bidInfos : impIdToBidInfos .values ()) {
721- final List <BidInfo > bidsWithRanking = isBidRankingEnabled
722- ? IntStream .range (0 , bidInfos .size ())
723- .mapToObj (i -> bidInfos .get (i ).toBuilder ().rank (i + 1 ).build ())
724- .toList ()
725- : bidInfos ;
726-
727- if (!bidsWithRanking .isEmpty ()) {
728- winningBids .add (bidsWithRanking .getFirst ());
729- bidsWithRanking .forEach (bidInfo ->
730- seatToBidderToBids .computeIfAbsent (bidInfo .getSeat (), k -> new HashMap <>())
731- .computeIfAbsent (bidInfo .getBidder (), k -> new ArrayList <>()).add (bidInfo ));
732- }
733- }
697+ final List <List <BidInfo >> bidInfosPerBidder = bidderResponses .stream ()
698+ .map (bidderResponse -> limitMultiBid (bidderResponse , bidderToMultiBids , comparator ))
699+ .toList ();
700+ final List <List <BidInfo >> rankedBidInfos = applyRanking (bidInfosPerBidder , comparator );
734701
735- return bidderResponseToReducedBidInfos .keySet ().stream ()
736- .map (bidderResponseInfo -> injectBidInfoWithTargeting (
737- bidderResponseInfo ,
738- bidderToMultiBids ,
739- seatToBidderToBids .getOrDefault (bidderResponseInfo .getSeat (), Collections .emptyMap ())
740- .getOrDefault (bidderResponseInfo .getBidder (), Collections .emptyList ()),
741- winningBids ))
702+ return IntStream .range (0 , bidderResponses .size ())
703+ .mapToObj (i -> enrichBidInfoWithTargeting (
704+ bidderResponses .get (i ),
705+ rankedBidInfos .get (i ),
706+ bidderToMultiBids ))
742707 .toList ();
743708 }
744709
745- private List <BidInfo > toSortedMultiBidInfo (BidderResponseInfo bidderResponse ,
710+ private static List <BidInfo > limitMultiBid (BidderResponseInfo bidderResponse ,
746711 Map <String , MultiBidConfig > bidderToMultiBids ,
747- boolean preferDeals ) {
712+ Comparator <BidInfo > comparator ) {
713+
714+ final MultiBidConfig multiBid = bidderToMultiBids .get (bidderResponse .getBidder ());
715+ final Integer bidLimit = multiBid != null ? multiBid .getMaxBids () : DEFAULT_BID_LIMIT_MIN ;
748716
749717 final List <BidInfo > bidInfos = bidderResponse .getSeatBid ().getBidsInfos ();
750718 final Map <String , List <BidInfo >> impIdToBidInfos = bidInfos .stream ()
751719 .collect (Collectors .groupingBy (bidInfo -> bidInfo .getCorrespondingImp ().getId ()));
752720
753- final MultiBidConfig multiBid = bidderToMultiBids .get (bidderResponse .getBidder ());
754- final Integer bidLimit = multiBid != null ? multiBid .getMaxBids () : DEFAULT_BID_LIMIT_MIN ;
755-
756721 return impIdToBidInfos .values ().stream ()
757- .map (infos -> sortReducedBidInfo (infos , bidLimit , preferDeals ))
758- .flatMap (Collection ::stream )
722+ .flatMap (infos -> infos .stream ()
723+ .sorted (comparator )
724+ .limit (bidLimit ))
759725 .toList ();
760726 }
761727
762- private List <BidInfo > sortReducedBidInfo (List <BidInfo > bidInfos , int limit , boolean preferDeals ) {
763- return bidInfos .stream ()
764- .sorted (winningBidComparatorFactory .create (preferDeals ).reversed ())
765- .limit (limit )
766- .toList ();
728+ private static List <List <BidInfo >> applyRanking (List <List <BidInfo >> bidInfosPerBidder ,
729+ Comparator <BidInfo > comparator ) {
730+
731+ final Map <String , List <Pair <Integer , BidInfo >>> impIdToBidderBidInfo = new HashMap <>();
732+ for (int bidderIndex = 0 ; bidderIndex < bidInfosPerBidder .size (); bidderIndex ++) {
733+ final List <BidInfo > bidInfos = bidInfosPerBidder .get (bidderIndex );
734+
735+ for (final BidInfo bidInfo : bidInfos ) {
736+ impIdToBidderBidInfo
737+ .computeIfAbsent (bidInfo .getCorrespondingImp ().getId (), ignore -> new ArrayList <>())
738+ .add (Pair .of (bidderIndex , bidInfo ));
739+ }
740+ }
741+
742+ for (List <Pair <Integer , BidInfo >> bidderToBidInfo : impIdToBidderBidInfo .values ()) {
743+ bidderToBidInfo .sort (Comparator .comparing (Pair ::getRight , comparator ));
744+ }
745+
746+ final List <List <BidInfo >> rankedBidInfosPerBidder = new ArrayList <>();
747+ for (int i = 0 ; i < bidInfosPerBidder .size (); i ++) {
748+ rankedBidInfosPerBidder .add (new ArrayList <>());
749+ }
750+
751+ for (List <Pair <Integer , BidInfo >> sortedBidderToBidInfo : impIdToBidderBidInfo .values ()) {
752+ for (int rank = 0 ; rank < sortedBidderToBidInfo .size (); rank ++) {
753+ final Pair <Integer , BidInfo > bidderToBidInfo = sortedBidderToBidInfo .get (rank );
754+ final BidInfo bidInfo = bidderToBidInfo .getRight ();
755+
756+ rankedBidInfosPerBidder .get (bidderToBidInfo .getLeft ())
757+ .add (bidInfo .toBuilder ().rank (rank + 1 ).build ());
758+ }
759+ }
760+
761+ return rankedBidInfosPerBidder ;
767762 }
768763
769- private static BidderResponseInfo injectBidInfoWithTargeting (BidderResponseInfo bidderResponseInfo ,
770- Map <String , MultiBidConfig > bidderToMultiBids ,
764+ private static BidderResponseInfo enrichBidInfoWithTargeting (BidderResponseInfo bidderResponseInfo ,
771765 List <BidInfo > bidderBidInfos ,
772- Set < BidInfo > winningBids ) {
766+ Map < String , MultiBidConfig > bidderToMultiBids ) {
773767
774768 final String bidder = bidderResponseInfo .getBidder ();
775- final List <BidInfo > bidInfosWithTargeting = toBidInfoWithTargeting (
776- bidderBidInfos ,
777- bidder ,
778- bidderToMultiBids ,
779- winningBids );
769+ final List <BidInfo > bidInfosWithTargeting = toBidInfoWithTargeting (bidderBidInfos , bidder , bidderToMultiBids );
780770
781771 final BidderSeatBidInfo seatBid = bidderResponseInfo .getSeatBid ();
782772 final BidderSeatBidInfo modifiedSeatBid = seatBid .with (bidInfosWithTargeting );
@@ -785,22 +775,20 @@ private static BidderResponseInfo injectBidInfoWithTargeting(BidderResponseInfo
785775
786776 private static List <BidInfo > toBidInfoWithTargeting (List <BidInfo > bidderBidInfos ,
787777 String bidder ,
788- Map <String , MultiBidConfig > bidderToMultiBids ,
789- Set <BidInfo > winningBids ) {
778+ Map <String , MultiBidConfig > bidderToMultiBids ) {
790779
791780 final Map <String , List <BidInfo >> impIdToBidInfos = bidderBidInfos .stream ()
792781 .collect (Collectors .groupingBy (bidInfo -> bidInfo .getCorrespondingImp ().getId ()));
793782
794783 return impIdToBidInfos .values ().stream ()
795- .map (bidInfos -> injectTargeting (bidInfos , bidder , bidderToMultiBids , winningBids ))
784+ .map (bidInfos -> enrichWithTargeting (bidInfos , bidder , bidderToMultiBids ))
796785 .flatMap (Collection ::stream )
797786 .toList ();
798787 }
799788
800- private static List <BidInfo > injectTargeting (List <BidInfo > bidderImpIdBidInfos ,
801- String bidder ,
802- Map <String , MultiBidConfig > bidderToMultiBids ,
803- Set <BidInfo > winningBids ) {
789+ private static List <BidInfo > enrichWithTargeting (List <BidInfo > bidderImpIdBidInfos ,
790+ String bidder ,
791+ Map <String , MultiBidConfig > bidderToMultiBids ) {
804792
805793 final List <BidInfo > result = new ArrayList <>();
806794
@@ -815,7 +803,7 @@ private static List<BidInfo> injectTargeting(List<BidInfo> bidderImpIdBidInfos,
815803
816804 final TargetingInfo targetingInfo = TargetingInfo .builder ()
817805 .isTargetingEnabled (targetingBidderCode != null )
818- .isWinningBid (winningBids . contains ( bidInfo ) )
806+ .isWinningBid (bidInfo . getRank () == 1 )
819807 .isAddTargetBidderCode (targetingBidderCode != null && multiBidSize > 1 )
820808 .bidderCode (targetingBidderCode )
821809 .seat (targetingCode (bidInfo .getSeat (), bidderCodePrefix , i ))
@@ -829,7 +817,11 @@ private static List<BidInfo> injectTargeting(List<BidInfo> bidderImpIdBidInfos,
829817 }
830818
831819 private static String targetingCode (String base , String prefix , int i ) {
832- return i == 0 ? base : prefix != null ? prefix + (i + 1 ) : null ;
820+ if (i == 0 ) {
821+ return base ;
822+ }
823+
824+ return prefix != null ? prefix + (i + 1 ) : null ;
833825 }
834826
835827 private ExtBidResponse toExtBidResponse (List <BidderResponseInfo > bidderResponseInfos ,
@@ -1585,6 +1577,8 @@ private Bid toBid(BidInfo bidInfo,
15851577 final ObjectNode originalBidExt = bid .getExt ();
15861578 final Boolean dealsTierSatisfied = bidInfo .getSatisfiedPriority ();
15871579
1580+ final boolean bidRankingEnabled = isBidRankingEnabled (account );
1581+
15881582 final ExtBidPrebid updatedExtBidPrebid =
15891583 getExtPrebid (originalBidExt , ExtBidPrebid .class )
15901584 .map (ExtBidPrebid ::toBuilder )
@@ -1594,7 +1588,7 @@ private Bid toBid(BidInfo bidInfo,
15941588 .dealTierSatisfied (dealsTierSatisfied )
15951589 .cache (cache )
15961590 .passThrough (extractPassThrough (bidInfo .getCorrespondingImp ()))
1597- .rank (bidInfo .getRank ())
1591+ .rank (bidRankingEnabled ? bidInfo .getRank () : null )
15981592 .build ();
15991593
16001594 final ObjectNode updatedBidExt =
@@ -1624,6 +1618,13 @@ private JsonNode extractPassThrough(Imp imp) {
16241618 .orElse (null );
16251619 }
16261620
1621+ private static boolean isBidRankingEnabled (Account account ) {
1622+ return Optional .ofNullable (account .getAuction ())
1623+ .map (AccountAuctionConfig ::getRanking )
1624+ .map (AccountBidRankingConfig ::getEnabled )
1625+ .orElse (false );
1626+ }
1627+
16271628 private String createNativeMarkup (String bidAdm , Imp correspondingImp ) {
16281629 final Response nativeMarkup ;
16291630 try {
0 commit comments