Springboot整合Elasticsearch实现实时搜索

前端页面采用的是github上看到的页面使用Vue实现,GitHub原址:https://github.com/lavyun/vue-demo-search ,后台页面采用springboot+es实现。

Springboot项目构建省略,不会的朋友参考。(springboot入门)
Elasticsearch安装步骤省略,没安装的参考。(Elasticsearch环境搭建和介绍(Windows))
Vue项目构建略过。( Vue-cli 快速构建Vue项目

创建SpringBoot 项目

首先新建一个SpringBoot项目,再进行Elasticsearch的整合实现搜索。
pom.xml
<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- elasticsearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>aliyunmaven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
application.yml
server:
  port: 8888
spring:
  data:
    elasticsearch:
      cluster-name: elasticsearch
      cluster-nodes: 192.168.43.238:9300		#ip地址填写自己的
  jackson:
    default-property-inclusion: non_null		#如果是空值则不返回
索引与查询实例
@Data
@Document(indexName = "goodscat", type = "docs", shards = 1, replicas = 0)
public class Goods {

    @Id
    private Long cid;
	// 所有需要被搜索的信息,包含标题,分类,甚至品牌
    @Field(type = FieldType.Keyword, index = true, analyzer = "ik_max_word")
    private String name;	//分类名称,
    private String isParent;
    private String parentId;
    private Long level;
    private String pathid;
}

Spring Data通过注解来声明字段的映射属性,上面三个注解代表的意思为:

  • @Document 作用在类,标记实体类为文档对象,一般有两个属性
  • indexName:对应索引库名称
  • type:对应在索引库中的类型
  • shards:分片数量,默认5
  • @Id 作用在成员变量,标记一个字段作为id主键
  • @Field 作用在成员变量,标记为文档的字段,并指定字段映射属性:
  • type:字段类型,是枚举:FieldType,可以是text、long、short、date、integer、object等
  • text:存储数据时候,会自动分词,并生成索引
  • keyword:存储数据时候,不会分词建立索引
  • Numerical:数值类型,分两类
  • 基本数据类型:long、interger、short、byte、double、float、half_float
  • 浮点数的高精度类型:scaled_float
  • 需要指定一个精度因子,比如10或100。elasticsearch会把真实值乘以这个因子后存储,取出时再还原。
  • Date:日期类型
  • elasticsearch可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间。
  • index:是否索引,布尔类型,默认是true
  • store:是否存储,布尔类型,默认是false
  • analyzer:分词器名称,这里的ik_max_word即使用ik分词器
4. 创建搜索配置类
public class SearchRequest {
    private String key;// 搜索条件

    private Integer page;// 当前页

    private static final Integer DEFAULT_SIZE = 10;// 每页大小,不从页面接收,而是固定大小
    private static final Integer DEFAULT_PAGE = 1;// 默认页

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Integer getPage() {
        if(page == null){
            return DEFAULT_PAGE;
        }
        // 获取页码时做一些校验,不能小于1
        return Math.max(DEFAULT_PAGE, page);
    }

    public void setPage(Integer page) {
        this.page = page;
    }

    public Integer getSize() {
        return DEFAULT_SIZE;
    }
}
  1. ElasticsearchRepository创建

dao层只需继承ElasticsearchRepository类。其中主要的方法就是 save、delete和search,其中save方法相当如insert和update,没有就新增,有就覆盖。delete方法主要就是删除数据以及索引库。至于search就是查询了。

package com.demo.elasticsearch.repository;

import com.demo.elasticsearch.pojo.Goods;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface GoodsRepository extends ElasticsearchRepository<Goods,Long> {

}
  1. service实现层(代码只有搜索的实现,数据在测试类中已经添加完成了,这里只做查询)
@Slf4j
@Service
public class SearchServiceImpl implements SearchService {


    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ElasticsearchTemplate template;

    @Override
    public PageResult<Goods> search(SearchRequest request) {
    	//分页
        int page = request.getPage() - 1;
        int size = request.getSize();

        // 定义高亮字段
        HighlightBuilder.Field titleField = new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>");
        //创建查询构建器
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //结果过滤,只查询cid,name字段
        queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"cid", "name"}, null));
        //分页
        queryBuilder.withPageable(PageRequest.of(page, size));
        //过滤
        queryBuilder.withQuery(QueryBuilders.matchQuery("name", request.getKey())).withHighlightFields(titleField);

        //查询,在查询的基础上给字段设置高亮红色
        AggregatedPage<Goods> result = template.queryForPage(queryBuilder.build(), Goods.class,
                new SearchResultMapper() {
                    @Override
                    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
                        List<Goods> list = new ArrayList<Goods>();
                        for (SearchHit searchHit : response.getHits()) {
                            if (response.getHits().getHits().length <= 0) {
                                return null;
                            }
                            Goods idea = new Goods();
                            HighlightField ideaTitle = searchHit.getHighlightFields().get("name");
                            if (ideaTitle != null) {
                                idea.setName(ideaTitle.fragments()[0].toString());
                            }
                            list.add(idea);
                        }
                        if (list.size() > 0) {
                            return new AggregatedPageImpl<T>((List<T>) list);
                        }
                        return null;
                    }
                    @Override
                    public <T> T mapSearchHit(SearchHit searchHit, Class<T> aClass) {
                        return null;
                    }
                }
        );

        //解析结果
        //分页结果解析
        long total = result.getTotalElements();
        Long totalPages = result.getTotalPages();   
        List<Goods> goodsList = result.getContent();

        //封装分页数据
        return new PageResult(total, totalPages, goodsList);
    }

}
  1. Controller层(比较简单,单纯调用一下)
@RestController
public class SearchController {
    @Autowired
    private SearchService searchService;

    /**
     * 搜索功能
     * @param request
     * @return
     */
    @PostMapping("search")
    public ResponseEntity<PageResult<Goods>> search(@RequestBody SearchRequest request) {
        return ResponseEntity.ok(searchService.search(request));
    }
}
好了,代码编写完成,我们启动我们的项目测试一下。

springboot es 通配符 springboot整合es搜索_springboot es 通配符

总结

只是简单的实现了一个springboot整合Elasticsearch的案例,我们还可以利用spring data提供的Repository接口做很多事情,比如对同一分类进行聚合为桶等,天天学习,向大佬们靠近。