小工具      在线工具  汉语词典  css  js  c++  java

SpringBoot 集成 elasticsearch 实现精确查询

Java,java,elasticsearch,es 额外说明

收录于:43天前

在 Mac 上安装 ElasticSearch 6.6.2

MAC下安装ElasticSearch Head插件

elasticsearch IK中文分词器精准查询

BoolQueryBuilder 和通配符查询查询

本文在上述elasticsearch文章的基础上,将SpringBoot与elasticsearch集成。

在集成前,先放一张图,必须严格遵守,否则可能会出现各种问题。。我本地使用的是红框标出来的这个版本。

 使用ES有两种常见的方式,一种是使用ElasticsearchRepository,一种是使用ElasticsearchTemplate(下面的Controller层代码展示了这两种类型)。

JPA中有一个ElasticsearchRepository,可以进行Elasticsearch相关的增删改查。用法和普通的CRUDRepository一样。这样就可以将ElasticSearch和普通的JPA操作统一起来,获得和操作mysql一样的代码体验。但同时,你可以看到ElasticsearchRepository的功能相对较少。简单的查询就足够了,但是复杂的查询还不够。

ElasticsearchTemplate提供了更多的方法来完成更多的功能,包括分页等。它实际上是一个封装的ElasticSearch Util功能类,通过直接连接客户端来完成数据操作。推荐使用ElasticsearchTemplate。

1.Springboot集成ES

我的springboot版本是2.1.7,本地ES服务版本是6.2.2,IK版本是6.3.0

pom.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.robinson</groupId>
    <artifactId>elasticsearchDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>elasticsearchDemo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties 文件配置

#===== elasticsearch 配置 ====

##开启 Elasticsearch 仓库(默认值:true)
#spring.data.elasticsearch.repositories.enabled=true
##默认 9300 是 Java 客户端的端口。9200 是支持 Restful HTTP 的接口
spring.data.elasticsearch.cluster-nodes=localhost:9300
##spring.data.elasticsearch.cluster-name Elasticsearch 集群名(默认值: elasticsearch)
spring.data.elasticsearch.cluster-name=elasticsearch
##spring.data.elasticsearch.cluster-nodes 集群节点地址列表,用逗号分隔。如果没有指定,就启动一个客户端节点
##spring.data.elasticsearch.propertie 用来配置客户端的额外属性
##存储索引的位置
#spring.data.elasticsearch.properties.path.home=/data/project/target/elastic
##连接超时的时间
#spring.data.elasticsearch.properties.transport.tcp.connect_timeout=120s

博客模型类

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.format.annotation.DateTimeFormat;

import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.Date;

@Document(indexName = "blog", type = "java")
public class BlogModel implements Serializable {

    private static final long serialVersionUID = 6320548148250372657L;

    @Id
    private String id;

    @Size(min = 3, max = 10)
    private String title;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date date;

    public BlogModel() {
        super();
    }

    public BlogModel(String id, String title, Date date) {
        super();
        this.id = id;
        this.title = title;
        this.date = date;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }
}

定义 BlogRepository 接口

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

public interface BlogRepository extends ElasticsearchRepository<BlogModel, String> {

    Page<BlogModel> findByTitle(String title, Pageable pageable);

    @Query("{\"match_phrase\":{\"title\":\"?0\"}}")
    List<BlogModel> findByTitleCustom(String keyword);
}

直接看Controller层的demo代码,如下:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
public class BlogController {

    @Autowired
    private BlogRepository blogRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    private Log log = LogFactory.getLog(this.getClass());

