上一节我们分析了广告索引的维护有2种,全量索引加载增量索引维护。因为广告检索是广告系统中最为重要的环节,大家一定要认真理解我们索引设计的思路,接下来我们来编码实现索引维护功能。

我们来定义一个接口,来接收所有index的增删改查操作,接口定义一个范型,来接收2个参数,K代表我们索引的健值,V代表返回值。

/*** IIndexAware for 实现广告索引的增删改查** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
public interface IIndexAware<K, V> {/*** 通过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);
}

我们一定要知道,并不是所有的数据库表都需要创建索引,比如User表我们在数据检索的时候其实是不需要的,当然也就没必要创建索引,并且,也不是表中的所有字段都需要索引,这个也是根据具体的业务来确定字段信息,比如我们接下来要编写的推广计划索引中,推广计划名称就可以不需要。下面,我们来实现我们的第一个正向索引

  • 首先创建操作推广计划的实体对象
/*** AdPlanIndexObject for 推广计划索引对象* 这个索引对象我们没有添加 推广计划名称* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AdPlanIndexObject {private Long planId;private Long userId;private Integer planStatus;private Date startDate;private Date endDate;/*** 根据实际字段来更新索引*/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();}}
}
  • 然后创建推广计划索引实现类,并实现IIndexAware接口。
/*** AdPlanIndexAwareImpl for 推广计划索引实现类** @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Slf4j
@Component
public class AdPlanIndexAwareImpl implements IIndexAware<Long, AdPlanIndexObject> {private static Map<Long, AdPlanIndexObject> planIndexObjectMap;/*** 因为操作索引的过程中有可能对索引进行更新,为了防止多线程造成的线程不安全问题,我们不能使用hashmap,需要实现ConcurrentHashMap*/static {planIndexObjectMap = new ConcurrentHashMap<>();}@Overridepublic AdPlanIndexObject get(Long key) {return planIndexObjectMap.get(key);}@Overridepublic void add(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before add::{}", planIndexObjectMap);planIndexObjectMap.put(key, value);log.info("AdPlanIndexAwareImpl after add::{}", planIndexObjectMap);}@Overridepublic void update(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before update::{}", planIndexObjectMap);//查询当前的索引信息,如果不存在,直接新增索引信息AdPlanIndexObject oldObj = planIndexObjectMap.get(key);if (null == oldObj) {planIndexObjectMap.put(key, value);} else {oldObj.update(value);}log.info("AdPlanIndexAwareImpl after update::{}", planIndexObjectMap);}@Overridepublic void delete(Long key, AdPlanIndexObject value) {log.info("AdPlanIndexAwareImpl before delete::{}", planIndexObjectMap);planIndexObjectMap.remove(key);log.info("AdPlanIndexAwareImpl after delete::{}", planIndexObjectMap);}
}

至此,我们已经完成了推广计划的索引对象和索引操作的代码编写,大家可以参考上面的示例,依次完成推广单元推广创意地域兴趣关键词以及推广创意和推广单元的关联索引,或者可直接从 Github传送门 / Gitee传送门 下载源码。

按照上述代码展示,我们已经实现了所有的索引操作的定义,但是实际情况中,我们需要使用这些服务的时候,需要在每一个Service中@Autowired注入,我们那么多的索引操作类,还不包含后续还有可能需要新增的索引维度,工作量实在是太大,而且不方便维护,作为一个合格的程序员来说,这是非常不友好的,也许会让后续的开发人员骂娘。

为了防止后续被骂,我们来编写一个索引缓存工具类com.sxzhongf.ad.index.IndexDataTableUtils,通过这个索引缓存工具类来实现一次注入,解决后顾之忧。要实现这个工具类,我们需要实现2个接口:org.springframework.context.ApplicationContextAwareorg.springframework.core.PriorityOrdered

  • org.springframework.context.ApplicationContextAware, 统一通过实现该接口的类,来操作Spring容器以及其中的Bean实例。
    在Spring中,以Aware为后缀结束的类,大家可以简单的理解为应用程序想要XXX,比如ApplicationContextAware代表应用程序想要ApplicationContext,BeanFactoryAware 表示应用程序想要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 所有索引服务需要缓存的Java Bean** 使用方式:* 获取{@link com.sxzhongf.ad.index.creative.CreativeIndexAwareImpl}索引服务类* 如下:* {@code*   IndexDataTableUtils.of(CreativeIndexAwareImpl.class)* }* @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | 若初</a>*/
@Component
public class IndexDataTableUtils implements ApplicationContextAware, PriorityOrdered {//注入ApplicationContextprivate static ApplicationContext applicationContext;/*** 定义用于保存所有Index的Map* Class标示我们的索引类*/private static final Map<Class, Object> dataTableMap = new ConcurrentHashMap<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {IndexDataTableUtils.applicationContext = applicationContext;}/*** 获取索引服务缓存*/public static <T> T of(Class<T> klass) {T instance = (T) dataTableMap.get(klass);//如果获取到索引bean,直接返回当前beanif (null != instance) {return instance;}//首次获取索引bean为空,写入MapdataTableMap.put(klass, bean(klass));return (T) dataTableMap.get(klass);}/*** 获取Spring 容器中的Bean对象*/private static <T> T bean(String beanName) {return (T) applicationContext.getBean(beanName);}/*** 获取Spring 容器中的Bean对象*/private static <T> T bean(Class klass) {return (T) applicationContext.getBean(klass);}@Overridepublic int getOrder() {return PriorityOrdered.HIGHEST_PRECEDENCE;}
}

