[Spring cloud 一步步实现广告系统] 13. 索引服务编码实现
上一节我们分析了广告索引的维护有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<>();
}
@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);
//查询当前的索引信息,如果不存在,直接新增索引信息
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);
}
}
至此,我们已经完成了推广计划的索引对象和索引操作的代码编写,大家可以参考上面的示例,依次完成推广单元
、推广创意
、地域
、兴趣
、关键词
以及推广创意和推广单元的关联索引
,或者可直接从 Github传送门 / Gitee传送门 下载源码。
按照上述代码展示,我们已经实现了所有的索引操作的定义,但是实际情况中,我们需要使用这些服务的时候,需要在每一个Service中
@Autowired
注入,我们那么多的索引操作类,还不包含后续还有可能需要新增的索引维度,工作量实在是太大,而且不方便维护,作为一个合格的程序员来说,这是非常不友好的,也许会让后续的开发人员骂娘。
为了防止后续被骂,我们来编写一个索引缓存工具类com.sxzhongf.ad.index.IndexDataTableUtils
,通过这个索引缓存工具类来实现一次注入,解决后顾之忧。要实现这个工具类,我们需要实现2个接口:org.springframework.context.ApplicationContextAware
和org.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 {
//注入ApplicationContext
private static ApplicationContext applicationContext;
/**
* 定义用于保存所有Index的Map
* Class标示我们的索引类
*/
private static final Map<Class, Object> dataTableMap = new ConcurrentHashMap<>();
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
IndexDataTableUtils.applicationContext = applicationContext;
}
/**
* 获取索引服务缓存
*/
public static <T> T of(Class<T> klass) {
T instance = (T) dataTableMap.get(klass);
//如果获取到索引bean,直接返回当前bean
if (null != instance) {
return instance;
}
//首次获取索引bean为空,写入Map
dataTableMap.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);
}
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE;
}
}

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
MessagePack Java 0.6.X 动态类型
我们知道 Java 是一个静态类型的语言。通过输入ValueMessagePack能够实现动态的特性。 Value有方法来检查自己的类型(isIntegerType(),isArrayType(), 等...),同时也转换为自己的类型 (asStringValue(),convert(Template))。 本代码可以在https://github.com/cwiki-us-demo/messagepack-6-demo-java/blob/master/src/test/java/com/insight/demo/msgpack/MessagePack6DynamicTyping.java中查看。 packagecom.insight.demo.msgpack; importorg.junit.Test;importorg.msgpack.MessagePack;importorg.msgpack.type.Value;importorg.msgpack.unpacker.Converter;importorg.slf4j.Logger;importorg.slf4j.LoggerF...
-
下一篇
Dotnet3.0下SnowFlake算法生成53位ID
世界上没有两片雪花是完全相同的。 为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的ID,这些id还需要一些大致的顺序(方便客户端排序),并且在分布式系统中不同机器产生的ID必须不同。Twitter公司提出了一种名为SnowFlake算法来生成唯一的ID作为系统中的key。 为何需要生成ID? 在应用程序中,经常需要全局唯一的ID作为数据库中表主键。如何生成全局唯一ID? 首先,需要确定全局唯一ID是整型还是字符串?如果是字符串,那么现有的UUID就完全满足需求,不需要额外的工作。缺点是字符串作为ID占用空间大,索引效率比整型低。 通常情况下,我们都会使用数据库的自增主键功能,从1开始,基本可以做到连续递增。Oracle可以用SEQUENCE,MySQL可以用表主键的AUTO_INCREMENT, 虽然不能保证全局唯一,但每个表唯一,也基本满足需求。 但是这样的做法有两个问题,第一个是每次生成都是先要插入数据库,让数据库去生成这个ID后返回。当需要插入关联数据的时候,必须先等数据库插入成功,然后才能插入关联数据。如果插入过程比较长,需要用队列操作的时候,就无法将相...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- MySQL8.0.19开启GTID主从同步CentOS8
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS8编译安装MySQL8.0.19
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7设置SWAP分区,小内存服务器的救世主