[Spring cloud 一步步实现广告系统] 14. 全量索引代码实现
上一節(jié)我們實現(xiàn)了索引基本操作的類以及索引緩存工具類,本小節(jié)我們開始實現(xiàn)加載全量索引數(shù)據(jù),在加載全量索引數(shù)據(jù)之前,我們需要先將數(shù)據(jù)庫中的表數(shù)據(jù)導(dǎo)出到一份文件中。Let's code.
1.首先定義一個常量類,用來存儲導(dǎo)出文件存儲的目錄和文件名稱
因為我們導(dǎo)出的文件需要在搜索服務(wù)中使用到,因此,我們將文件名 & 目錄以及導(dǎo)出對象的信息編寫在mscx-ad-commom項目中。
public class FileConstant {public static final String DATA_ROOT_DIR = "/Users/xxx/Documents/promotion/data/mysql/";//各個表數(shù)據(jù)的存儲文件名public static final String AD_PLAN = "ad_plan.data";public static final String AD_UNIT = "ad_unit.data";public static final String AD_CREATIVE = "ad_creative.data";public static final String AD_CREATIVE_RELARION_UNIT = "ad_creative_relation_unit.data";public static final String AD_UNIT_HOBBY = "ad_unit_hobby.data";public static final String AD_UNIT_DISTRICT = "ad_unit_district.data";public static final String AD_UNIT_KEYWORD = "ad_unit_keyword.data"; }2.定義索引對象導(dǎo)出的字段信息,依然用Ad_Plan為例。
/*** AdPlanTable for 需要導(dǎo)出的表字段信息 => 是搜索索引字段一一對應(yīng)** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/ @Data @AllArgsConstructor @NoArgsConstructor public class AdPlanTable {private Long planId;private Long userId;private Integer planStatus;private Date startDate;private Date endDate; }3.導(dǎo)出文件服務(wù)實現(xiàn)
同樣,最好的實現(xiàn)方式就是將導(dǎo)出服務(wù)作為一個子工程來獨立運行,我這里直接實現(xiàn)在了mscx-ad-db項目中
- 定義一個空接口,為了符合我們的編碼規(guī)范
- 實現(xiàn)service
- 實現(xiàn)Controller,提供操作入口
- 結(jié)果文件內(nèi)容如下,每一行都代表了一個推廣計劃
根據(jù)文件內(nèi)容構(gòu)建索引
我們在之前編寫索引服務(wù)的時候,創(chuàng)建了一些索引需要使用的實體對象類,比如構(gòu)建推廣計劃索引的時候,需要使用到的實體對象com.sxzhongf.ad.index.adplan.AdPlanIndexObject,可是呢,我們在上一節(jié)實現(xiàn)索引導(dǎo)出的時候,實體對象又是common 包中的com.sxzhongf.ad.common.export.table.AdPlanTable,讀取出來文件中的數(shù)據(jù)只能反序列化為JSON.parseObject(p, AdPlanTable.class),我們需要將2個對象做相互映射才能創(chuàng)建索引信息。
1.首先我們定義一個操作類型枚舉,代表我們每一次的操作類型(也需要對應(yīng)到后期binlog監(jiān)聽的操作類型)
public enum OperationTypeEnum {ADD,UPDATE,DELETE,OTHER;public static OperationTypeEnum convert(EventType type) {switch (type) {case EXT_WRITE_ROWS:return ADD;case EXT_UPDATE_ROWS:return UPDATE;case EXT_DELETE_ROWS:return DELETE;default:return OTHER;}} }2.因為全量索引的加載和增量索引加載的本質(zhì)是一樣的,全量索引其實就是一種特殊的增量索引,為了代碼的可復(fù)用,我們創(chuàng)建統(tǒng)一的類來操作索引。
/*** AdLevelDataHandler for 通用處理索引類* 1. 索引之間存在層級劃分,也就是相互之間擁有依賴關(guān)系的劃分* 2. 加載全量索引其實是增量索引 "添加"的一種特殊實現(xiàn)** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/ @Slf4j public class AdLevelDataHandler {/*** 實現(xiàn)廣告推廣計劃的第二層級索引實現(xiàn)。* (第一級為用戶層級,但是用戶層級不參與索引,所以從level 2開始)* 第二層級的索引是表示 不依賴于其他索引,但是可被其他索引所依賴*/public static void handleLevel2Index(AdPlanTable adPlanTable, OperationTypeEnum type) {// 對象轉(zhuǎn)換AdPlanIndexObject planIndexObject = new AdPlanIndexObject(adPlanTable.getPlanId(),adPlanTable.getUserId(),adPlanTable.getPlanStatus(),adPlanTable.getStartDate(),adPlanTable.getEndDate());//調(diào)用通用方法處理,使用IndexDataTableUtils#of來獲取索引的實現(xiàn)類beanhandleBinlogEvent(// 在前一節(jié)我們實現(xiàn)了一個索引工具類,來獲取注入的bean對象IndexDataTableUtils.of(AdPlanIndexAwareImpl.class),planIndexObject.getPlanId(),planIndexObject,type);}/*** 處理全量索引和增量索引的通用處理方式* K,V代表索引的鍵和值** @param index 索引實現(xiàn)代理類父級* @param key 鍵* @param value 值* @param type 操作類型*/private static <K, V> void handleBinlogEvent(IIndexAware<K, V> index, K key, V value, OperationTypeEnum type) {switch (type) {case ADD:index.add(key, value);break;case UPDATE:index.update(key, value);break;case DELETE:index.delete(key, value);break;default:break;}} }3.讀取文件實現(xiàn)全量索引加載。
因為我們文件加載之前需要依賴另一個組件,也就是我們的索引工具類,需要添加上@DependsOn("indexDataTableUtils"),全量索引在系統(tǒng)啟動的時候就需要加載,我們需要添加@PostConstruct來實現(xiàn)初始化加載,被@PostConstruct修飾的方法會在服務(wù)器加載Servlet的時候運行,并且只會被服務(wù)器調(diào)用一次。
@Component @DependsOn("indexDataTableUtils") public class IndexFileLoader {/*** 服務(wù)啟動時,執(zhí)行全量索引加載*/@PostConstructpublic void init() {//加載 推廣計劃List<String> adPlanStrings = loadExportedData(String.format("%s%s",FileConstant.DATA_ROOT_DIR, FileConstant.AD_PLAN));adPlanStrings.forEach(p -> AdLevelDataHandler.handleLevel2Index(JSON.parseObject(p, AdPlanTable.class), OperationTypeEnum.ADD));}/*** <h3>讀取全量索引加載需要的文件</h3>** @param fileName 文件名稱* @return 文件行數(shù)據(jù)*/private List<String> loadExportedData(String fileName) {try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) {return reader.lines().collect(Collectors.toList());} catch (IOException e) {throw new RuntimeException(e.getMessage());}} }Tips
在實現(xiàn)初始化加載全量索引的過程中,一定要保證數(shù)據(jù)加載的順序問題,因為不同的數(shù)據(jù)有可能存在著相互依賴的關(guān)聯(lián)關(guān)系,一旦順序?qū)戝e,會造成程序報錯問題。
轉(zhuǎn)載于:https://www.cnblogs.com/zhangpan1244/p/11324363.html
總結(jié)
以上是生活随笔為你收集整理的[Spring cloud 一步步实现广告系统] 14. 全量索引代码实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 洛谷 P4151 BZOJ 2115 [
- 下一篇: 重写Notification有感~~