摘要:上一節(jié)我們分析了廣告索引的維護(hù)有種,全量索引加載和增量索引維護(hù)。因?yàn)閺V告檢索是廣告系統(tǒng)中最為重要的環(huán)節(jié),大家一定要認(rèn)真理解我們索引設(shè)計(jì)的思路,接下來(lái)我們來(lái)編碼實(shí)現(xiàn)索引維護(hù)功能。
上一節(jié)我們分析了廣告索引的維護(hù)有2種,全量索引加載和增量索引維護(hù)。因?yàn)閺V告檢索是廣告系統(tǒng)中最為重要的環(huán)節(jié),大家一定要認(rèn)真理解我們索引設(shè)計(jì)的思路,接下來(lái)我們來(lái)編碼實(shí)現(xiàn)索引維護(hù)功能。
我們來(lái)定義一個(gè)接口,來(lái)接收所有index的增刪改查操作,接口定義一個(gè)范型,來(lái)接收2個(gè)參數(shù),K代表我們索引的健值,V代表返回值。
/** * IIndexAware for 實(shí)現(xiàn)廣告索引的增刪改查 * * @author Isaac.Zhang | 若初 */ public interface IIndexAware{ /** * 通過(guò)key 獲取索引 */ V get(K key); /** * 添加索引 * @param key * @param value */ void add(K key, V value); /** * 更新索引 */ void update(K key, V value); /** * 刪除索引 */ void delete(K key, V value); }
我們一定要知道,并不是所有的數(shù)據(jù)庫(kù)表都需要?jiǎng)?chuàng)建索引,比如User表我們?cè)跀?shù)據(jù)檢索的時(shí)候其實(shí)是不需要的,當(dāng)然也就沒(méi)必要?jiǎng)?chuàng)建索引,并且,也不是表中的所有字段都需要索引,這個(gè)也是根據(jù)具體的業(yè)務(wù)來(lái)確定字段信息,比如我們接下來(lái)要編寫的推廣計(jì)劃索引中,推廣計(jì)劃名稱就可以不需要。下面,我們來(lái)實(shí)現(xiàn)我們的第一個(gè)正向索引。
首先創(chuàng)建操作推廣計(jì)劃的實(shí)體對(duì)象
/** * AdPlanIndexObject for 推廣計(jì)劃索引對(duì)象 * 這個(gè)索引對(duì)象我們沒(méi)有添加 推廣計(jì)劃名稱 * @author Isaac.Zhang | 若初 */ @Data @NoArgsConstructor @AllArgsConstructor public class AdPlanIndexObject { private Long planId; private Long userId; private Integer planStatus; private Date startDate; private Date endDate; /** * 根據(jù)實(shí)際字段來(lái)更新索引 */ public void update(AdPlanIndexObject newObject) { if (null != newObject.getPlanId()) { this.planId = newObject.getPlanId(); } if (null != newObject.getUserId()) { this.userId = newObject.getUserId(); } if (null != newObject.getPlanStatus()) { this.planStatus = newObject.getPlanStatus(); } if (null != newObject.getStartDate()) { this.startDate = newObject.getStartDate(); } if (null != newObject.getEndDate()) { this.endDate = newObject.getEndDate(); } } }
然后創(chuàng)建推廣計(jì)劃索引實(shí)現(xiàn)類,并實(shí)現(xiàn)IIndexAware接口。
/** * AdPlanIndexAwareImpl for 推廣計(jì)劃索引實(shí)現(xiàn)類 * * @author Isaac.Zhang | 若初 */ @Slf4j @Component public class AdPlanIndexAwareImpl implements IIndexAware{ private static Map planIndexObjectMap; /** * 因?yàn)椴僮魉饕倪^(guò)程中有可能對(duì)索引進(jìn)行更新,為了防止多線程造成的線程不安全問(wèn)題,我們不能使用hashmap,需要實(shí)現(xiàn)ConcurrentHashMap */ static { planIndexObjectMap = new ConcurrentHashMap<>(); } @Override public AdPlanIndexObject get(Long key) { return planIndexObjectMap.get(key); } @Override public void add(Long key, AdPlanIndexObject value) { log.info("AdPlanIndexAwareImpl before add::{}", planIndexObjectMap); planIndexObjectMap.put(key, value); log.info("AdPlanIndexAwareImpl after add::{}", planIndexObjectMap); } @Override public void update(Long key, AdPlanIndexObject value) { log.info("AdPlanIndexAwareImpl before update::{}", planIndexObjectMap); //查詢當(dāng)前的索引信息,如果不存在,直接新增索引信息 AdPlanIndexObject oldObj = planIndexObjectMap.get(key); if (null == oldObj) { planIndexObjectMap.put(key, value); } else { oldObj.update(value); } log.info("AdPlanIndexAwareImpl after update::{}", planIndexObjectMap); } @Override public void delete(Long key, AdPlanIndexObject value) { log.info("AdPlanIndexAwareImpl before delete::{}", planIndexObjectMap); planIndexObjectMap.remove(key); log.info("AdPlanIndexAwareImpl after delete::{}", planIndexObjectMap); } }
至此,我們已經(jīng)完成了推廣計(jì)劃的索引對(duì)象和索引操作的代碼編寫,大家可以參考上面的示例,依次完成推廣單元、推廣創(chuàng)意、地域、興趣、關(guān)鍵詞以及推廣創(chuàng)意和推廣單元的關(guān)聯(lián)索引,或者可直接從 Github傳送門 / Gitee傳送門 下載源碼。
按照上述代碼展示,我們已經(jīng)實(shí)現(xiàn)了所有的索引操作的定義,但是實(shí)際情況中,我們需要使用這些服務(wù)的時(shí)候,需要在每一個(gè)Service中@Autowired注入,我們那么多的索引操作類,還不包含后續(xù)還有可能需要新增的索引維度,工作量實(shí)在是太大,而且不方便維護(hù),作為一個(gè)合格的程序員來(lái)說(shuō),這是非常不友好的,也許會(huì)讓后續(xù)的開(kāi)發(fā)人員罵娘。
為了防止后續(xù)被罵,我們來(lái)編寫一個(gè)索引緩存工具類com.sxzhongf.ad.index.IndexDataTableUtils,通過(guò)這個(gè)索引緩存工具類來(lái)實(shí)現(xiàn)一次注入,解決后顧之憂。要實(shí)現(xiàn)這個(gè)工具類,我們需要實(shí)現(xiàn)2個(gè)接口:org.springframework.context.ApplicationContextAware和org.springframework.core.PriorityOrdered
org.springframework.context.ApplicationContextAware, 統(tǒng)一通過(guò)實(shí)現(xiàn)該接口的類,來(lái)操作Spring容器以及其中的Bean實(shí)例。
在Spring中,以Aware為后綴結(jié)束的類,大家可以簡(jiǎn)單的理解為應(yīng)用程序想要XXX,比如ApplicationContextAware代表應(yīng)用程序想要ApplicationContext,BeanFactoryAware 表示應(yīng)用程序想要BeanFactory...等等
org.springframework.core.PriorityOrdered組件加載順序,也可以使用org.springframework.core.Ordered
以下代碼為我們的工具類:
package com.sxzhongf.ad.index; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.PriorityOrdered; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * IndexDataTableUtils for 所有索引服務(wù)需要緩存的Java Bean * * 使用方式: * 獲取{@link com.sxzhongf.ad.index.creative.CreativeIndexAwareImpl}索引服務(wù)類 * 如下: * {@code * IndexDataTableUtils.of(CreativeIndexAwareImpl.class) * } * @author Isaac.Zhang | 若初 */ @Component public class IndexDataTableUtils implements ApplicationContextAware, PriorityOrdered { //注入ApplicationContext private static ApplicationContext applicationContext; /** * 定義用于保存所有Index的Map * Class標(biāo)示我們的索引類 */ private static final MapdataTableMap = new ConcurrentHashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { IndexDataTableUtils.applicationContext = applicationContext; } /** * 獲取索引服務(wù)緩存 */ public static T of(Class klass) { T instance = (T) dataTableMap.get(klass); //如果獲取到索引bean,直接返回當(dāng)前bean if (null != instance) { return instance; } //首次獲取索引bean為空,寫入Map dataTableMap.put(klass, bean(klass)); return (T) dataTableMap.get(klass); } /** * 獲取Spring 容器中的Bean對(duì)象 */ private static T bean(String beanName) { return (T) applicationContext.getBean(beanName); } /** * 獲取Spring 容器中的Bean對(duì)象 */ private static T bean(Class klass) { return (T) applicationContext.getBean(klass); } @Override public int getOrder() { return PriorityOrdered.HIGHEST_PRECEDENCE; } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/75918.html
摘要:各個(gè)表數(shù)據(jù)的存儲(chǔ)文件名定義索引對(duì)象導(dǎo)出的字段信息依然用為例。通用處理索引類索引之間存在層級(jí)劃分,也就是相互之間擁有依賴關(guān)系的劃分加載全量索引其實(shí)是增量索引添加的一種特殊實(shí)現(xiàn)若初實(shí)現(xiàn)廣告推廣計(jì)劃的第二層級(jí)索引實(shí)現(xiàn)。 上一節(jié)我們實(shí)現(xiàn)了索引基本操作的類以及索引緩存工具類,本小節(jié)我們開(kāi)始實(shí)現(xiàn)加載全量索引數(shù)據(jù),在加載全量索引數(shù)據(jù)之前,我們需要先將數(shù)據(jù)庫(kù)中的表數(shù)據(jù)導(dǎo)出到一份文件中。Lets cod...
摘要:索引設(shè)計(jì)介紹在我們廣告系統(tǒng)中,為了我們能更快的拿到我們想要的廣告數(shù)據(jù),我們需要對(duì)廣告數(shù)據(jù)添加類似于數(shù)據(jù)庫(kù)一樣的索引結(jié)構(gòu),分兩大類正向索引和倒排索引。如何在廣告系統(tǒng)中使用倒排索引核心用途是對(duì)各個(gè)維度限制的整理。 索引設(shè)計(jì)介紹 在我們廣告系統(tǒng)中,為了我們能更快的拿到我們想要的廣告數(shù)據(jù),我們需要對(duì)廣告數(shù)據(jù)添加類似于數(shù)據(jù)庫(kù)index一樣的索引結(jié)構(gòu),分兩大類:正向索引和倒排索引。 正向索引 通過(guò)...
摘要:在前面的過(guò)程中,我們創(chuàng)建了個(gè)服務(wù)發(fā)現(xiàn)我們使用作為服務(wù)發(fā)現(xiàn)組件,學(xué)習(xí)了的使用。加依賴加注解改配置使用項(xiàng)目三部曲,我們可以快速添加一個(gè)新組件,并正常使用這個(gè)我沒(méi)有在項(xiàng)目中實(shí)現(xiàn),但是大家可以和一樣,三部曲搞定。 在前面的過(guò)程中,我們創(chuàng)建了4個(gè)project: 服務(wù)發(fā)現(xiàn) 我們使用Eureka 作為服務(wù)發(fā)現(xiàn)組件,學(xué)習(xí)了Eureka Server,Eureka Client的使用。 Eureka...
摘要:對(duì)的配置和行為進(jìn)行定制修改匹配路由請(qǐng)求規(guī)則注冊(cè)自定義的和添加靜態(tài)資源處理器添加自定義視圖控制器添加自定義方法參數(shù)處理器配置消息轉(zhuǎn)換器清空所有轉(zhuǎn)換器做一個(gè)好人。博客園掘金簡(jiǎn)書(shū)頭條知乎 一個(gè)大的系統(tǒng),在代碼的復(fù)用肯定是必不可少的,它能解決: 統(tǒng)一的響應(yīng)處理(可以對(duì)外提供統(tǒng)一的響應(yīng)對(duì)象包裝) showImg(https://segmentfault.com/img/remote/146000...
摘要:不會(huì)記錄數(shù)據(jù)表的列名在接下來(lái)的實(shí)現(xiàn)中,我們會(huì)將自己的系統(tǒng)包裝成一個(gè)假的,通過(guò)開(kāi)源工具來(lái)實(shí)現(xiàn)監(jiān)聽(tīng)。因?yàn)槲覀冎恍枰械膬?nèi)容,那么我們也就只需要通過(guò)實(shí)現(xiàn)接口,來(lái)自定義一個(gè)監(jiān)聽(tīng)器實(shí)現(xiàn)我們的業(yè)務(wù)即可。 MySQL Binlog簡(jiǎn)介 什么是binlog? 一個(gè)二進(jìn)制日志,用來(lái)記錄對(duì)數(shù)據(jù)發(fā)生或潛在發(fā)生更改的SQL語(yǔ)句,并以而進(jìn)行的形式保存在磁盤中。 binlog 的作用? 最主要有3個(gè)用途: ...
閱讀 1751·2021-09-27 14:02
閱讀 3100·2021-09-27 13:36
閱讀 1046·2019-08-30 12:46
閱讀 1834·2019-08-30 10:51
閱讀 3571·2019-08-29 17:02
閱讀 941·2019-08-29 16:38
閱讀 1846·2019-08-29 16:37
閱讀 3004·2019-08-26 10:32