前言

被逼无奈,各行各业都在卷,给自己充电学习了Elasticsearch,在学完基础知识后(其实就是CRUD😂),就去Springboot中尝试整合ES。终于抽出时间,将学习的东西整理分享在此,欢迎大家批评指正哈~


一、ElasticSearch本地环境搭建

详细安装步骤参考此资料windows 安装 Elasticsearch

二、SpringBoot整合ElasticSearch

我这里Spring Boot版本2.7.5,ElasticSearch版本7.17.3。版本一定要对应上,否则会报一堆错误问题。
SpringBoot官方推荐对应Elasticsearch版本。
在这里插入图片描述
先启动ES本地服务(双击elasticsearch.bat启动服务),然后在elasticsearch-head可视化插件目录中执行npm start run启动可视化插件。
在这里插入图片描述
在这里插入图片描述

1.pom中引入ES依赖

<!-- ElasticSearch -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>elasticsearch-java</artifactId>
                    <groupId>co.elastic.clients</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
            <version>8.0.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>jakarta.json-api</artifactId>
                    <groupId>jakarta.json</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
            <version>2.0.1</version>
        </dependency>

2.application.yaml配置elasticsearch

elasticsearch:
  port: 9200
  ip: 127.0.0.1
  username: elastic
  password: 123456

3.ElasticSearchClientConnect连接ES客户端工具类

@Configuration
public class ElasticSearchClientConnect {
    @Value("${elasticsearch.port}")
    private int port;

    @Value("${elasticsearch.ip}")
    private String ip;

    @Value("${elasticsearch.username}")
    private String username;

    @Value("${elasticsearch.password}")
    private String password;

    /**
     * 创建rest客户端
     */
    @Bean
    public ElasticSearchResult restClient(){
        RestClient restClient = RestClient.builder(
                new HttpHost(ip, port,"http")).build();
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper());
        ElasticsearchClient client = new ElasticsearchClient(transport);
        return new ElasticSearchResult(restClient,transport,client);
    }
}

4.ElasticSearchResult封装响应结果

@Data
public class ElasticSearchResult {

    private RestClient restClient;

    private ElasticsearchTransport elasticsearchTransport;

    private ElasticsearchClient elasticsearchClient;

    public ElasticSearchResult(RestClient restClient, ElasticsearchTransport elasticsearchTransport, ElasticsearchClient elasticsearchClient) {
        this.restClient = restClient;
        this.elasticsearchTransport = elasticsearchTransport;
        this.elasticsearchClient = elasticsearchClient;
    }
}

5.Person实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private String name;
    private String sex;
    private Integer age;
}

6.ElasticsearchController增删改查控制层

/**
 * ES增删改查
 */
@RestController
public class ElasticsearchController {

    @Autowired
    private ElasticSearchClientConnect elasticSearchClientConfig;

    /**
     * 新建my_index索引
     * @return
     * @throws IOException
     */
    @GetMapping("/createIndex")
    public Boolean createIndex() throws IOException {

        CreateIndexResponse createIndexResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().indices().create(c -> c.index("my_index"));
        // 打印结果
        System.out.println(createIndexResponse.acknowledged());
        // 关闭连接

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
        return createIndexResponse.acknowledged();
    }

    /**
     * 查询索引
     * @throws IOException
     */
    @GetMapping("/selectIndex")
    public void selectIndex() throws IOException {

        GetIndexResponse getIndexResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().indices().get(e -> e.index("jing_index"));

        // 打印结果
        System.out.println("getIndexResponse.result() = " + getIndexResponse.result());
        System.out.println("getIndexResponse.result().keySet() = " + getIndexResponse.result().keySet());

        // 关闭连接
        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 删除索引
     * @return
     * @throws IOException
     */
    @GetMapping("/deleteIndex")
    public Boolean deleteIndex() throws IOException {
        // 删除索引
        DeleteIndexResponse deleteIndexResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().indices().delete(e -> e.index("jing_index"));
        System.out.println("删除操作 = " + deleteIndexResponse.acknowledged());
        // 关闭连接
        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
        return deleteIndexResponse.acknowledged();
    }

}

7.ElasticsearchDocumentController文档操作控制层

/**
 * ES文档操作
 */
@RestController
public class ElasticsearchDocumentController {

