上一节我们分析了广告索引的维护有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.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 { //注入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;
}
}

[Spring cloud 一步步实现广告系统] 13. 索引服务编码实现的更多相关文章

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

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

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

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

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

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

  4. [Spring cloud 一步步实现广告系统] 2. 配置&Eureka服务

    父项目管理 首先,我们在创建投放系统之前,先看一下我们的工程结构: mscx-ad-sponsor就是我们的广告投放系统.如上结构,我们需要首先创建一个Parent Project mscx-ad 来 ...

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

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

  6. [Spring cloud 一步步实现广告系统] 7. 中期总结回顾

    在前面的过程中,我们创建了4个project: 服务发现 我们使用Eureka 作为服务发现组件,学习了Eureka Server,Eureka Client的使用. Eureka Server 加依 ...

  7. [Spring cloud 一步步实现广告系统] 1. 业务架构分析

    什么是广告系统? 主要包含: 广告主投放广告的<广告投放系统> 媒体方(广告展示媒介-)检索广告用的<广告检索系统> 广告计费系统(按次,曝光量等等) 报表系统 Etc. 使用 ...

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

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

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

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

随机推荐

  1. webpack学习2.3webpack核心概念

    核心概念(四个) Entry(入口) Output(出口) Loaders()来处理其他类型的资源文件 Plugins(插件) 1.入口(Entry) 作用:代码的入口,打包的入口,单个或多个, 示例 ...

  2. 深入理解Kafka必知必会(3)

    Kafka中的事务是怎么实现的? Kafka中的事务可以使应用程序将消费消息.生产消息.提交消费位移当作原子操作来处理,同时成功或失败,即使该生产或消费会跨多个分区. 生产者必须提供唯一的transa ...

  3. excel中生成32位随机id

    记录下如何在EXCEL中利用公式生成32位的随机id(无符号,只有数字和小写字母). ,,)),),"",DEC2HEX(RANDBETWEEN(,,)),),"&quo ...

  4. 爬虫(五):代理IP、Cookie

    1. 代理IP 代理IP这个功能呢,在urllib和requests中都存在,但是这个在大的爬虫项目中是非常重要的,所以我拿出来单独讲解. 对于某些网站,如果同一个 IP 短时间内发送大量请求,则可能 ...

  5. 服务器(VPS)被墙怎么办?

    比如开发接口用的临时服务器被墙,就可以使用以下方法之一. 方法一(推荐) 为你的服务器分配一个浮动IP 等于给你的 droplet 增加一个新的 ip,我们以后访问这个新的ip就ok了. 直到下一次被 ...

  6. 腾讯云推出一站式 DevOps 解决方案 —— CODING DevOps

    在产业互联网的大背景下,如何将人工智能.大数据等前沿技术与实体产业相结合,推动传统企业转型升级,已经成为每一个企业不得不思考的问题.落后的软件研发能力已经拖慢了中国大量企业的数字化转型进程. 为了满足 ...

  7. Linux - CentOS 7 通过Yum源安装 MySql 5.7

    添加MySQL Yum存储库 从官网下载最新的mysql源 官网地址:https://dev.mysql.com/downloads/repo/yum/ 选择并下载适用于平台的发行包. 然后,在Lin ...

  8. 中移动物联手机端APP软件

    https://open.iot.10086.cn/doc/book/device-develop/multpro/sdk-doc-tool/APP.html

  9. Python——高阶函数概念(Higher-order function)

    1.变量可以指向函数 以内置的求绝对值abs()函数为例,: >>> abs(-12) 12 >>> abs <built-in function abs&g ...

  10. TensorFlow实现简单线性回归示例代码

    # -*- coding: utf-8 -*- import tensorflow as tf import numpy as np import matplotlib.pyplot as plt d ...