    @PostMapping("/blog/add")
    public JsonResult<Object> add(@Validated @RequestBody BlogModel blogModel, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> list = bindingResult.getAllErrors();
            int len = list.size();
            for (int i = 0; i < len; i++) {
                FieldError fieldError = (FieldError) list.get(i);
                log.error("对象 " + fieldError.getObjectName() + " 的字段 " + fieldError.getField() + ":" + fieldError.getDefaultMessage());
                return new JsonResult<>("someCode",
                        "对象" + fieldError.getObjectName() + "的字段" + fieldError.getField() +
                                ":" + fieldError.getDefaultMessage());
            }
        }
        blogRepository.save(blogModel);
        return new JsonResult<>();
    }

    @PostMapping("/blog/get/{id}")
    public BlogModel getBlogById(@PathVariable String id) {
        Optional<BlogModel> blogModelOptional = blogRepository.findById(id);
        if (blogModelOptional.isPresent()) {
            BlogModel blogModel = blogModelOptional.get();
            return blogModel;
        }
        return null;
    }

    @PostMapping("/blog/update")
    public String updateById(@RequestBody BlogModel blogModel) {
        String id = blogModel.getId();
        if (StringUtils.isEmpty(id)) {
            return "缺少id";
        }
        blogRepository.save(blogModel);
        return "success";
    }

    @PostMapping("/blog/delete/{id}")
    public String deleteById(@PathVariable String id) {
        if (StringUtils.isEmpty(id)) {
            return "error";
        }
        blogRepository.deleteById(id);
        return "success";
    }

    @PostMapping("/blog/search")
    public JsonResult<Object> getByTitle(@RequestParam int currentPage, @RequestParam String title,
                                         @RequestParam(required = false, defaultValue = "1") int pageSize) {
        // JPA 中,page是从0开始,不是从1开始;因此,将用户输入的从1开始的page页码减1;
        PageRequest pageRequest = PageRequest.of(currentPage - 1, pageSize);
        Page<BlogModel> pages = blogRepository.findByTitle(title, pageRequest);
        log.info(pages);
        long totalElements = pages.getTotalElements();
        long totalPages = pages.getTotalPages();
        List<BlogModel> list = pages.getContent();
        Map map = new HashMap<String, Object>();
        map.put("totalElements", totalElements);
        map.put("totalPages", totalPages);
        map.put("pageSize", pageSize);
        map.put("currentPage", currentPage);
        map.put("list", list);
        return new JsonResult<>(map);
    }

    @PostMapping("/blog/searchByTitleCustom")
    public JsonResult<Object> findByTitleCustom(@RequestParam String title) {
        List<BlogModel> pages = blogRepository.findByTitleCustom(title);
        log.info(pages);
//        long totalElements = pages.getTotalElements();
//        long totalPages = pages.getTotalPages();
//        List<BlogModel> list = pages.size();
//        Map map = new HashMap<String, Object>();
//        map.put("totalElements", totalElements);
//        map.put("totalPages", totalPages);
//        map.put("pageSize", pageSize);
//        map.put("currentPage", currentPage);
//        map.put("list", list);
        return new JsonResult<>(pages);
    }

    @GetMapping("/blog/search/title")
    public JsonResult<List<BlogModel>> searchTitle(String keyword) {
//        if (StringUtils.isEmpty(keyword))
//            throw new JsonResult<String>("参数不能为空");

        String field = "title";

        // 精确查找
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        boolQueryBuilder.must(QueryBuilders.termsQuery(field, keyword));
        SearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withPageable(PageRequest.of(0, 100))
                .build();

//        SearchQuery searchQuery = new NativeSearchQueryBuilder()
//                .withQuery(QueryBuilders.queryStringQuery(keyword).defaultField(field))
//                .withPageable(PageRequest.of(0, 100))
//                .build();

        List<BlogModel> list = elasticsearchTemplate.queryForList(searchQuery, BlogModel.class);
        return new JsonResult<>(list);
    }

    @GetMapping("/blog/getAll")
    public JsonResult getAll() {
        Iterable<BlogModel> iterable = blogRepository.findAll();
        List<BlogModel> list = new ArrayList<>();
        iterable.forEach(list::add);
        return new JsonResult<List<BlogModel>>(list);
    }
}

这里说明一下,一般查询主要是利用BoolQueryBuilder的must、should等来组合模糊或精确查询。这是查询的重点。如有需要,请单独研究。你也可以阅读我的这篇文章,BoolQueryBuilder 和通配符查询查询

2.ES数据测试

参考文章:https://segmentfault.com/a/1190000018625101 

. . .

相关推荐

额外说明

Maven生命周期详解

目录 一、生命周期(clean+site+default) 1、生命周期与插件的关系 2、maven的三套生命周期 3、生命周期执行规则 二、Maven插件(plugin) 1、两种类型的插件 2、调用插件有两种方式 3、内置绑定 4、自定义绑定插件 三

额外说明

com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused: con

  eureka启动时有异常,但访问没问题:         eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ register

额外说明

正则表达式-----小数点后允许有两位数字

//校验是否全由数字组成 function isDigit(s) { var patrn=/^[0-9]{1,20}$/; if (!patrn.exec(s)) return false return true } //校验登录名:只能输入5-20个以

额外说明

[Python] lambda 匿名函数

文章目录 前言 lambda匿名函数的定义 lambda匿名函数的使用 使用lambda匿名函数写一个计算器 总结 前言 在Python中,可以使用def 关键字定义函数,使用def定义的关键字是有名称的,在调用时可以重复使用.还有一种是使用lambda

额外说明

liunx命令 如下快速下载文件或者日志

liunx命令 如下快速下载文件或者日志 有时候我们因为各种的原因没有办法直接从liunx中拿到想到文件或者日志就像我:xftp 被禁止使用了 只能找命令下载; 下面直接上命令: sz redis.log 下面之后直接打开即可: rz //上传文件 r

额外说明

git 添加远程库

现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。 首先,登陆GitHub,然后,在右上角找到“C

额外说明

在Windows中,如何更改 Visual Studio Code 扩展插件的安装位置?

目录 一、前言 二、先将扩展插件extensions从默认安装路径剪切到你真正想要存放的位置 三、方法1:使用VSCode的 “ --extensions-dir ” 指令 1. 可以通过cmd使用VS Code指令,修改指定的插件加载路径。 2. 也可

额外说明

分布式事务解决方案:Seata

1. Seata介绍 (前身为Fescar),是一款开源的分布式事务解决方案,由阿里巴巴发起并维护,用于帮助应用程序管理和协调分布式事务。Seata支持多种分布式事务模式,其中最常见的是AT(原子性事务)模式。以下是Seata的一些重要特点和功能: 分布

额外说明

计算机丢失xactengine3_7.dll怎么办?

其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或者损坏了,这时你只需下载这个xactengine3_7.dll文件进行安装(前提是找到适合

额外说明

文案方法论:带你掌握文案底层逻辑 点字成金

标题:文案创作的黄金法则:化文字为金,掌握底层逻辑 文章: 随着信息时代的到来,文案创作已经成为商务沟通中不可或缺的一部分。无论是广告、宣传、营销还是品牌推广,成功的文案都能引起读者的共鸣,激发他们的兴趣和购买欲望。要想写出有吸引力、有影响力的文案,需要

ads via 小工具