Skip to content

Commit 65fd3e1

Browse files
authored
Rubicon: simplify logic for truncating segtaxes (#3796)
1 parent c614f17 commit 65fd3e1

File tree

4 files changed

+38
-150
lines changed

4 files changed

+38
-150
lines changed

src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java

Lines changed: 21 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import io.vertx.core.MultiMap;
3030
import io.vertx.core.http.HttpMethod;
3131
import org.apache.commons.collections4.CollectionUtils;
32-
import org.apache.commons.collections4.MapUtils;
3332
import org.apache.commons.lang3.ObjectUtils;
3433
import org.apache.commons.lang3.StringUtils;
3534
import org.apache.commons.lang3.math.NumberUtils;
@@ -106,19 +105,16 @@
106105
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
107106
import org.prebid.server.util.BidderUtil;
108107
import org.prebid.server.util.HttpUtil;
109-
import org.prebid.server.util.ListUtil;
110108
import org.prebid.server.util.ObjectUtil;
111109
import org.prebid.server.version.PrebidVersionProvider;
112110

113111
import java.math.BigDecimal;
114112
import java.net.URISyntaxException;
115-
import java.util.ArrayDeque;
116113
import java.util.ArrayList;
117114
import java.util.Arrays;
118115
import java.util.Base64;
119116
import java.util.Collection;
120117
import java.util.Collections;
121-
import java.util.Deque;
122118
import java.util.HashMap;
123119
import java.util.HashSet;
124120
import java.util.Iterator;
@@ -130,6 +126,7 @@
130126
import java.util.Set;
131127
import java.util.function.Function;
132128
import java.util.stream.Collectors;
129+
import java.util.stream.Stream;
133130
import java.util.stream.StreamSupport;
134131

135132
public class RubiconBidder implements Bidder<BidRequest> {
@@ -814,10 +811,6 @@ private static String getTextValueFromNodeByPath(JsonNode node, String path) {
814811
return nodeByPath != null && nodeByPath.isTextual() ? nodeByPath.textValue() : null;
815812
}
816813

817-
private static String getTextValueFromNode(JsonNode node) {
818-
return node != null && node.isTextual() ? node.textValue() : null;
819-
}
820-
821814
private void populateFirstPartyDataAttributes(ObjectNode sourceNode, ObjectNode targetNode) {
822815
if (sourceNode == null || sourceNode.isNull()) {
823816
return;
@@ -1259,97 +1252,40 @@ private void mergeFirstPartyDataFromUser(ExtUser userExt, ObjectNode result) {
12591252
}
12601253
}
12611254

1262-
private static void enrichWithIabAndSegtaxAttribute(ObjectNode target, List<Data> data, Set<Integer> segtaxValues) {
1263-
final Map<Integer, Deque<Segment>> segments = CollectionUtils.emptyIfNull(data).stream()
1255+
private static void enrichWithIabAndSegtaxAttribute(ObjectNode target, List<Data> data, Set<Integer> iabTaxes) {
1256+
CollectionUtils.emptyIfNull(data).stream()
12641257
.filter(Objects::nonNull)
1265-
.map(RubiconBidder::getValidSegments)
1266-
.filter(Objects::nonNull)
1267-
.collect(Collectors.toMap(
1268-
Map.Entry::getKey,
1269-
Map.Entry::getValue,
1270-
(first, second) -> {
1271-
first.addAll(second);
1272-
return first;
1273-
}));
1274-
1275-
if (MapUtils.isEmpty(segments)) {
1276-
return;
1277-
}
1278-
1279-
final Map<Integer, List<String>> relevantSegments = pickRelevantSegments(segments);
1280-
final Map<String, List<String>> resultSegments = groupBySegtaxValues(relevantSegments, segtaxValues);
1281-
1282-
resultSegments.forEach((segtaxValue, segmentIds) -> {
1283-
final ArrayNode array = target.putArray(segtaxValue);
1284-
segmentIds.forEach(array::add);
1285-
});
1258+
.flatMap(dataEntry -> extractTaxToSegmentId(dataEntry, iabTaxes))
1259+
.limit(MAX_NUMBER_OF_SEGMENTS)
1260+
.forEach(entry -> getArrayNodeOrCreate(target, entry.getKey()).add(entry.getValue()));
12861261
}
12871262

1288-
private static Map<String, List<String>> groupBySegtaxValues(Map<Integer, List<String>> segments,
1289-
Set<Integer> segtaxValues) {
1290-
1291-
return segments.entrySet().stream()
1292-
.collect(Collectors.toMap(
1293-
entry -> resolveSegmentName(entry.getKey(), segtaxValues),
1294-
Map.Entry::getValue,
1295-
ListUtil::union));
1296-
}
1297-
1298-
private static String resolveSegmentName(Integer taxonomyId, Set<Integer> segtaxValues) {
1299-
return segtaxValues.contains(taxonomyId) ? SEGTAX_IAB : SEGTAX_TAX + taxonomyId;
1300-
}
1301-
1302-
private static Map.Entry<Integer, Deque<Segment>> getValidSegments(Data data) {
1263+
private static Stream<Map.Entry<String, String>> extractTaxToSegmentId(Data data, Set<Integer> iabTaxes) {
13031264
final ObjectNode ext = data.getExt();
13041265
final JsonNode taxonomyId = ext != null ? ext.get(SEGTAX) : null;
13051266
if (taxonomyId == null || !taxonomyId.isInt()) {
1306-
return null;
1267+
return Stream.empty();
13071268
}
13081269

1309-
final Deque<Segment> segments = getValidOnlySegments(data.getSegment());
1310-
return CollectionUtils.isNotEmpty(segments) ? Map.entry(taxonomyId.intValue(), segments) : null;
1270+
final String taxKey = resolveTaxName(taxonomyId.intValue(), iabTaxes);
1271+
return CollectionUtils.emptyIfNull(data.getSegment()).stream()
1272+
.filter(Objects::nonNull)
1273+
.map(Segment::getId)
1274+
.filter(StringUtils::isNotBlank)
1275+
.map(id -> Map.entry(taxKey, id));
13111276
}
13121277

1313-
private static Deque<Segment> getValidOnlySegments(List<Segment> segments) {
1314-
return CollectionUtils.isNotEmpty(segments)
1315-
? segments.stream()
1316-
.filter(segment -> StringUtils.isNotBlank(segment.getId()))
1317-
.collect(Collectors.toCollection(ArrayDeque::new))
1318-
: null;
1278+
private static String resolveTaxName(Integer taxonomyId, Set<Integer> iabTaxes) {
1279+
return iabTaxes.contains(taxonomyId) ? SEGTAX_IAB : SEGTAX_TAX + taxonomyId;
13191280
}
13201281

1321-
private static Map<Integer, List<String>> pickRelevantSegments(final Map<Integer, Deque<Segment>> segments) {
1322-
final Map<Integer, List<String>> result = new HashMap<>();
1323-
final List<Integer> segmentsKeys = new ArrayList<>(segments.keySet());
1324-
1325-
int i = 0;
1326-
int consumedSegmentsCount = 0;
1327-
1328-
while (consumedSegmentsCount < MAX_NUMBER_OF_SEGMENTS && !segmentsKeys.isEmpty()) {
1329-
final int segmentsIndex = i % segmentsKeys.size();
1330-
final Integer segmentKey = segmentsKeys.get(segmentsIndex);
1331-
final Deque<Segment> currentSegments = segments.get(segmentKey);
1332-
1333-
final Segment lastSegment = currentSegments.pollLast();
1334-
result.computeIfAbsent(segmentKey, key -> new ArrayList<>()).add(lastSegment.getId());
1335-
consumedSegmentsCount++;
1336-
1337-
if (currentSegments.isEmpty()) {
1338-
segmentsKeys.remove(segmentKey);
1339-
i--;
1340-
}
1341-
i++;
1282+
private static ArrayNode getArrayNodeOrCreate(ObjectNode parent, String field) {
1283+
final JsonNode node = parent.get(field);
1284+
if (node == null || !node.isArray()) {
1285+
return parent.putArray(field);
13421286
}
13431287

1344-
return result;
1345-
}
1346-
1347-
private static Segment getAndRemoveLastSegment(List<Segment> list) {
1348-
final int lastElementIndex = list.size() - 1;
1349-
final Segment lastSegment = list.get(lastElementIndex);
1350-
list.remove(lastElementIndex);
1351-
1352-
return lastSegment;
1288+
return (ArrayNode) node;
13531289
}
13541290

13551291
private void processWarnings(List<BidderError> errors, List<String> priceFloorsWarnings) {

src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java

Lines changed: 15 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,34 +1119,6 @@ public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeIfSegtaxEqualsFou
11191119
.build()));
11201120
}
11211121

1122-
@Test
1123-
public void makeHttpRequestsShouldFillUserExtRpWithSegtaxValuesWithSegtaxesFromEachData() {
1124-
// given
1125-
final List<Data> dataWithSegments = asList(givenTestDataWithSegmentEntries(3),
1126-
givenDataWithSegmentEntry(3, "Included_SegmentId_1"),
1127-
givenDataWithSegmentEntry(3, "Included_SegmentId_2"));
1128-
1129-
final BidRequest bidRequest = givenBidRequest(
1130-
builder -> builder.user(User.builder().data(dataWithSegments).build()),
1131-
builder -> builder.video(Video.builder().build()),
1132-
identity());
1133-
1134-
// when
1135-
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
1136-
1137-
// then
1138-
assertThat(result.getErrors()).isEmpty();
1139-
assertThat(result.getValue()).hasSize(1).doesNotContainNull()
1140-
.extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class))
1141-
.extracting(BidRequest::getUser).doesNotContainNull()
1142-
.extracting(User::getExt)
1143-
.extracting(userExt -> userExt.getProperty("rp"))
1144-
.extracting(rp -> rp.get("target"))
1145-
.extracting(target -> target.get("tax3"))
1146-
.flatExtracting(tax3 -> mapper.convertValue(tax3, List.class))
1147-
.contains("Included_SegmentId_1", "Included_SegmentId_2");
1148-
}
1149-
11501122
@Test
11511123
public void makeHttpRequestsShouldRemoveUserDataObject() {
11521124
// given
@@ -1170,7 +1142,7 @@ public void makeHttpRequestsShouldRemoveUserDataObject() {
11701142
}
11711143

11721144
@Test
1173-
public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxValuesWithNoMoreThanHundredEntriesWithEvenDistribution()
1145+
public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxValuesWithNoMoreThanHundredEntriesFromDifferentSources()
11741146
throws IOException {
11751147

11761148
// given
@@ -1199,16 +1171,16 @@ public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxValuesWithNoMoreThanHun
11991171
final BidRequest capturedBidRequest = mapper.readValue(result.getValue().get(0).getBody(), BidRequest.class);
12001172
final JsonNode targetNode = capturedBidRequest.getSite().getExt().getProperty("rp").get("target");
12011173

1202-
assertThat(targetNode.elements()).toIterable().hasSize(4);
1174+
assertThat(targetNode.elements()).toIterable().hasSize(3);
12031175

12041176
final List<String> expectedIabValues = Streams.concat(
12051177
IntStream.range(1, 6).mapToObj(i -> "firstSegmentId_" + i),
12061178
IntStream.range(1, 5).mapToObj(i -> "secondSegmentId_" + i),
12071179
IntStream.range(1, 2).mapToObj(i -> "fifthSegmentId_" + i),
1208-
IntStream.range(59, 101).mapToObj(i -> "sixthSegmentId_" + i))
1180+
IntStream.range(1, 86).mapToObj(i -> "sixthSegmentId_" + i))
12091181
.toList();
12101182

1211-
assertThat(targetNode.get("iab").elements()).toIterable().hasSize(52)
1183+
assertThat(targetNode.get("iab").elements()).toIterable().hasSize(95)
12121184
.extracting(JsonNode::asText)
12131185
.containsExactlyInAnyOrderElementsOf(expectedIabValues);
12141186

@@ -1222,11 +1194,7 @@ public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxValuesWithNoMoreThanHun
12221194
.extracting(JsonNode::asText)
12231195
.containsExactlyInAnyOrderElementsOf(expectedTax4Values);
12241196

1225-
final List<String> expectedTax7Values = IntStream.range(58, 101).mapToObj(i -> "seventhSegmentId_" + i)
1226-
.toList();
1227-
assertThat(targetNode.get("tax7").elements()).toIterable().hasSize(43)
1228-
.extracting(JsonNode::asText)
1229-
.containsExactlyInAnyOrderElementsOf(expectedTax7Values);
1197+
assertThat(targetNode.get("tax7")).isNull();
12301198
}
12311199

12321200
@Test
@@ -1262,7 +1230,7 @@ public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxValuesWithNoMoreThanHun
12621230
}
12631231

12641232
@Test
1265-
public void makeHttpRequestsShouldFillUserExtRpWithSegtaxValuesWithNoMoreThanHundredEntriesWithEvenDistribution()
1233+
public void makeHttpRequestsShouldFillUserExtRpWithSegtaxValuesWithNoMoreThanHundredEntriesFromDifferentSources()
12661234
throws IOException {
12671235

12681236
// given
@@ -1289,7 +1257,7 @@ public void makeHttpRequestsShouldFillUserExtRpWithSegtaxValuesWithNoMoreThanHun
12891257
final BidRequest capturedBidRequest = mapper.readValue(result.getValue().get(0).getBody(), BidRequest.class);
12901258
final JsonNode targetNode = capturedBidRequest.getUser().getExt().getProperty("rp").get("target");
12911259

1292-
assertThat(targetNode.elements()).toIterable().hasSize(7);
1260+
assertThat(targetNode.elements()).toIterable().hasSize(6);
12931261

12941262
final List<String> expectedIabValues = IntStream.range(1, 3).mapToObj(i -> "fourthSegmentId_" + i).toList();
12951263
assertThat(targetNode.get("iab").elements()).toIterable()
@@ -1321,18 +1289,13 @@ public void makeHttpRequestsShouldFillUserExtRpWithSegtaxValuesWithNoMoreThanHun
13211289
.extracting(JsonNode::asText)
13221290
.containsExactlyInAnyOrderElementsOf(expectedTax5Values);
13231291

1324-
final List<String> expectedTax6Values = IntStream.range(59, 101).mapToObj(i -> "sixthSegmentId_" + i).toList();
1292+
final List<String> expectedTax6Values = IntStream.range(1, 86).mapToObj(i -> "sixthSegmentId_" + i).toList();
13251293
assertThat(targetNode.get("tax6").elements()).toIterable()
1326-
.hasSize(42)
1294+
.hasSize(85)
13271295
.extracting(JsonNode::asText)
13281296
.containsExactlyInAnyOrderElementsOf(expectedTax6Values);
13291297

1330-
final List<String> expectedTax7Values = IntStream.range(58, 101).mapToObj(i -> "seventhSegmentId_" + i)
1331-
.toList();
1332-
assertThat(targetNode.get("tax7").elements()).toIterable()
1333-
.hasSize(43)
1334-
.extracting(JsonNode::asText)
1335-
.containsExactlyInAnyOrderElementsOf(expectedTax7Values);
1298+
assertThat(targetNode.get("tax7")).isNull();
13361299

13371300
}
13381301

@@ -2118,9 +2081,9 @@ public void makeHttpRequestsShouldNotCreateUserExtTpIdWithAdServerEidSourceIfExt
21182081
final BidRequest bidRequest = givenBidRequest(builder -> builder.user(User.builder()
21192082
.ext(ExtUser.builder()
21202083
.eids(singletonList(Eid.builder()
2121-
.source("adserver.org")
2122-
.uids(singletonList(Uid.builder().id("id").build()))
2123-
.build()))
2084+
.source("adserver.org")
2085+
.uids(singletonList(Uid.builder().id("id").build()))
2086+
.build()))
21242087
.build())
21252088
.build()),
21262089
builder -> builder.video(Video.builder().build()), identity());
@@ -2724,7 +2687,7 @@ public void makeHttpRequestsShouldMergeImpExtRubiconAndDataKeywordsToRubiconImpE
27242687
}
27252688

