大发uu快3_uu快3最新版_大发uu快3最新版 - 大发uu快3,uu快3最新版,大发uu快3最新版,24小时提供时政新闻,国内新闻,国际新闻,生活新闻,时事热点,新闻图片,军事,历史,生活,大发uu快3,uu快3最新版,大发uu快3最新版的专业时事报道门户网站

[Spring cloud 一步步实现广告系统] 14. 全量索引代码实现

  • 时间:
  • 浏览:5

上一节大伙儿实现了索引基本操作的类以及索引缓存工具类,本小节大伙儿现在刚开始实现加载全量索引数据,在加载全量索引数据事先 ,大伙儿都可以先将数据库中的表数据导出到一份文件中。Let's code.

1.首先定义事先常量类,用来存储导出文件存储的目录和文件名称

事先 大伙儿导出的文件都可以在搜索服务中使用到,就让,大伙儿将文件名 & 目录以及导出对象的信息编写在mscx-ad-commom项目中。

public class FileConstant {
    public static final String DATA_ROOT_DIR = "/Users/xxx/Documents/promotion/data/mysql/";

    //各个表数据的存储文件名
    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.定义索引对象导出的字段信息,依然用Ad_Plan为例。

/**
 * AdPlanTable for 都可以导出的表字段信息 => 是搜索索引字段一一对应
 *
 * @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.导出文件服务实现

同样,最好的实现辦法 就让将导出服务作为事先子工程来独立运行,我这里直接实现在了mscx-ad-db项目中

  • 定义事先空接口,为了符合大伙儿的编码规范
/**
 * IExportDataService for 导出数据库广告索引初始化数据
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
 */
public interface IExportDataService {
}
  • 实现service
@Slf4j
@Service
public class ExportDataServiceImpl implements IExportDataService {

    @Autowired
    private AdPlanRepository planRepository;

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

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

        //将数据写入文件
        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!");
        }
    }
}
  • 实现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();
    }
}
  • 结果文件内容如下,每一行都代表了事先推广计划
{"endDate":156143810000000,"planId":10,"planStatus":1,"startDate":156143810000000,"userId":10}
{"endDate":156143810000000,"planId":11,"planStatus":1,"startDate":156143810000000,"userId":10}
根据文件内容构建索引

大伙儿在事先 编写索引服务的事先 ,创建了或多或少索引都可以使用的实体对象类,比如构建推广计划索引的事先 ,都可以使用到的实体对象com.sxzhongf.ad.index.adplan.AdPlanIndexObject,事先呢,大伙儿在上一节实现索引导出的事先 ,实体对象又是common 包中的com.sxzhongf.ad.common.export.table.AdPlanTable,读取出来文件中的数据不到反序列化为JSON.parseObject(p, AdPlanTable.class),大伙儿都可以将事先对象做相互映射都可以创建索引信息。

1.首先大伙儿定义事先操作类型枚举,代表大伙儿每一次的操作类型(也都可以对应到后期binlog监听的操作类型

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.事先 全量索引的加载和增量索引加载的本质是一样的,全量索引人太好就让五种特殊的增量索引,为了代码的可复用,大伙儿创建统一的类来操作索引。

/**
 * AdLevelDataHandler for 通用避免索引类
 * 1. 索引之间位于层级划分,也就让相互之间拥有依赖关系的划分
 * 2. 加载全量索引人太好是增量索引 "加进去去"的五种特殊实现
 *
 * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>
 */
@Slf4j
public class AdLevelDataHandler {

    /**
     * 实现广告推广计划的第二层级索引实现。
     * (第一级为用户层级,就让用户层级不参与索引,或多或少或多或少从level 2现在刚开始)
     * 第二层级的索引是表示 不依赖于或多或少索引,就让可被或多或少索引所依赖
     */
    public static void handleLevel2Index(AdPlanTable adPlanTable, OperationTypeEnum type) {
        // 对象转换
        AdPlanIndexObject planIndexObject = new AdPlanIndexObject(
                adPlanTable.getPlanId(),
                adPlanTable.getUserId(),
                adPlanTable.getPlanStatus(),
                adPlanTable.getStartDate(),
                adPlanTable.getEndDate()
        );

        //调用通用辦法

避免,使用IndexDataTableUtils#of来获取索引的实现类bean
        handleBinlogEvent(
                    // 在前一节大伙儿实现了事先索引工具类,来获取注入的bean对象
                IndexDataTableUtils.of(AdPlanIndexAwareImpl.class),
                planIndexObject.getPlanId(),
                planIndexObject,
                type
        );
    }

    /**
     * 避免全量索引和增量索引的通用避免辦法

     * K,V代表索引的键和值
     *
     * @param index 索引实现代理类父级
     * @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.读取文件实现全量索引加载。

事先 大伙儿文件加载事先 都可以依赖事先组件,也就让大伙儿的索引工具类,都可以加进去去进去@DependsOn("indexDataTableUtils"),全量索引在系统启动的事先 就都可以加载,大伙儿都可以加进去去@PostConstruct来实现初始化加载,被@PostConstruct修饰的辦法 会在服务器加载Servlet的事先 运行,就让只会被服务器调用一次。

@Component
@DependsOn("indexDataTableUtils")
public class IndexFileLoader {

    /**
     * 服务启动时,执行全量索引加载
     */
    @PostConstruct
    public 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 文件行数据
     */
    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

在实现初始化加载全量索引的过程中,一定要保证数据加载的顺序问题报告 ,事先 不同的数据有事先 位于着相互依赖的关联关系,一旦顺序写错,会造成应用应用程序报错问题报告 。