SpringBoot + Elasticsearch 实现模糊查询,批量CRUD,排序,分页,高亮!

本文介绍了如何在SpringBoot应用中整合Elasticsearch,实现模糊查询、批量创建读取更新删除(CRUD)、排序和分页功能。文章详细讲解了依赖引入、配置类构建以及基本用法,包括索引管理、文档操作和高级查询技巧。在使用过程中,作者强调了版本匹配的重要性以及合理管理索引名称的建议。

一、引入依赖

当前Elasticsearch服务端的版本为8.5.1,此处Spring Data Elasticsearch的版本为2.6.1

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>2.6.1</version>
</dependency>

其Elasticsearch客户端真正使用到的版本为7.15.2:

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.6.1</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.bc</groupId>
	<artifactId>elasticsearch</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>
	<name>elasticsearch</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-web</artifactId>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
		</dependency>

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

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

</project>

二、构建配置类

package com.bc.elasticsearch.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

三、基本用法

3.1 创建、判断存在、删除索引

package com.bc.elasticsearch;

import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
class ElasticsearchBaseTests {

	@Autowired
	private RestHighLevelClient restHighLevelClient;

	@Test
	void testCreateIndex() throws IOException {
		//1.创建索引请求
		CreateIndexRequest request = new CreateIndexRequest("shopping");
		//2.客户端执行请求IndicesClient,执行create方法创建索引,请求后获得响应
		CreateIndexResponse response=
				restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
		System.out.println(response);
	}

	@Test
	void testExistIndex() throws IOException {
		//1.查询索引请求
		GetIndexRequest request=new GetIndexRequest("shopping");
		//2.执行exists方法判断是否存在
		boolean exists=restHighLevelClient.indices().exists(request,RequestOptions.DEFAULT);
		System.out.println(exists);
	}

	@Test
	void testDeleteIndex() throws IOException {
		//1.删除索引请求
		DeleteIndexRequest request=new DeleteIndexRequest("shopping");
		//2.执行delete方法删除指定索引
		AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
		System.out.println(delete.isAcknowledged());
	}
}

3.2 对文档的CRUD

package com.bc.elasticsearch;

import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;

@SpringBootTest
public class ElasticsearchCurdTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    void testAddUser() throws IOException {
        //1.创建对象
        String jsonStr ="{\"name\":\"张三\",\"age\":25}";
        //2.创建请求
        IndexRequest request=new IndexRequest("shopping");
        //3.设置规则 PUT /ljx666/_doc/1
        //设置文档id=6,设置超时=1s等,不设置会使用默认的
        //同时支持链式编程如 request.id("6").timeout("1s");
        request.id("6");
        request.timeout("1s");

        //4.将数据放入请求,要将对象转化为json格式
        //XContentType.JSON,告诉它传的数据是JSON类型
        request.source(jsonStr, XContentType.JSON);

        //5.客户端发送请求,获取响应结果
        IndexResponse indexResponse=restHighLevelClient.index(request,RequestOptions.DEFAULT);
        System.out.println(indexResponse.toString());
        System.out.println(indexResponse.status());
    }

    @Test
    void testGetUser() throws IOException {
        // 1.创建请求,指定索引、文档id
        GetRequest request=new GetRequest("shopping","6");
        GetResponse getResponse=restHighLevelClient.get(request,RequestOptions.DEFAULT);
        // 2.获取响应结果
        System.out.println(getResponse);
        // 3.getResponse.getSource() 返回的是Map集合
        System.out.println(getResponse.getSourceAsString());//获取响应结果source中内容,转化为字符串
    }

    @Test
    void testUpdateUser() throws IOException {
        // 1.创建请求,指定索引、文档id
        UpdateRequest request=new UpdateRequest("shopping","6");
        // 2.更新数据
        String jsonStr ="{\"name\":\"张三\",\"age\":26}";
        // 3.将创建的对象放入文档中
        request.doc(jsonStr,XContentType.JSON);
        UpdateResponse updateResponse=restHighLevelClient.update(request,RequestOptions.DEFAULT);
        System.out.println(updateResponse.status());//更新成功返回OK
    }
}

