成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

[Spring cloud 一步步實(shí)現(xiàn)廣告系統(tǒng)] 14. 全量索引代碼實(shí)現(xiàn)

MycLambert / 3209人閱讀

摘要:各個(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é)我們開始實(shí)現(xiàn)加載全量索引數(shù)據(jù),在加載全量索引數(shù)據(jù)之前,我們需要先將數(shù)據(jù)庫中的表數(shù)據(jù)導(dǎo)出到一份文件中。Let"s code.

1.首先定義一個(gè)常量類,用來存儲(chǔ)導(dǎo)出文件存儲(chǔ)的目錄和文件名稱

因?yàn)槲覀儗?dǎo)出的文件需要在搜索服務(wù)中使用到,因此,我們將文件名 & 目錄以及導(dǎo)出對(duì)象的信息編寫在mscx-ad-commom項(xiàng)目中。
public class FileConstant {
    public static final String DATA_ROOT_DIR = "/Users/xxx/Documents/promotion/data/mysql/";

    //各個(gè)表數(shù)據(jù)的存儲(chǔ)文件名
    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.定義索引對(duì)象導(dǎo)出的字段信息,依然用Ad_Plan為例。

/**
 * AdPlanTable for 需要導(dǎo)出的表字段信息 => 是搜索索引字段一一對(duì)應(yīng)
 *
 * @author Isaac.Zhang | 若初
 */
@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ù)實(shí)現(xiàn)

同樣,最好的實(shí)現(xiàn)方式就是將導(dǎo)出服務(wù)作為一個(gè)子工程來獨(dú)立運(yùn)行,我這里直接實(shí)現(xiàn)在了mscx-ad-db項(xiàng)目中

定義一個(gè)空接口,為了符合我們的編碼規(guī)范

/**
 * IExportDataService for 導(dǎo)出數(shù)據(jù)庫廣告索引初始化數(shù)據(jù)
 *
 * @author Isaac.Zhang | 若初
 */
public interface IExportDataService {
}

實(shí)現(xiàn)service

@Slf4j
@Service
public class ExportDataServiceImpl implements IExportDataService {

    @Autowired
    private AdPlanRepository planRepository;

    /**
     * 導(dǎo)出 {@code AdPlan} from DB to File
     *
     * @param fileName 文件名稱
     */
    public void exportAdPlanTable(String fileName) {
        List planList = planRepository.findAllByPlanStatus(CommonStatus.VALID.getStatus());
        if (CollectionUtils.isEmpty(planList)) {
            return;
        }

        List planTables = new ArrayList<>();
        planList.forEach(item -> planTables.add(
                new AdPlanTable(
                        item.getPlanId(),
                        item.getUserId(),
                        item.getPlanStatus(),
                        item.getStartDate(),
                        item.getEndDate()
                )
        ));

        //將數(shù)據(jù)寫入文件
        Path path = Paths.get(fileName);
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            for (AdPlanTable adPlanTable : planTables) {
                writer.write(JSON.toJSONString(adPlanTable));
                writer.newLine();
            }
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
            log.error("export AdPlanTable Exception!");
        }
    }
}

實(shí)現(xiàn)Controller,提供操作入口

@Slf4j
@Controller
@RequestMapping("/export")
public class ExportDataController {
    private final ExportDataServiceImpl exportDataService;

    @Autowired
    public ExportDataController(ExportDataServiceImpl exportDataService) {
        this.exportDataService = exportDataService;
    }

    @GetMapping("/export-plan")
    public CommonResponse exportAdPlans() {

        exportDataService.exportAdPlanTable(String.format("%s%s", FileConstant.DATA_ROOT_DIR, FileConstant.AD_PLAN));
        return new CommonResponse();
    }
}

結(jié)果文件內(nèi)容如下,每一行都代表了一個(gè)推廣計(jì)劃

{"endDate":1561438800000,"planId":10,"planStatus":1,"startDate":1561438800000,"userId":10}
{"endDate":1561438800000,"planId":11,"planStatus":1,"startDate":1561438800000,"userId":10}
根據(jù)文件內(nèi)容構(gòu)建索引

