基于SpringBoot的ES整合

基于SpringBoot的ES整合

Elasticsearch(ES)的作用可看之前的课件

这儿直接演示使用ES检索学习资料的功能。

步骤一:引入相关依赖,在文件中smpe-system下的pom.xml中引入下面依赖

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <!-- 这儿的版本需要和本地的版本保持一致 -->
    <version>7.8.0</version>
</dependency>

步骤二:添加一个配置类,新建目录层级tiku/config/ElasticSearchClientConfig

[图片上传失败...(image-61aba2-1650806738439)]

@Configuration
public class ElasticSearchClientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("127.0.0.1", 9200, "http"))
        );
        return client;
    }
}

步骤三:项目启动的时候将需要的数据加载进ES中

@Component
@Slf4j
@RequiredArgsConstructor
public class StudyDataRunner implements ApplicationRunner {

    private final RestHighLevelClient restHighLevelClient;
    private final IEStudyDataService studyDataService;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 查询所有的学习资料数据,加载到es中
        log.info("往es中存储数据开始------------");
        PageVO pageVO = new PageVO();
        pageVO.setSize(-1);
        pageVO.setCurrent(-1);
        IPage<EStudyData> eStudyDataIPage = studyDataService.queryAll(new StudyDataQueryCriteria(), pageVO);
        List<EStudyData> records = eStudyDataIPage.getRecords();
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.timeout("2m");
        for (EStudyData record : records) {
            bulkRequest.add(new IndexRequest("study_data").source(JSON.toJSONString(record), XContentType.JSON));
        }
        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);


        log.info("es存储数据结束----------------");
    }
}

步骤四:对接查询操作

    @ApiOperation(value="前台:分页查询某个安全类别的学习资料",notes="\n anthor:mfei")
    @AnonymousGetMapping("/front-all")
    public Result<Object> queryES(Long safeTypeId, String keyword,PageVO pageVO){
        pageVO.setOrders("[{'column': 'create_time','asc': false}]");
        StudyDataQueryCriteria criteria = new StudyDataQueryCriteria();
        criteria.setKeywords(keyword);
        criteria.setSafeTypeId(safeTypeId);
        return Result.success(eStudyDataService.queryAllByES(criteria,pageVO));
    }
}

IEStudyDataService接口

IPage<EStudyData> queryAllByES(StudyDataQueryCriteria criteria, PageVO pageVO);

实现类