创建文档:如果添加时不指定文档ID,Elasticsearch就会随机生成一个ID,ID唯一。 创建文档时若该ID已存在,发送创建文档请求后会更新文档中的数据。

更新文档:要将json串中的属性全部指定值,不然会被覆盖掉。

3.3 查询所有、模糊查询、分页查询、排序、高亮显示

package com.bc.elasticsearch;

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@SpringBootTest
public class ElasticsearchBatchTests {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Test
    void testBulkAddUser() throws IOException {
        BulkRequest bulkRequest=new BulkRequest();
        //设置超时
        bulkRequest.timeout("10s");

        List<String> list = new ArrayList<>();
        list.add("{\"name\":\"张三\",\"age\":25}");
        list.add("{\"name\":\"李四\",\"age\":26}");
        list.add("{\"name\":\"王五\",\"age\":27}");

        int id=1;
        //批量处理请求
        for (String jsonStr :list){
            //不设置id会生成随机id
            bulkRequest.add(new IndexRequest("shopping")
                    .id(""+(id++))
                    .source(jsonStr,XContentType.JSON));
        }

        BulkResponse bulkResponse=restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
        System.out.println(bulkResponse.hasFailures());//是否执行失败,false为执行成功
    }

    @Test
    void testSearch() throws IOException {
        SearchRequest searchRequest=new SearchRequest("shopping");//里面可以放多个索引
        SearchSourceBuilder sourceBuilder=new SearchSourceBuilder();//构造搜索条件

        //此处可以使用QueryBuilders工具类中的方法
        //1.查询所有
        sourceBuilder.query(QueryBuilders.matchAllQuery());
        //2.查询name中含有“张三”的
        sourceBuilder.query(QueryBuilders.multiMatchQuery("张三","name"));
        //3.分页查询
        sourceBuilder.from(0).size(5);

        //4.按照score正序排列
        //sourceBuilder.sort(SortBuilders.scoreSort().order(SortOrder.ASC));
        //5.按照id倒序排列(score会失效返回NaN)
        //sourceBuilder.sort(SortBuilders.fieldSort("_id").order(SortOrder.DESC));

        //6.给指定字段加上指定高亮样式
        HighlightBuilder highlightBuilder=new HighlightBuilder();
        highlightBuilder.field("name").preTags("<span style='color:red;'>").postTags("</span>");
        sourceBuilder.highlighter(highlightBuilder);

        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse=restHighLevelClient.search(searchRequest,RequestOptions.DEFAULT);

        //获取总条数
        System.out.println(searchResponse.getHits().getTotalHits().value);
        //输出结果数据(如果不设置返回条数,大于10条默认只返回10条)
        SearchHit[] hits=searchResponse.getHits().getHits();
        for(SearchHit hit :hits){
            System.out.println("分数:"+hit.getScore());
            Map<String,Object> source=hit.getSourceAsMap();
            System.out.println("index->"+hit.getIndex());
            System.out.println("id->"+hit.getId());
            for(Map.Entry<String,Object> s:source.entrySet()){
                System.out.println(s.getKey()+"--"+s.getValue());
            }
        }
    }
}

四、总结 

1、大致请求

创建对应的请求 --> 设置请求(添加规则、添加数据等) --> 执行对应的方法(传入请求,默认请求选项)--> 接收响应结果(执行方法返回值)--> 输出响应结果中需要的数据(source、status等)

2、注意事项

  • 如果不指定ID,会自动生成一个随机ID。

  • 正常情况下,不应该这样使用 new IndexRequest("shopping"),如果索引发生改变了,那么代码都需要修改,可以定义一个枚举类或者一个专门存放常量的类,将变量用final static等进行修饰,并指定索引值。其它地方引用该常量即可,需要修改也只需修改该类即可。

  • elasticsearch相关的东西,版本都必须一致,不然会报错。

  • elasticsearch很消耗内存,建议在内存较大的服务器上运行elasticsearch,否则会因为内存不足导致elasticsearch自动killed。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值