27262689
@Test
2727-
public void makeHttpRequestsShouldCopyDataSearchToRubiconImpExtRpTargetSearch() throws IOException {
2690+
public void makeHttpRequestsShouldCopyDataSearchToRubiconImpExtRpTargetSearch() {
27282691
// given
27292692
final BidRequest bidRequest = givenBidRequest(
27302693
identity(),
@@ -2970,8 +2933,7 @@ public void makeHttpRequestsShouldProcessMetricsAndFillViewabilityVendor() {
29702933
}
29712934

29722935
@Test
2973-
public void makeHttpRequestsShouldReturnOnlyLineItemRequestsWithExpectedFieldsWhenImpPmpDealsArePresent()
2974-
throws IOException {
2936+
public void makeHttpRequestsShouldReturnOnlyLineItemRequestsWithExpectedFieldsWhenImpPmpDealsArePresent() {
29752937
// given
29762938
final List<Deal> dealsList = asList(
29772939
Deal.builder().ext(mapper.valueToTree(ExtDeal.of(ExtDealLine.of(null, "123",
@@ -4074,16 +4036,6 @@ private static RubiconBid givenRubiconBid(UnaryOperator<RubiconBid.RubiconBidBui
40744036
return bidCustomizer.apply(RubiconBid.builder()).build();
40754037
}
40764038

4077-
private static Data givenTestDataWithSegmentEntries(Integer segtax) {
4078-
final List<Segment> segments = IntStream.range(0, 1000)
4079-
.mapToObj(index -> Segment.builder().id("segmentId_" + index).build())
4080-
.toList();
4081-
return Data.builder()
4082-
.segment(segments)
4083-
.ext(mapper.createObjectNode().put("segtax", segtax))
4084-
.build();
4085-
}
4086-
40874039
private static ObjectNode givenImpExtRpTarget() {
40884040
return mapper.createObjectNode()
40894041
.put("pbs_login", USERNAME)

src/test/resources/org/prebid/server/it/openrtb2/magnite/test-magnite-bid-request.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
"site_id": 3001,
5656
"target": {
5757
"iab": [
58-
"segmentId2",
5958
"segmentId1",
59+
"segmentId2",
6060
"segmentId3"
6161
]
6262
}

src/test/resources/org/prebid/server/it/openrtb2/rubicon/test-rubicon-bid-request.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
"site_id": 3001,
5656
"target": {
5757
"iab": [
58-
"segmentId2",
5958
"segmentId1",
59+
"segmentId2",
6060
"segmentId3"
6161
]
6262
}

0 commit comments

Comments
 (0)