@Override
public IPage<EStudyData> queryAllByES(StudyDataQueryCriteria criteria, PageVO pageVO) {
    List<EStudyData> eStudyDataList = new ArrayList<>();
    SearchRequest searchRequest = new SearchRequest("study_data");

    // 构建搜索条件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
    if (ObjectUtil.isNotNull(criteria.getKeywords())){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .should(QueryBuilders.matchQuery("title", criteria.getKeywords()))
                .should(QueryBuilders.matchQuery("keywords", criteria.getKeywords()));
        sourceBuilder.query(boolQueryBuilder);

        //构建高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.requireFieldMatch(true); // 多个高亮显示
        highlightBuilder.field("title");
        highlightBuilder.preTags("<span style='color:red'>").postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);
    }

    if (ObjectUtil.isNotNull(criteria.getSafeTypeId())) {
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("safeTypeId", criteria.getSafeTypeId());
        sourceBuilder.query(termQueryBuilder);
    }

    searchRequest.source(sourceBuilder);
    try {
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        for (SearchHit documentFields : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> highlightFields = documentFields.getHighlightFields();
            HighlightField title = highlightFields.get("title");
            Map<String, Object> sourceAsMap = documentFields.getSourceAsMap();// 最开始的结果
            if (ObjectUtil.isNotNull(title)) {
                Text[] fragments = title.fragments();
                String n_title = "";
                for (Text fragment : fragments) {
                    n_title += fragment;
                }
                sourceAsMap.put("title", n_title);
            }
            EStudyData eStudyData = BeanUtil.fillBeanWithMap(sourceAsMap, new EStudyData(), false);
            eStudyDataList.add(eStudyData);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    IPage<EStudyData> eStudyDataIPage = new Page<>();
    eStudyDataIPage.setRecords(eStudyDataList);
    return eStudyDataIPage;
}

题库练习模块实现

  • 查询该类型下所有的题型(ERepositoryController中)
/**
 * 前台调用   返回题库和练习记录id
 *
 * @param id
 * @return
 */
@ApiOperation(value = "按安全分类id查询")
@GetMapping(value = "/getBySafeTypeId")
public Result<ERepositoryAndPracticeRecordDTO> getRepositoryBySafeTypeId(Long id) {
    if (id == null || id <= 0) {
        throw new BadRequestException("id不能为空,且id不能小于0");
    }
    ERepositoryAndPracticeRecordDTO eRepositoryAndPracticeRecordDTO = eRepositoryService.getRepositoryAndPracticeRecordIdBySafeTypeId(id);
    return Result.success(eRepositoryAndPracticeRecordDTO);
}

返回对象ERepositoryAndPracticeRecordDTO为

[图片上传失败...(image-bbead3-1650806738439)]

[图片上传失败...(image-f674ba-1650806738439)]

定义IERepositoryService中的查询接口

/**
 * 根据分类id查询题目(前台  返回某个分类的全部题库和练习记录表中的id)
 * @param id
 * @return
 */
ERepositoryAndPracticeRecordDTO getRepositoryAndPracticeRecordIdBySafeTypeId(Long id);

实现方法

@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "repository")
public class ERepositoryServiceImpl extends BasicServiceImpl<ERepositoryMapper, ERepository> implements IERepositoryService {


-----------------------------------------------------------------------------------------------------

@Override
@Cacheable(key = "'safeTypeId:'+ #safeTypeId")
public ERepositoryAndPracticeRecordDTO getRepositoryAndPracticeRecordIdBySafeTypeId(Long safeTypeId) {
    // 声明返回的数据
    ERepositoryAndPracticeRecordDTO practiceRecordDTO = new ERepositoryAndPracticeRecordDTO();
    Long practiceRecordId = null;
    Long userId = SecurityUtils.getCurrentUserId();
    // 查询联系记录表中该用户的该分类数据
    List<EPracticeRecord> practiceRecordList = ePracticeRecordMapper.getByUserIdAndSafeTypeId(userId, safeTypeId);
    if (practiceRecordList.size() == 0) {
        EPracticeRecord ePracticeRecord = new EPracticeRecord();
        ePracticeRecord.setUserId(userId);
        ePracticeRecord.setSafeTypeId(safeTypeId);
        ePracticeRecordMapper.insert(ePracticeRecord);
        practiceRecordId = ePracticeRecord.getId();
    } else {
        practiceRecordId = practiceRecordList.get(0).getId();
    }
    LambdaQueryWrapper<ERepository> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(ERepository::getSafeTypeId,safeTypeId);
    PageVO pageVO = new PageVO();
    // 查询该分类下所有的题库信息
    IPage<ERepositoryDto> dtoIPage = eRepositoryMapper.selectRepositoryPage(pageVO.buildPage(), queryWrapper);

    practiceRecordDTO.setPracticeRecordId(practiceRecordId);
    practiceRecordDTO.setERepositoryDTOS(dtoIPage.getRecords());

    return practiceRecordDTO;
}
@RequiredArgsConstructor
@RestController
@Slf4j
@Api(tags = "题库练习记录模块")
@RequestMapping("/api/ePracticeRecord")
public class EPracticeRecordController {

    private final IEPracticeRecordService ePracticeRecordService;

    /**
     * 前台调用  传练习记录id
     * @param id
     * @return
     */
    @ApiOperation(value = "根据练习记录id查询练习记录")
    @GetMapping(value = "/getEPracticeRecordById")
    public Result<List<EPracticeRecord>> getEPraticeRecord(Long id){
        return Result.success(ePracticeRecordService.getEPracticeRecordByIdForReids(id));
    }

    @ApiOperation(value = "添加练习记录")
    @PostMapping
    public Result<Void> insertEPracticeRecord(@RequestBody EPracticeRecord ePracticeRecord){
        ePracticeRecordService.addPracticeRecord(ePracticeRecord);
        return Result.success();
    }
}
public interface IEPracticeRecordService extends IBasicService<EPracticeRecord> {

