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

简介: 上一节我们分析了广告索引的维护有2种,全量索引加载和增量索引维护。因为广告检索是广告系统中最为重要的环节,大家一定要认真理解我们索引设计的思路,接下来我们来编码实现索引维护功能。我们来定义一个接口,来接收所有index的增删改查操作,接口定义一个范型,来接收2个参数,K代表我们索引的健值,V代表返回值。

上一节我们分析了广告索引的维护有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;
    }
}
目录
相关文章
|
4月前
|
负载均衡 算法 Java
【SpringCloud(4)】OpenFeign客户端:OpenFeign服务绑定;调用服务接口;Feign和OpenFeign
Feign是一个WebService客户端。使用Feign能让编写WebService客户端更加简单。 它的使用方法是定义一个服务接口然后再上面添加注解。Feign也支持可拔插式的编码器和解码器。SpringCloud对Feign进行了封装,十七支持了SpringMVC标准注解和HttpMessageConverters。 Feign可用于Eureka和Ribbon组合使用以支持负载均衡
785 139
|
人工智能 Java Serverless
【MCP教程系列】搭建基于 Spring AI 的 SSE 模式 MCP 服务并自定义部署至阿里云百炼
本文详细介绍了如何基于Spring AI搭建支持SSE模式的MCP服务,并成功集成至阿里云百炼大模型平台。通过四个步骤实现从零到Agent的构建,包括项目创建、工具开发、服务测试与部署。文章还提供了具体代码示例和操作截图,帮助读者快速上手。最终,将自定义SSE MCP服务集成到百炼平台,完成智能体应用的创建与测试。适合希望了解SSE实时交互及大模型集成的开发者参考。
13851 60
|
10月前
|
存储 Java 数据库
Spring Boot 注册登录系统:问题总结与优化实践
在Spring Boot开发中,注册登录模块常面临数据库设计、密码加密、权限配置及用户体验等问题。本文以便利店销售系统为例,详细解析四大类问题:数据库字段约束(如默认值缺失)、密码加密(明文存储风险)、Spring Security配置(路径权限不当)以及表单交互(数据丢失与提示不足)。通过优化数据库结构、引入BCrypt加密、完善安全配置和改进用户交互,提供了一套全面的解决方案,助力开发者构建更 robust 的系统。
354 0
|
7月前
|
存储 人工智能 自然语言处理
用Spring AI搭建本地RAG系统:让AI成为你的私人文档助手
想让AI帮你读懂PDF文档吗?本文教你用Spring AI和Ollama搭建一个本地RAG系统,让AI成为你的私人文档助手。无需GPU,无需云端API,只需几行代码,你的文档就能开口说话了!
1692 2
|
10月前
|
存储 人工智能 Java
Spring AI与DeepSeek实战四:系统API调用
在AI应用开发中,工具调用是增强大模型能力的核心技术,通过让模型与外部API或工具交互,可实现实时信息检索(如天气查询、新闻获取)、系统操作(如创建任务、发送邮件)等功能;本文结合Spring AI与大模型,演示如何通过Tool Calling实现系统API调用,同时处理多轮对话中的会话记忆。
2102 57
|
消息中间件 存储 Java
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统
本文详细介绍了如何使用Spring Boot 3结合RabbitMQ构建高效可靠的聊天消息存储系统。通过引入消息队列,实现了聊天功能与消息存储的解耦,解决了高并发场景下直接写入数据库带来的性能瓶颈问题。文章首先分析了不同MQ产品的特点及适用场景,最终选择RabbitMQ作为解决方案,因其成熟稳定、灵活路由和易于集成等优势。接着,通过Docker快速部署RabbitMQ,并完成Spring Boot项目的配置与代码实现,包括生产者发送消息、消费者接收并处理消息等功能。最后,通过异步存储机制,既保证了消息的即时性,又实现了可靠持久化。
805 0
📨 Spring Boot 3 整合 MQ 构建聊天消息存储系统
|
7月前
|
Prometheus 监控 Cloud Native
Docker 部署 Prometheus 和 Grafana 监控 Spring Boot 服务
Docker 部署 Prometheus 和 Grafana 监控 Spring Boot 服务实现步骤
701 0
|
8月前
|
Java 调度 流计算
基于Java 17 + Spring Boot 3.2 + Flink 1.18的智慧实验室管理系统核心代码
这是一套基于Java 17、Spring Boot 3.2和Flink 1.18开发的智慧实验室管理系统核心代码。系统涵盖多协议设备接入(支持OPC UA、MQTT等12种工业协议)、实时异常检测(Flink流处理引擎实现设备状态监控)、强化学习调度(Q-Learning算法优化资源分配)、三维可视化(JavaFX与WebGL渲染实验室空间)、微服务架构(Spring Cloud构建分布式体系)及数据湖建设(Spark构建实验室数据仓库)。实际应用中,该系统显著提升了设备调度效率(响应时间从46分钟降至9秒)、设备利用率(从41%提升至89%),并大幅减少实验准备时间和维护成本。
439 0
|
11月前
|
人工智能 自然语言处理 Java
对话即服务:Spring Boot整合MCP让你的CRUD系统秒变AI助手
本文介绍了如何通过Model Context Protocol (MCP) 协议将传统Spring Boot服务改造为支持AI交互的智能系统。MCP作为“万能适配器”,让AI以统一方式与多种服务和数据源交互,降低开发复杂度。文章以图书管理服务为例,详细说明了引入依赖、配置MCP服务器、改造服务方法(注解方式或函数Bean方式)及接口测试的全流程。最终实现用户通过自然语言查询数据库的功能,展示了MCP在简化AI集成、提升系统易用性方面的价值。未来,“对话即服务”有望成为主流开发范式。
7996 7

热门文章

最新文章