> 媒體方(手機APP打開的展現廣告,走在路上看到的大屏幕廣告等等)java
從上圖咱們能夠看出,在媒體方向咱們的廣告檢索系統發起請求的時候,請求中會有不少的請求參數信息,他們分爲了三個部分,咱們來編碼封裝這幾個參數對象信息以及咱們請求自己的信息。Let's code.git
/** * ISearch for 請求接口, * 根據廣告請求對象,獲取廣告響應信息 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @FunctionalInterface public interface ISearch { /** * 根據請求返回廣告結果 */ SearchResponse fetchAds(SearchRequest request); }
mediaId
,RequestInfo
,FeatureInfo
@Data @NoArgsConstructor @AllArgsConstructor public class SearchRequest { //媒體方請求標示 private String mediaId; //請求基本信息 private RequestInfo requestInfo; //匹配信息 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; } }
其餘的對象你們能夠去github傳送門 & gitee傳送門 下載源碼。github
/** * SearchResponse for 檢索API響應對象 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Data @Builder @NoArgsConstructor @AllArgsConstructor public class SearchResponse { //一個廣告位,能夠展現多個廣告 //Map key爲廣告位 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; //展現監控url private List<string> showMonitorUrl = Arrays.asList("www.life-runner.com", "www.babydy.cn"); //點擊監控url private List<string> clickMonitorUrl = Arrays.asList("www.life-runner.com", "www.babydy.cn"); } /** * 咱們的檢索服務針對的是內存中的索引檢索,那麼咱們就須要一個轉換方法 */ 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(); } }
流量類型自己屬於推廣單元下的類目,有不少種類貼片廣告
,開屏廣告
等等,這些類型須要同步到媒體方,媒體方會根據不一樣的流量類型發起不一樣的廣告請求,咱們須要先定義一個流量類型的信息類。緩存
public class AdUnitConstants { public static class PositionType{ //App啓動時展現的、展現時間短暫的全屏化廣告形式。 private static final int KAIPING = 1; //電影開始以前的廣告 private static final int TIEPIAN = 2; //電影播放中途廣告 private static final int TIEPIAN_MIDDLE = 4; //暫停視頻時候播放的廣告 private static final int TIEPIAN_PAUSE = 8; //視頻播放完 private static final int TIEPIAN_POST = 16; } }
從上述類型的數字,咱們能夠看出是2的倍數,這是爲了使用位運算提高性能。app
在com.sxzhongf.ad.index.adunit.AdUnitIndexObject
中,咱們添加類型校驗方法:ide
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; } } /** * 與運算,低位取等,高位補零。 * 若是 > 0,則爲開屏 */ 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; }
無所如何,咱們都是須要根據positionType進行數據查詢過濾,咱們在以前的com.sxzhongf.ad.index.adunit.AdUnitIndexAwareImpl
中添加2個方法來實現過濾:性能
/** * 過濾當前是否存在知足positionType的UnitIds */ 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; } /** * 根據UnitIds查詢AdUnit list */ 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; }
上述咱們準備了一系列的查詢方法,都是爲了根據流量類型查詢廣告單元信息,咱們如今開始實現咱們的查詢接口,查詢接口中,咱們能夠獲取到媒體方的請求對象信息,它帶有一系列查詢所須要的過濾參數:fetch
/** * SearchImpl for 實現search 服務 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a> */ @Service @Slf4j public class SearchImpl implements ISearch { @Override public SearchResponse fetchAds(SearchRequest request) { //獲取請求廣告位信息 List<adslot> adSlotList = request.getRequestInfo().getAdSlots(); //獲取三個Feature信息 KeywordFeature keywordFeature = request.getFeatureInfo().getKeywordFeature(); HobbyFeatrue hobbyFeatrue = request.getFeatureInfo().getHobbyFeatrue(); DistrictFeature districtFeature = request.getFeatureInfo().getDistrictFeature(); //Feature關係 FeatureRelation featureRelation = request.getFeatureInfo().getRelation(); //構造響應對象 SearchResponse response = new SearchResponse(); Map<string, list<searchresponse.creative>> adSlotRelationAds = response.getAdSlotRelationAds(); for (AdSlot adSlot : adSlotList) { Set<long> targetUnitIdSet; //根據流量類型從緩存中獲取 初始 廣告信息 Set<long> adUnitIdSet = IndexDataTableUtils.of( AdUnitIndexAwareImpl.class ).match(adSlot.getPositionType()); } return null; } } ```</long></long></string,></adslot></adunitindexobject></long></adunitindexobject></long></long></string></string></string,></adslot>