    /**
     * 通过id查找redis中的练习记录
     * @param id 练习记录id
     * @return
     */
    List<EPracticeRecord> getEPracticeRecordByIdForReids(Long id);

    /**
     * 用户每次点下一题,将上一题的练习记录存入缓存
     *
     * @param ePracticeRecord
     */
    void addPracticeRecord(EPracticeRecord ePracticeRecord);
}
@Service
@RequiredArgsConstructor
public class EPracticeRecordServiceImpl extends BasicServiceImpl<EPracticeRecordMapper, EPracticeRecord> implements IEPracticeRecordService {

    private final EPracticeRecordMapper ePracticeRecordMapper;
    private final RedisUtils redisUtils;

    @Override
    public List<EPracticeRecord> getEPracticeRecordByIdForReids(Long id) {
        List<EPracticeRecord> ePracticeRecordList = new ArrayList<>();
//        EPracticeRecord ePracticeRecord = new EPracticeRecord();
        Map<String, Object> ePracticeRecordRedis = new HashMap<>();
        String key = CacheKey.PRACTICERECORD + id;

        if (redisUtils.hasKey(key)) {
            ePracticeRecordRedis =(Map<String, Object>) (Object) redisUtils.hmget(key);
            Set<String> keySet = ePracticeRecordRedis.keySet();
            for (Object keyReposiId : keySet) {
                EPracticeRecord ePracticeRecord = new EPracticeRecord();
                ePracticeRecord.setId(id);
                ePracticeRecord.setFinishRepoIds((String) keyReposiId);
                ePracticeRecord.setFinishQuesAnswer((String) ePracticeRecordRedis.get(keyReposiId));
                ePracticeRecordList.add(ePracticeRecord);
            }
            return ePracticeRecordList;
        }

        //若redis中的key已过期,说明练习记录已入库,此时,需要查数据库
        EPracticeRecord ePracticeRecord = ePracticeRecordMapper.selectById(id);
        if (ObjectUtil.isNotNull(ePracticeRecord)) {
            String repoidsString = ePracticeRecord.getFinishRepoIds();
            String answersString = ePracticeRecord.getFinishQuesAnswer();
            if (StrUtil.isNotBlank(repoidsString) && StrUtil.isNotBlank(answersString)) {
                String[] repoids = repoidsString.split(",");
                String[] answers = answersString.split(",");
                for (int i = 0; i < repoids.length; i++) {
                    EPracticeRecord ePracticeRecord1 = new EPracticeRecord();
                    ePracticeRecordRedis.put(repoids[i],answers[i]);
                    ePracticeRecord1.setFinishRepoIds(repoids[i]);
                    ePracticeRecord1.setFinishQuesAnswer(answers[i]);
                    ePracticeRecordList.add(ePracticeRecord1);
                }
                //放入缓存
                redisUtils.hmset(key, ePracticeRecordRedis);
            }
        }
        return ePracticeRecordList;
    }

    @Override
    public void addPracticeRecord(EPracticeRecord ePracticeRecord) {
        Long practiceRecordId = ePracticeRecord.getId();
        String key = CacheKey.PRACTICERECORD + practiceRecordId;
        long time = Duration.between(LocalDateTime.now(), LocalDateTime.now().plusDays(2L)).getSeconds();
        //用户练习记录存入缓存(key为练习记录id,map中的key为题目id,value为答案)
        String answer = ePracticeRecord.getFinishQuesAnswer();
        String repoId = ePracticeRecord.getFinishRepoIds();

        if (!redisUtils.hasKey(key)) {
            //没有此key,说明已经入库或者第一次添加记录
            // 初始化redis
            this.getEPracticeRecordByIdForReids(practiceRecordId);
        }

        redisUtils.hset(key, repoId, answer, time);
    }
}

其中CacheKey.PRACTICERECORD为

/**
 * 题库练习记录
 */
String PRACTICERECORD = "practiceRecord::practiceRecordId:";
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容