Advertising Retrieval Service
Functional introduction
Media (display ads opened by mobile APP, big screen ads seen on the road, etc.)
Request Data Object Implementation
From the image above, we can see that when the media makes a request to our advertising retrieval system, there are a lot of request parameter information in the request. They are divided into three parts. We encoding and encapsulating the object information of these parameters and the information of our request itself.Let's code.
- Create ad retrieval request interface
/** * ISearch for Request interface, * Get advertising response information based on who requested it * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | If initial </a> */ @FunctionalInterface public interface ISearch { /** * Return ad results on request */ SearchResponse fetchAds(SearchRequest request); }
- Create SearchRequest with three parts: mediaId,RequestInfo,FeatureInfo
@Data @NoArgsConstructor @AllArgsConstructor public class SearchRequest { //Media requests labeling private String mediaId; //Request basic information private RequestInfo requestInfo; //Matching information private FeatureInfo featureInfo; @Data @NoArgsConstructor @AllArgsConstructor public static class RequestInfo { private String requestId; private List<AdSlot> adSlots; private App app; private Geo geo; private Device device; } @Data @NoArgsConstructor @AllArgsConstructor public static class FeatureInfo { private KeywordFeature keywordFeature; private DistrictFeature districtFeature; private HobbyFeatrue hobbyFeatrue; private FeatureRelation relation = FeatureRelation.AND; } }
Everyone else can go github portal & gitee portal Download the source code.
Retrieving Response Object Definitions
/** * SearchResponse for Retrieving API Response Objects * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | If initial </a> */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class SearchResponse { //One advertising space to display multiple advertisements //Map key is AdSlot#adSlotCode public Map<String, List<Creative>> adSlotRelationAds = new HashMap<>(); @Data @Builder @NoArgsConstructor @AllArgsConstructor public static class Creative { private Long adId; private String adUrl; private Integer width; private Integer height; private Integer type; private Integer materialType; //Show monitoring url private List<String> showMonitorUrl = Arrays.asList("www.life-runner.com", "www.babydy.cn"); //Click to monitor url private List<String> clickMonitorUrl = Arrays.asList("www.life-runner.com", "www.babydy.cn"); } /** * Our retrieval service is for in-memory index retrieval, so we need a conversion method */ public static Creative convert(CreativeIndexObject object) { return Creative.builder() .adId(object.getAdId()) .adUrl(object.getAdUrl()) .width(object.getWidth()) .height(object.getHeight()) .type(object.getType()) .materialType(object.getMaterialType()) .build(); } }
Filter by traffic type
Traffic type itself belongs to the category under the promotion unit. There are many kinds of patch advertisements, open-screen advertisements and so on. These types need to be synchronized with the media. The media will launch different advertisement requests according to different traffic types. We need to define an information class of traffic type first.
public class AdUnitConstants { public static class PositionType{ //Full-screen ad format displayed at the start of App with a short display time. private static final int KAIPING = 1; //Advertisements before the start of the movie private static final int TIEPIAN = 2; //Movie Play Midway Advertising private static final int TIEPIAN_MIDDLE = 4; //Advertisements played when video is paused private static final int TIEPIAN_PAUSE = 8; //Video finished playing private static final int TIEPIAN_POST = 16; } }
From these types of numbers, we can see that they are multiples of 2, which is to improve performance using bit operations.
In com.sxzhongf.ad.index.adunit.AdUnitIndexObject, we add a type checking method:
public static boolean isAdSlotType(int adSlotType, int positionType) { switch (adSlotType) { case AdUnitConstants.PositionType.KAIPING: return isKaiPing(positionType); case AdUnitConstants.PositionType.TIEPIAN: return isTiePian(positionType); case AdUnitConstants.PositionType.TIEPIAN_MIDDLE: return isTiePianMiddle(positionType); case AdUnitConstants.PositionType.TIEPIAN_PAUSE: return isTiePianPause(positionType); case AdUnitConstants.PositionType.TIEPIAN_POST: return isTiePianPost(positionType); default: return false; } } /** * And operations, low bits, high bits, etc. * If > 0, it opens the screen */ private static boolean isKaiPing(int positionType) { return (positionType & AdUnitConstants.PositionType.KAIPING) > 0; } private static boolean isTiePianMiddle(int positionType) { return (positionType & AdUnitConstants.PositionType.TIEPIAN_MIDDLE) > 0; } private static boolean isTiePianPause(int positionType) { return (positionType & AdUnitConstants.PositionType.TIEPIAN_PAUSE) > 0; } private static boolean isTiePianPost(int positionType) { return (positionType & AdUnitConstants.PositionType.TIEPIAN_POST) > 0; } private static boolean isTiePian(int positionType) { return (positionType & AdUnitConstants.PositionType.TIEPIAN) > 0; }
Anyway, we all need data query filtering based on positionType. We added two methods to the previous com.sxzhongf.ad.index.adunit.AdUnitIndexAwareImpl to achieve filtering:
/** * Filter for the presence of UnitIds that satisfy positionType */ public Set<Long> match(Integer positionType) { Set<Long> adUnitIds = new HashSet<>(); objectMap.forEach((k, v) -> { if (AdUnitIndexObject.isAdSlotType(positionType, v.getPositionType())) { adUnitIds.add(k); } }); return adUnitIds; } /** * Query AdUnit list based on UnitIds */ public List<AdUnitIndexObject> fetch(Collection<Long> adUnitIds) { if (CollectionUtils.isEmpty(adUnitIds)) { return Collections.EMPTY_LIST; } List<AdUnitIndexObject> result = new ArrayList<>(); adUnitIds.forEach(id -> { AdUnitIndexObject object = get(id); if (null == object) { log.error("AdUnitIndexObject does not found:{}", id); return; } result.add(object); }); return result; }
- Implement Search Service Interface
Above all, we have prepared a series of query methods to query ad unit information according to the traffic type. Now we begin to implement our query interface, in which we can get the media's request object information with a series of filter parameters needed for query:
/** * SearchImpl for Implement search service * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | If initial </a> */ @Service @Slf4j public class SearchImpl implements ISearch { @Override public SearchResponse fetchAds(SearchRequest request) { //Get Request Advertising Bit Information List<AdSlot> adSlotList = request.getRequestInfo().getAdSlots(); //Get three Feature information KeywordFeature keywordFeature = request.getFeatureInfo().getKeywordFeature(); HobbyFeatrue hobbyFeatrue = request.getFeatureInfo().getHobbyFeatrue(); DistrictFeature districtFeature = request.getFeatureInfo().getDistrictFeature(); //Feature Relationships FeatureRelation featureRelation = request.getFeatureInfo().getRelation(); //Construct Response Object SearchResponse response = new SearchResponse(); Map<String, List<SearchResponse.Creative>> adSlotRelationAds = response.getAdSlotRelationAds(); for (AdSlot adSlot : adSlotList) { Set<Long> targetUnitIdSet; //Get initial advertising information from the cache based on traffic type Set<Long> adUnitIdSet = IndexDataTableUtils.of( AdUnitIndexAwareImpl.class ).match(adSlot.getPositionType()); } return null; } }