我們?cè)谥熬帉懰饕?wù)的時(shí)候,創(chuàng)建了一些索引需要使用的實(shí)體對(duì)象類,比如構(gòu)建推廣計(jì)劃索引的時(shí)候,需要使用到的實(shí)體對(duì)象com.sxzhongf.ad.index.adplan.AdPlanIndexObject,可是呢,我們?cè)谏弦还?jié)實(shí)現(xiàn)索引導(dǎo)出的時(shí)候,實(shí)體對(duì)象又是common 包中的com.sxzhongf.ad.common.export.table.AdPlanTable,讀取出來文件中的數(shù)據(jù)只能反序列化為JSON.parseObject(p, AdPlanTable.class),我們需要將2個(gè)對(duì)象做相互映射才能創(chuàng)建索引信息。

1.首先我們定義一個(gè)操作類型枚舉,代表我們每一次的操作類型(也需要對(duì)應(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.因?yàn)槿克饕募虞d和增量索引加載的本質(zhì)是一樣的,全量索引其實(shí)就是一種特殊的增量索引,為了代碼的可復(fù)用,我們創(chuàng)建統(tǒng)一的類來操作索引。

/**
 * AdLevelDataHandler for 通用處理索引類
 * 1. 索引之間存在層級(jí)劃分,也就是相互之間擁有依賴關(guān)系的劃分
 * 2. 加載全量索引其實(shí)是增量索引 "添加"的一種特殊實(shí)現(xiàn)
 *
 * @author Isaac.Zhang | 若初
 */
@Slf4j
public class AdLevelDataHandler {

    /**
     * 實(shí)現(xiàn)廣告推廣計(jì)劃的第二層級(jí)索引實(shí)現(xiàn)。
     * (第一級(jí)為用戶層級(jí),但是用戶層級(jí)不參與索引,所以從level 2開始)
     * 第二層級(jí)的索引是表示 不依賴于其他索引,但是可被其他索引所依賴
     */
    public static void handleLevel2Index(AdPlanTable adPlanTable, OperationTypeEnum type) {
          // 對(duì)象轉(zhuǎn)換
        AdPlanIndexObject planIndexObject = new AdPlanIndexObject(
                adPlanTable.getPlanId(),
                adPlanTable.getUserId(),
                adPlanTable.getPlanStatus(),
                adPlanTable.getStartDate(),
                adPlanTable.getEndDate()
        );

        //調(diào)用通用方法處理,使用IndexDataTableUtils#of來獲取索引的實(shí)現(xiàn)類bean
        handleBinlogEvent(
                      // 在前一節(jié)我們實(shí)現(xiàn)了一個(gè)索引工具類,來獲取注入的bean對(duì)象
                IndexDataTableUtils.of(AdPlanIndexAwareImpl.class),
                planIndexObject.getPlanId(),
                planIndexObject,
                type
        );
    }

    /**
     * 處理全量索引和增量索引的通用處理方式
     * K,V代表索引的鍵和值
     *
     * @param index 索引實(shí)現(xiàn)代理類父級(jí)
     * @param key   鍵
     * @param value 值
     * @param type  操作類型
     */
    private static  void handleBinlogEvent(IIndexAware 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.讀取文件實(shí)現(xiàn)全量索引加載。

因?yàn)槲覀兾募虞d之前需要依賴另一個(gè)組件,也就是我們的索引工具類,需要添加上@DependsOn("indexDataTableUtils"),全量索引在系統(tǒng)啟動(dòng)的時(shí)候就需要加載,我們需要添加@PostConstruct來實(shí)現(xiàn)初始化加載,被@PostConstruct修飾的方法會(huì)在服務(wù)器加載Servlet的時(shí)候運(yùn)行,并且只會(huì)被服務(wù)器調(diào)用一次。
@Component
@DependsOn("indexDataTableUtils")
public class IndexFileLoader {

    /**
     * 服務(wù)啟動(dòng)時(shí),執(zhí)行全量索引加載
     */
    @PostConstruct
    public void init() {
        //加載 推廣計(jì)劃
        List 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
        ));
    }

    /**
     * 

讀取全量索引加載需要的文件

* * @param fileName 文件名稱 * @return 文件行數(shù)據(jù) */ private List 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

在實(shí)現(xiàn)初始化加載全量索引的過程中,一定要保證數(shù)據(jù)加載的順序問題,因?yàn)椴煌臄?shù)據(jù)有可能存在著相互依賴的關(guān)聯(lián)關(guān)系,一旦順序?qū)戝e(cuò),會(huì)造成程序報(bào)錯(cuò)問題。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/75945.html

