springboot 集成 elasticsearch实战

本文详细介绍如何在Windows环境下安装配置Elasticsearch,并通过Spring Boot进行集成,实现数据索引、分页查询、高亮搜索等功能,同时提供代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 首先版本要求

2.下载对应的 压缩包  

下载地址: https://www.elastic.co/cn/downloads/elasticsearch

3.解压我这对应的是2.4.6版本  (window)

config 文件修改 

cluster.name: es-pdf
node.name: node-pdf

network.host: 0.0.0.0
http.port: 9200

4. bin>elasticsearch.bat双击,然后访问http://localhost:9200/ 出现以下就代表成功

5,安装head插件, 首先node环境,这里网上一大批,成功后访问http://localhost:9100/可查看数据,

记着先起es服务,后起grunt server,

接下来就是代码实战

1.我的springboot1.5.9为例,先添加依赖

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
spring:
     data:
        elasticsearch:
           cluster-name: es-pdf
           cluster-nodes: 192.168.110.109:9300
           repositories:
             enabled: true

 

2,创建索引

package com.**.p**.elasticsearch.model;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldIndex;
import org.springframework.data.elasticsearch.annotations.FieldType;


import java.io.Serializable;
import java.util.Date;

/**
 * @author chong
 * @create 2020/4/7
 * Desc: 
 */
@Data
@Document(indexName = "demo",type = "customer", shards = 1, replicas = 0, refreshInterval = "-1")
public class Demo implements Serializable {

    /**
     * 唯一标识符
     */
    @Id
    @Field(type = FieldType.Long,index = FieldIndex.not_analyzed, store = true)
    private Long id;

    /**
     * 添加时间
     */
    @Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true)
    private Date addDateTime;

    /**
     * 修改时间
     */
    @Field(type = FieldType.Date, index = FieldIndex.not_analyzed, store = true)
    private Date updateDateTime = new Date();

    /**
     * 名称
     */
    @Field(type = FieldType.String,analyzer = "ik", searchAnalyzer = "ik" , store = true)
    private String name;

    /**
     * 描述
     */
    @Field(type = FieldType.String,analyzer = "ik", searchAnalyzer = "ik" , store = true)
    private String desc;

   

    /**
     * 删除标志位(0:未删除;1:删除)
     */
    @Field(type = FieldType.Integer, index = FieldIndex.not_analyzed, store = true)
    private Integer ifDelete = 0;

    /**
     * 启用禁用状态(0:禁用;1:启用)
     */
    @Field(type = FieldType.Integer, index = FieldIndex.not_analyzed, store = true)
    private Integer useMark;

    /**
     * 浏览次数
     */
    @Field(type = FieldType.Integer, index = FieldIndex.not_analyzed, store = true)
    private Integer viewingTimes = 0;

  
}

3.创建repository 类似于jpa,使用简单


import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;


/**
 * @author chong
 * @create 2020/4/7
 * Desc: es
 */
@Repository
public interface DemoRepository extends ElasticsearchRepository<Demo,Long> {

}

4,实现简单的保存 , 分页 , 高亮显示搜索条件 以及返回前台时报错处理,中间遇到不少的坑,希望可以帮助大家

实现的方法很多,我这列举一两种

@Service
public class DemoServiceImpl{

    @Autowired
    private DemoRepository demoRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public Demo save(Demo demo) {
      demoRepository.save(demo);
    } 
/**
     * es分页查询
     *
     * @param pageAndSortDto
     * @return
     */
    @Override
    public Page<Demo> getPageList(PageAndSortDto pageAndSortDto) throws Exception{
        Pageable pageable = null;
        if (pageAndSortDto.getPage() != null) {
            List<MySort> sorts = pageAndSortDto.getSorts();
            Sort sort = null;
            if (sorts.size() > 0) {
                Sort.Direction dir = sorts.get(0).getDir().toLowerCase().equals("desc") ? Sort.Direction.DESC : Sort.Direction.ASC;
                sort = new Sort(dir, sorts.get(0).getProp());
            }
            pageable = new PageRequest(pageAndSortDto.getPage().getPageNum() - 1, pageAndSortDto.getPage().getPageSize(), sort);
        }
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        HighlightBuilder.Field hfieldName = new HighlightBuilder.Field("name")
                .preTags("<em style='color:red'>")
                .postTags("</em>")
                .fragmentSize(100);
        HighlightBuilder.Field hfieldAns = new HighlightBuilder.Field("desc")
                .preTags("<em style='color:red'>")
                .postTags("</em>")
                .fragmentSize(100);
        for (QueryDto queryDto : pageAndSortDto.getQueryList()) {
            switch (queryDto.getType()) {
                case "equal":
                    builder.must(QueryBuilders.matchQuery(queryDto.getParam(), queryDto.getValue()[0]));
                    break;
                case "like":
                    builder.must(QueryBuilders.multiMatchQuery(queryDto.getValue()[0],"name", "answer"));
                    break;
                case "in":
                    Object[] obj = queryDto.getValue();
                    for (Object o : obj) {
                        builder.should(QueryBuilders.matchPhraseQuery(queryDto.getParam(), o));
                    }
                    break;
            }
        }
//        Iterable<Demo> search = demoRepository.search(builder, pageable);
        // 高亮显示搜索条件
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(builder)
                .withPageable(pageable)
                .withHighlightFields(hfieldName,hfieldAns)
                .build();
        Page<Demo> page = elasticsearchTemplate.queryForPage(searchQuery, Demo.class, new SearchResultMapper() {
            @Override
            public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                List<T> chunk = new ArrayList<T>();
                for (SearchHit searchHit : response.getHits().getHits()) {
                    Map<String, Object> smap = searchHit.getSource();
                    Map<String, HighlightField> hmap = searchHit.getHighlightFields();
                    chunk.add((T)createEsDoc(smap,hmap));
                }
                AggregatedPage<T> result=new AggregatedPageImpl<T>(chunk,pageable,response.getHits().getTotalHits());
                return result;
            }
        });
        return fixEmptyPage(page);
    }

    /**
     * 返回结果高亮显示
     * @param smap
     * @param hmap
     * @return
     */
    private Demo createEsDoc(Map<String, Object> smap,Map<String, HighlightField> hmap){
        Demo ed = new Demo();
        if (hmap.get("name") != null)
            ed.setName(hmap.get("name").fragments()[0].toString());
        if (hmap.get("desc") != null)
            ed.setDesc(hmap.get("desc").fragments()[0].toString());
        if (smap.get("id") != null)
            ed.setId(Long.parseLong(smap.get("id").toString()));
        return ed;
    }

    /**
     * 分页返回数据json 序列化转换报错处理
     *
     * @param page
     * @param <T>
     * @return
     */
    private <T> Page<T> fixEmptyPage(Page<T> page) {
        AggregatedPageImpl<T> aggregatedPage = (AggregatedPageImpl<T>) page;
        Aggregations aggregations = aggregatedPage.getAggregations();
        if (aggregations == null) {
            Field field = ReflectionUtils.findField(AggregatedPageImpl.class, "aggregations");
            ReflectionUtils.makeAccessible(field);
            ReflectionUtils.setField(field, aggregatedPage, InternalAggregations.EMPTY);
            return aggregatedPage;
        }
        return page;
    }

}

这里需要注意的是PageAndSortDto 是自定义的前台接收参数,个人可根据自己业务

5.分词,如果不装分词默认中文你会发现会吧中文分成单个,这块需要安装ik分词.根据版本下载,建议下载releases,直接解压,不需要打包

这里下载的是1.10.6,在elasticsearch里面plugins新建ik文件夹,重启就OK了

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值