    @Autowired
    private ElasticSearchClientConnect elasticSearchClientConfig;

    /**
     * 添加document
     * @throws IOException
     */
    @GetMapping("/addDocument")
    public void addDocument() throws IOException {

        // 向Person对象中添加数据
        Person Person = new Person("java客户端", "男", 18);
        // 向索引中添加数据
        CreateResponse createResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().create(e -> e.index("jing_index").id("1001").document(Person));
        System.out.println("createResponse.result() = " + createResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 查询document
     * @throws IOException
     */
    @GetMapping("/queryDocument")
    public void queryDocument() throws IOException {
        // 构建请求
        GetResponse<Person> getResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().get(e -> e.index("jing_index").id("1001"), Person.class);
        System.out.println("getResponse.source().toString() = " + getResponse.source().toString());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 修改document
     * @throws IOException
     */
    @GetMapping("/modifyDocument")
    public void modifyDocument() throws IOException {

        // 使用map集合封装需要修改的内容
        Map<String, Object> map = new HashMap<>();
        map.put("name", "java客户端aaa");
        // 构建请求
        UpdateResponse<Person> updateResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().update(e -> e.index("jing_index").id("1001").doc(map), Person.class);
        System.out.println("updateResponse.result() = " + updateResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 删除document
     * @throws IOException
     */
    @GetMapping("/removeDocument")
    public void removeDocument() throws  IOException {

        // 构建请求
        DeleteResponse deleteResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().delete(e -> e.index("jing_index").id("1001"));
        System.out.println("deleteResponse.result() = " + deleteResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 批量添加document
     * @throws IOException
     */
    @GetMapping("/batchAddDocument")
    public void batchAddDocument() throws IOException {

        // 构建一个批量数据集合
        List<BulkOperation> list = new ArrayList<>();
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test2", "男", 19)).id("1002").index("Person_test")).build());
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test3", "男", 20)).id("1003").index("Person_test")).build());
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test4", "女", 21)).id("1004").index("Person_test")).build());
        // 调用bulk方法执行批量插入操作
        BulkResponse bulkResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().bulk(e -> e.index("Person_test").operations(list));
        System.out.println("bulkResponse.items() = " + bulkResponse.items());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 批量删除document
     * @throws IOException
     */
    @GetMapping("/batchDeleteDocument")
    public void batchDeleteDocument() throws IOException {

        // 构建一个批量数据集合
        List<BulkOperation> list = new ArrayList<>();
        list.add(new BulkOperation.Builder().delete(
                d -> d.id("1002").index("Person_test")).build());
        list.add(new BulkOperation.Builder().delete(
                d -> d.id("1003").index("Person_test")).build());
        // 调用bulk方法执行批量插入操作
        BulkResponse bulkResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().bulk(e -> e.index("Person_test").operations(list));
        System.out.println("bulkResponse.items() = " + bulkResponse.items());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 全量查询document
     * @throws IOException
     */
    @GetMapping("/queryAllDocument")
    public void queryAllDocument() throws IOException {

        // 全量查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(e -> e.index("Person_test").query(q -> q.matchAll(m -> m)), Person.class);
        HitsMetadata<Person> hits = searchResponse.hits();
        for (Hit<Person> hit : hits.hits()) {
            System.out.println("Person = " + hit.source().toString());
        }
        System.out.println("searchResponse.hits().total().value() = " + searchResponse.hits().total().value());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 分页查询document
     * @throws IOException
     */
    @GetMapping("/pagingQueryDocument")
    public void pagingQueryDocument() throws IOException {

        // 分页查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test")
                        .query(q -> q.matchAll(m -> m))
                        .from(0)
                        .size(2)
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));
        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 排序查询document
     * @throws IOException
     */
    @GetMapping("/sortQueryDocument")
    public void sortQueryDocument() throws IOException {

        // 排序查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test")
                        .query(q -> q.matchAll(m -> m))
                        .sort(o -> o.field(f -> f.field("age").order(SortOrder.Asc)))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 条件查询document
     * @throws IOException
     */
    @GetMapping("/conditionQueryDocument")
    public void conditionQueryDocument() throws IOException {

        // 条件查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test").query(q -> q.matchAll(m -> m))
                        .sort(o -> o.field(f -> f.field("age").order(SortOrder.Asc)))
                        .source(r -> r.filter(f -> f.includes("name", "age").excludes("")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 组合查询  must是必须满足所有条件,should只要满足一个就行
     * @throws IOException
     */
    @GetMapping("/combinationQueryDocument")
    public void combinationQueryDocument() throws IOException {

        // 组合查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test").query(q -> q.bool(b -> b
                        .must(m -> m.match(u -> u.field("age").query(21)))
                        .must(m -> m.match(u -> u.field("sex").query("男")))
                        .mustNot(m -> m.match(u -> u.field("sex").query("女")))
                ))
                , Person.class);


        //SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
        //                s -> s.index("Person_test").query(q -> q.bool(b -> b
        //                        .should(h -> h.match(u -> u.field("age").query(19)))
        //                        .should(h -> h.match(u -> u.field("sex").query("男")))
        //                ))
        //                , Person.class);

        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 范围查询
     * @throws IOException
     */
    @GetMapping("/scopeQueryDocument2")
    public void scopeQueryDocument2() throws IOException {

        // 范围查询,gte()表示取大于等于,gt()表示大于,lte()表示小于等于
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .range(r -> r.field("age").gte(JsonData.of(20)).lt(JsonData.of(21))))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }


    /**
     * 模糊查询
     * @throws IOException
     */
    @GetMapping("/fuzzyQueryDocument2")
    public void fuzzyQueryDocument2() throws IOException {

        // 模糊查询,fuzziness表示差几个可以查询出来
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .fuzzy(f -> f.field("name").value("tst").fuzziness("2")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 高亮查询
     * @throws IOException
     */
    @GetMapping("/highlightQueryDocument2")
    public void highlightQueryDocument2() throws IOException {

        // 高亮查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .term(t -> t.field("name").value("test4")))
                        .highlight(h -> h.fields("name", f -> f.preTags("<font color='red'>").postTags("</font>")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }


    /**
     * 聚合查询
     * @throws IOException
     */
    @GetMapping("/aggregateQueryDocument2")
    public void aggregateQueryDocument2() throws IOException {

        // 聚合查询,取最大年龄
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").aggregations("maxAge", a ->a.max(m -> m.field("age")))
                , Person.class);
        searchResponse.aggregations().entrySet().forEach(f -> System.out.println(f.getKey() + ":" + f.getValue().max().value()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 分组查询
     * @throws IOException
     */
    @GetMapping("/groupQueryDocument2")
    public void groupQueryDocument2() throws IOException {

        // 分组查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test")
                        .aggregations("ageGroup", a ->a.terms(t -> t.field("age")))
                , Person.class);
        searchResponse.aggregations().get("ageGroup").lterms().buckets().array().forEach(f -> System.out.println(f.key() + ":" + f.docCount()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }
}

三、测试

1.创建索引,名为my_index

在这里插入图片描述

在这里插入图片描述
查询结果显示创建成功
在这里插入图片描述

2.创建文档,给名为my_index的索引创建文档

在这里插入图片描述
在这里插入图片描述
查询结果显示创建文档成功
在这里插入图片描述

四、项目结构及代码下载

在这里插入图片描述
源码下载地址,欢迎Star哦~~
springboot-cacheable


参考资料

SpringBoot官方推荐对应Elasticsearch版本
SpringBoot集成elasticsearch 7.17.3及常规应用
Elasticsearch8.x版本中RestHighLevelClient被弃用
SpringBoot 整合ElasticSearch实现模糊查询,批量CRUD,排序,分页,高亮
windows 安装 Elasticsearch

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