转载于:https://www.cnblogs.com/zhangpan1244/p/11318481.html

[Spring cloud 一步步实现广告系统] 13. 索引服务编码实现相关推荐

  1. [Spring cloud 一步步实现广告系统] 16. 增量索引实现以及投送数据到MQ(kafka)

    实现增量数据索引 上一节中,我们为实现增量索引的加载做了充足的准备,使用到mysql-binlog-connector-java 开源组件来实现MySQL 的binlog监听,关于binlog的相关知 ...

  2. [Spring cloud 一步步实现广告系统] 22. 广告系统回顾总结

    到目前为止,我们整个初级广告检索系统就初步开发完成了,我们来整体回顾一下我们的广告系统. 整个广告系统编码结构如下: 1.mscx-ad 父模块 主要是为了方便我们项目的统一管理 2.mscx-ad- ...

  3. [Spring cloud 一步步实现广告系统] 21. 系统错误汇总

    广告系统学习过程中问题答疑 博客园 Eureka集群启动报错 Answer 因为Eureka在集群启动过程中,会连接集群中其他的机器进行数据同步,在这个过程中,如果别的服务还没有启动完成,就会出现Co ...

  4. [Spring cloud 一步步实现广告系统] 19. 监控Hystrix Dashboard

    在之前的18次文章中,我们实现了广告系统的广告投放,广告检索业务功能,中间使用到了 服务发现Eureka,服务调用Feign,网关路由Zuul以及错误熔断Hystrix等Spring Cloud组件. ...

  5. [Spring cloud 一步步实现广告系统] 12. 广告索引介绍

    索引设计介绍 在我们广告系统中,为了我们能更快的拿到我们想要的广告数据,我们需要对广告数据添加类似于数据库index一样的索引结构,分两大类:正向索引和倒排索引. 正向索引 通过唯一键/主键生成与对象 ...

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

    上一节我们实现了索引基本操作的类以及索引缓存工具类,本小节我们开始实现加载全量索引数据,在加载全量索引数据之前,我们需要先将数据库中的表数据导出到一份文件中.Let's code. 1.首先定义一个常 ...

  7. [Spring cloud 一步步实现广告系统] 11. 使用Feign实现微服务调用

    上一节我们使用了Ribbon(基于Http/Tcp)进行微服务的调用,Ribbon的调用比较简单,通过Ribbon组件对请求的服务进行拦截,通过Eureka Server 获取到服务实例的IP:Por ...

  8. feign响应拦截_[Spring cloud 一步步实现广告系统] 11. 使用Feign实现微服务调用

    上一节我们使用了Ribbon(基于Http/Tcp)进行微服务的调用,Ribbon的调用比较简单,通过Ribbon组件对请求的服务进行拦截,通过Eureka Server 获取到服务实例的IP:Por ...

  9. [Spring cloud 一步步实现广告系统] 15. 使用开源组件监听Binlog 实现增量索引准备...

    MySQL Binlog简介 什么是binlog? 一个二进制日志,用来记录对数据发生或潜在发生更改的SQL语句,并以而进行的形式保存在磁盘中. binlog 的作用? 最主要有3个用途: 数据复制( ...

最新文章

  1. Activity的setResult方法
  2. Zynq的AMP开发注意事项之禁用L2 cache
  3. 【字节网盘】九款超好看不同页面404源码
  4. cmake的一个编译报错
  5. 个位百位AS3实现经典算法(二) 水仙花数
  6. Java反射----获取Class类实例的4种方式
  7. 动态库的隐式链接和显示链接
  8. WinRAR5.60 64位 官方无广告正式版注册破解
  9. linux i350网卡,intel I350 网卡驱动安装方法
  10. 如何正确的制定目标?(只需4步)
  11. 2017 Multi-University Training Contest - Team 10
  12. 阿里巴巴的类ChatGPT产品
  13. 玫瑰线 matlab,如何用MATLAB画玫瑰线
  14. Python爬虫第二课 Selenium介绍和反爬技术
  15. unity3d如何获知场景中需要加载的数据_游戏中遮挡剔除方案总结
  16. 树莓派3b安装新系统的步骤和一些问题
  17. element-ui 获取当前行的 id
  18. 小程序流量主能赚多少_微信:6月1日起调整小程序和公众号流量主广告收入分成比例...
  19. 【CV】图像融合结果评价
  20. 10大电子书免费下载网站

热门文章

  1. 心得体悟帖---12、志向还是太短浅,目光也是
  2. Cisco 交換機命名規則
  3. Java之构造器和构造方法的使用和意义
  4. Spring MVC静态资源处理
  5. JavaScript基础——处理字符串
  6. jQuery学习笔记之extend方法小结
  7. Python基础(3) - 数据类型:2字符串类型
  8. Java学习之 多态 Polymorphism
  9. Bootstrap—基础样式定义
  10. 一个高(3D/2D)动态表现的酷站