相關(guān)文章

  • [Spring cloud 步步實(shí)現(xiàn)廣告系統(tǒng)] 12. 廣告索引介紹

    摘要:索引設(shè)計(jì)介紹在我們廣告系統(tǒng)中,為了我們能更快的拿到我們想要的廣告數(shù)據(jù),我們需要對(duì)廣告數(shù)據(jù)添加類似于數(shù)據(jù)庫一樣的索引結(jié)構(gòu),分兩大類正向索引和倒排索引。如何在廣告系統(tǒng)中使用倒排索引核心用途是對(duì)各個(gè)維度限制的整理。 索引設(shè)計(jì)介紹 在我們廣告系統(tǒng)中,為了我們能更快的拿到我們想要的廣告數(shù)據(jù),我們需要對(duì)廣告數(shù)據(jù)添加類似于數(shù)據(jù)庫index一樣的索引結(jié)構(gòu),分兩大類:正向索引和倒排索引。 正向索引 通過...

    endless_road 評(píng)論0 收藏0
  • [Spring cloud 步步實(shí)現(xiàn)廣告系統(tǒng)] 13. 索引服務(wù)編碼實(shí)現(xiàn)

    摘要:上一節(jié)我們分析了廣告索引的維護(hù)有種,全量索引加載和增量索引維護(hù)。因?yàn)閺V告檢索是廣告系統(tǒng)中最為重要的環(huán)節(jié),大家一定要認(rèn)真理解我們索引設(shè)計(jì)的思路,接下來我們來編碼實(shí)現(xiàn)索引維護(hù)功能。 上一節(jié)我們分析了廣告索引的維護(hù)有2種,全量索引加載和增量索引維護(hù)。因?yàn)閺V告檢索是廣告系統(tǒng)中最為重要的環(huán)節(jié),大家一定要認(rèn)真理解我們索引設(shè)計(jì)的思路,接下來我們來編碼實(shí)現(xiàn)索引維護(hù)功能。 我們來定義一個(gè)接口,來接收所有...

    stefanieliang 評(píng)論0 收藏0
  • [Spring cloud 步步實(shí)現(xiàn)廣告系統(tǒng)] 7. 中期總結(jié)回顧

    摘要:在前面的過程中,我們創(chuàng)建了個(gè)服務(wù)發(fā)現(xiàn)我們使用作為服務(wù)發(fā)現(xiàn)組件,學(xué)習(xí)了的使用。加依賴加注解改配置使用項(xiàng)目三部曲,我們可以快速添加一個(gè)新組件,并正常使用這個(gè)我沒有在項(xiàng)目中實(shí)現(xiàn),但是大家可以和一樣,三部曲搞定。 在前面的過程中,我們創(chuàng)建了4個(gè)project: 服務(wù)發(fā)現(xiàn) 我們使用Eureka 作為服務(wù)發(fā)現(xiàn)組件,學(xué)習(xí)了Eureka Server,Eureka Client的使用。 Eureka...

    cnsworder 評(píng)論0 收藏0
  • [Spring cloud 步步實(shí)現(xiàn)廣告系統(tǒng)] 8. 檢索系統(tǒng)配置&依賴

    摘要:工作流程項(xiàng)目依賴監(jiān)控面板引入服務(wù)調(diào)用的組件依賴引入服務(wù)消費(fèi)者的依賴數(shù)據(jù)庫鏈接依賴工具類集合類操作日志監(jiān)聽解析開源工具類庫中的配置相關(guān)依賴圖片壓縮 工作流程 showImg(https://i.loli.net/2019/07/29/5d3ee1829df4d57461.png); 項(xiàng)目依賴 org.springframewo...

    dailybird 評(píng)論0 收藏0
  • [Spring cloud 步步實(shí)現(xiàn)廣告系統(tǒng)] 11. 使用Feign實(shí)現(xiàn)微服務(wù)調(diào)用

    摘要:上一節(jié)我們使用了基于進(jìn)行微服務(wù)的調(diào)用,的調(diào)用比較簡(jiǎn)單,通過組件對(duì)請(qǐng)求的服務(wù)進(jìn)行攔截,通過獲取到服務(wù)實(shí)例的然后再去調(diào)用。為了代碼的重用性,我們來創(chuàng)建一個(gè)新的作為的服務(wù)調(diào)用工具。 上一節(jié)我們使用了Ribbon(基于Http/Tcp)進(jìn)行微服務(wù)的調(diào)用,Ribbon的調(diào)用比較簡(jiǎn)單,通過Ribbon組件對(duì)請(qǐng)求的服務(wù)進(jìn)行攔截,通過Eureka Server 獲取到服務(wù)實(shí)例的IP:Port,然后再去...

    Forest10 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<