使用ElasticSearch搜索商品及向es中批量添加商品的实现思路及部分代码实现(后台系统上架商品、下架、修改的时候分别发送MQ消息到队列,消息监听器监听队列的消息变化,更新ES)

本文介绍了如何使用ElasticSearch实现全站搜索,重点在商品搜索。通过Spring Data Elasticsearch与ElasticSearch集成,建立'micro:products'索引。为了保证数据一致性,采取了两种策略:定时任务每2小时从Redis同步数据,包括新增、修改和删除的内容;后台系统操作如上架、下架、修改商品时,通过MQ发送消息到队列,由消息监听器监听并更新ES。

搜索服务
需求
实现整个系统的全站搜索
主要是实现商品相关搜索
分析
技术站:ElasticSearch Spring Data Elasticsearch
索引:
商品信息:micro:products
文档:
商品id 商品名称 商品的关键字 商品的类型
1.数据一致性的保证:
a.采用定时任务实现ES数据的维护
从Redis获取数据:
1个:新增的内容
1个:修改的内容
1个:删除的内容
批处理
b.MQ
后台系统上架商品、下架、修改的时候分别发送MQ消息到队列,消息监听器监听队列的消息变化,更新ES
二、代码实现

public class SystemConfig {

    /*
    ES用来存储商品信息的索引名称
     */
    public static final String ES_PRODUCTS="micro:es:product";
}
package com.lxm.searchservice.model;

import com.lxm.common.config.SystemConfig;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;

/**
 * @Author LXM
 * @Date 2020/7/16 0016
 */
@Data
@Document(indexName = SystemConfig.ES_PRODUCTS)
public class ProductModel {
    @Id //唯一标记
    private Integer id;
    @Field(index = true,name = "esname")//设置字段信息,比如分词规则
    private String name;
    private String type;
    private String keywords;
}
package com.lxm.searchservice.service.impl;

import com.lxm.common.config.RedisKeyConfig;
import com.lxm.common.utils.RUtil;
import com.lxm.common.utils.RedissionCore;
import com.lxm.common.vo.R;
import com.lxm.searchservice.dao.ProductDao;
import com.lxm.searchservice.model.ProductModel;
import com.lxm.searchservice.service.ProductService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.WildcardQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Author LXM
 * @Date 2020/7/16 0016
 */
@Service
public class ProductServiceImpl implements ProductService {
    @Resource
    private ProductDao dao;
    @Resource
    private RedissionCore redissionCore;
    @Resource
    private ElasticsearchRestTemplate restTemplate;

    /**
     * 批量向es添加修改删除数据
     * @return
     */
    @Override
    public R batchData() {
        List<ProductModel> productModels=new ArrayList<>();
        //批量新增
        Map<Object,Object> add=redissionCore.getMap(RedisKeyConfig.ES_PRODUCT_ADD);
        add.values().stream().forEach(o->{
            if (o instanceof ProductModel){
                productModels.add((ProductModel) o);
            }
        });
        //批量修改
        Map<Object,Object> update=redissionCore.getMap(RedisKeyConfig.ES_PRODUCT_UPDATE);
        update.values().stream().forEach(o -> {
            if (o instanceof ProductModel){
                productModels.add((ProductModel) o);
            }
        });
        dao.saveAll(productModels);
        //批量删除
        Map<Object,Object> del=redissionCore.getMap(RedisKeyConfig.ES_PROUCT_DEL);
        del.values().stream().forEach(o -> {
            if (o instanceof ProductModel){
                productModels.add((ProductModel) o);
            }
        });
        dao.deleteAll(productModels);

        return RUtil.ok();
    }

    /**
     * 按照关键字进行搜索
     * @param msg
     * @return
     */
    @Override
    public R search(String msg) {
        //设定模糊查询查询条件
        //根据商品类型进行模糊匹配
        WildcardQueryBuilder wildcard1= QueryBuilders.wildcardQuery("type","*"+msg+"*");
        //根据商品标题进行模糊匹配
        WildcardQueryBuilder wildcard2= QueryBuilders.wildcardQuery("name","*"+msg+"*");
        //根据商品关键字进行模糊匹配
        WildcardQueryBuilder wildcard3= QueryBuilders.wildcardQuery("keywords","*"+msg+"*");
        //bool查询
        BoolQueryBuilder boolQueryBuilder=QueryBuilders.boolQuery();
        //拼接查询条件
        boolQueryBuilder.should(wildcard1).should(wildcard2).should(wildcard3);

        //实例化查询对象
        NativeSearchQueryBuilder queryBuilder=new NativeSearchQueryBuilder();
        queryBuilder.withQuery(boolQueryBuilder);
        SearchHits<ProductModel> hits=restTemplate.search(queryBuilder.build(),ProductModel.class);

        HashMap<String,Integer> map=new HashMap<>();
        for (SearchHit<ProductModel> s:hits){
            ProductModel p=s.getContent();
            //校验类型
            if (p.getType().contains(msg)){
                if (map.containsKey(p.getType())){
                    map.put(p.getType(),map.get(p.getType())+1);
                }else {
                    map.put(p.getType(),1);
                }
            }
            //校验关键字
            if (p.getKeywords().contains(msg)){
                if (map.containsKey(p.getKeywords())){
                    map.put(p.getKeywords(),map.get(p.getKeywords())+1);
                }else {
                    map.put(p.getKeywords(),1);
                }
            }
            if (map.containsKey(msg)){
                map.put(msg,map.get(msg)+1);
            }else {
                map.put(msg,1);
            }
        }
        return RUtil.ok(map);
    }
}
package com.lxm.searchservice.dao;

import com.lxm.searchservice.model.ProductModel;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface ProductDao extends ElasticsearchRepository<ProductModel,Integer> {
}
package com.lxm.searchservice.service;

import com.lxm.common.vo.R;

public interface ProductService {
    /**
     * 批量向es添加修改删除数据
     * @return
     */
    R batchData();

    /**
     * 按照关键字进行搜索
     * @param msg
     * @return
     */
    R search(String msg);
}

定时任务——每2小时执行一次同步一次数据

package com.lxm.searchservice.task;

import com.lxm.searchservice.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author LXM
 * @Date 2020/7/17 0017
 */
@Component
@Slf4j
public class EsProductTask {
    @Resource
    private ProductService service;

    @Scheduled(cron = "0 0 0/2 * * ? ")
    public void task(){
        log.info("定时任务-ES-mysql:开始执行:"+System.currentTimeMillis());
        service.batchData();
        log.info("定时任务-ES-mysql:结束执行:"+System.currentTimeMillis());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值