zoukankan      html  css  js  c++  java
  • 重磅来袭!!!Elasticsearch7.14.1(ES 7.14.1)与Springboot

    1. 概述

     前面我们聊了 Elasticsearch(ES)集群的搭建,今天我们来聊一下,Elasticsearch(ES)集群如何与 Springboot 进行整合。

     Elasticsearch(ES)集群的搭建可参见我的另一篇文章《Elasticsearch(ES)集群的搭建》。

     Elasticsearch(ES)集群 我们采用的是目前最新的 7.14.1 版本。

     Springboot 我们采用的是目前最新的 2.5.4 版本。

    2. Springboot 与  Elasticsearch(ES)的版本对应问题

    从 spring-boot-starter-data-elasticsearch 的 jar 包依赖来看,最新的 Springboot 2.5.4 版本 对应的 ElasticSearch(ES)版本应该是 7.12.1。

    经本人亲测,API完全可以兼容 ElasticSearch(ES)7.14.1 版本,所以完全不用担心兼容问题。

    如果担心有风险,可搭建 ElasticSearch(ES)7.12.1 版本的集群,搭建方法与 7.14.1 版本完全一致,可参见我的另一篇文章《Elasticsearch(ES)集群的搭建》。

    ElasticSearch(ES)7.12.1 版本下载地址:

    https://www.elastic.co/cn/downloads/past-releases#elasticsearch

    https://www.elastic.co/cn/downloads/past-releases/elasticsearch-7-12-1

    3. Elasticsearch(ES )与 Springboot 的整合

    3.1 使用 InterlliJ IDEA 创建Springboot项目

    1)打开IDEA,选择 New —> Project...

     2)选择 Spring Initializr, 填写项目名称等信息,点击【Next】

    3)依赖中勾选 Spring Data Elasticsearch(Access+Driver),点击【Finish】即可

    4)pom.xml 中的主要依赖

    复制代码
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.4</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    复制代码
    复制代码
        <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>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>
            </dependency>
        </dependencies>
    复制代码

    3.2 在 Elasticsearch(ES) 中创建索引 index_user 同时创建映射

    特别说明

    不建议使用 Java代码 对索引进行管理类操作,例如:创建索引、更新映射、删除索引。

    类似在mysql,我们通常不会用 Java代码 去进行建库、建表、改表、删表的操作,只用代码对表中的数据进行增删改查操作。

    PUT  http://192.168.1.8:9200/index_user

    参数:

    复制代码
    {
        "settings":{
            "index":{
                "number_of_shards":3,
                "number_of_replicas":1
            }
        },
        "mappings" : {
            "properties":{
                "user_id":{
                    "type":"keyword"
                },
                "name":{
                    "type": "text",
                    "fields": {
                        "keyword": {
                            "ignore_above": 256,
                            "type": "keyword"
                        }
                    },
                    "analyzer":"ik_max_word"
                },
                "login_name":{
                    "type":"keyword"
                },
                "age":{
                    "type":"integer"
                },
                "birthday":{
                    "type":"date"
                },
                "desc":{
                    "type":"text",
                    "analyzer":"ik_max_word"
                },
                "head_url":{
                    "type":"text",
                    "index":false
                }
            }
        }
    }
    复制代码

    3.3 配置 Springboot 配置文件

    打开 application.yml 文件,将 Elasticsearch(ES)的集群信息配置在里面

    复制代码
    spring:
      data:
        elasticsearch:
          client:
            reactive:
              endpoints: 192.168.1.8:9200,192.168.1.22:9200,192.168.1.144:9200
      elasticsearch:
        rest:
          uris: 192.168.1.8:9200,192.168.1.22:9200,192.168.1.144:9200
    复制代码

    3.4 创建实体类 User

    在实体类中用注解标识 实体 与 索引 的对应关系

    复制代码
    import lombok.Builder;
    import lombok.Getter;
    import lombok.Setter;
    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.FieldType;
    import org.springframework.data.elasticsearch.annotations.Setting;
    
    import java.util.Date;
    
    @Builder
    @Setter
    @Getter
    @Setting(shards = 3, replicas = 1)
    @Document(indexName = "index_user", createIndex = false)
    public class User {
    
        @Id
        @Field(store = true, name = "user_id", type = FieldType.Keyword)
        private String userId;
    
        @Field(store = true, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
        private String name;
    
        @Field(store = true, name = "login_name", type = FieldType.Keyword)
        private String loginName;
    
        @Field(store = true, type = FieldType.Integer)
        private Integer age;
    
        @Field(store = true, type = FieldType.Date)
        private Date birthday;
    
        @Field(store = true, searchAnalyzer = "ik_max_word", analyzer = "ik_max_word")
        private String desc;
    
        @Field(store = true, name = "head_url", type = FieldType.Keyword)
        private String headUrl;
    
    }
    复制代码

    3.5 单条文档的新增或更新

    这里我们使用单元测试,演示一下,Java代码是如何操作Elasticsearch(ES)的。

    文档ID不存在则新增文档,ID存在则更新文档

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.IndexQuery;
    import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        
        @Test
        public void save() throws ParseException {
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    
            User user = User.builder()
                    .userId("2")
                    .name("夏维尔")
                    .loginName("xwe")
                    .age(28)
                    .birthday(sdf.parse("1992-06-06"))
                    .desc("我是一名高级开发经理,每天坐地铁上班,在北京住,从不堵车")
                    .headUrl("https://www.zhuifengren.cn/img/xwe.jpg")
                    .build();
    
            elasticsearchRestTemplate.save(user);
        }
    
    }
    复制代码

    3.6 依据文档ID更新文档的部分字段

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.IndexQuery;
    import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
    import org.springframework.data.elasticsearch.core.query.UpdateQuery;
    import org.springframework.data.elasticsearch.core.query.UpdateResponse;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void update() {
    
            Map<String, Object> params = new HashMap<>();
            params.put("name", "夏维尔5");
    
            Document document = Document.from(params);
    
            UpdateQuery updateQuery = UpdateQuery.builder("2")  // 2 是文档的ID
                    .withDocument(document)
                    .build();
    
            UpdateResponse result = elasticsearchRestTemplate.update(updateQuery, IndexCoordinates.of("index_user"));
            System.out.println(JsonUtils.objectToJson(result));  // 结果:{"result":"UPDATED"}
        }
    
    }
    复制代码

    3.7 依据文档ID获得文档

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.IndexQuery;
    import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
    import org.springframework.data.elasticsearch.core.query.UpdateQuery;
    import org.springframework.data.elasticsearch.core.query.UpdateResponse;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void getById() {
    
            User user = elasticsearchRestTemplate.get("2", User.class);
            System.out.println(JsonUtils.objectToJson(user));
            // 结果:{"userId":"2","name":"夏维尔5","loginName":"xwe","age":28,"birthday":707760000000,"desc":"我是一名高级开发经理,每天坐地铁上班,在北京住,从不堵车","headUrl":"https://www.zhuifengren.cn/img/xwe.jpg"}
        }
    }
    复制代码

    3.8 依据文档ID删除文档

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.IndexQuery;
    import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
    import org.springframework.data.elasticsearch.core.query.UpdateQuery;
    import org.springframework.data.elasticsearch.core.query.UpdateResponse;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void delete() {
    
            String result = elasticsearchRestTemplate.delete("2", User.class);
            System.out.println(JsonUtils.objectToJson(result));  // 结果:"2"
        }
    }
    复制代码

    3.9 分页检索

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.SearchHits;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.*;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void searchForPage() {
    
            Pageable pageable = PageRequest.of(0,10);  // page 从第 0 页开始
    
            Query query = new NativeSearchQueryBuilder()
                    .withQuery(QueryBuilders.matchQuery("desc", "一名小学生")) 
                    .withQuery(QueryBuilders.termQuery("age", 10)) 
                    .withPageable(pageable)
                    .build();
    
            SearchHits<User> result = elasticsearchRestTemplate.search(query, User.class);
            System.out.println(JsonUtils.objectToJson(result));
        }
    }
    复制代码

    结果Json:

    复制代码
    {
        "totalHits": 1,
        "totalHitsRelation": "EQUAL_TO",
        "maxScore": 1,
        "scrollId": null,
        "searchHits": [
            {
                "index": "index_user",
                "id": "3",
                "score": 1,
                "sortValues": [],
                "content": {
                    "userId": "3",
                    "name": "迪士尼在逃仙柔",
                    "loginName": "dsnzxr",
                    "age": 10,
                    "birthday": 1308672000000,
                    "desc": "我是一名五年级的小学生,每天专车接专车送,中午在学校入伙,食堂菜可好了,上学期期末考试我拿了三好学生奖",
                    "headUrl": "https://www.zhuifengren.cn/img/dsnzxr.jpg"
                },
                "highlightFields": {},
                "innerHits": {},
                "nestedMetaData": null,
                "routing": null,
                "explanation": null,
                "matchedQueries": []
            }
        ],
        "aggregations": null,
        "empty": false
    }
    复制代码

     3.10 高亮的实现

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.elasticsearch.index.query.QueryBuilders;
    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 org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.SearchHits;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.*;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void highlight() {
    
            Pageable pageable = PageRequest.of(0,10);  // page 从第 0 页开始
    
            HighlightBuilder.Field highlightField = new HighlightBuilder.Field("desc")
                                                .preTags("<span>")
                                                .postTags("</span>");
    
            Query query = new NativeSearchQueryBuilder()
                    .withQuery(QueryBuilders.matchQuery("desc", "一名小学生"))
                    .withHighlightFields(highlightField)
                    .withPageable(pageable)
                    .build();
    
            SearchHits<User> result = elasticsearchRestTemplate.search(query, User.class);
            System.out.println(JsonUtils.objectToJson(result));
        }
    }
    复制代码

    结果Json:

    复制代码
    {
        "totalHits": 3,
        "totalHitsRelation": "EQUAL_TO",
        "maxScore": 3.0418546,
        "scrollId": null,
        "searchHits": [
            {
                "index": "index_user",
                "id": "3",
                "score": 3.0418546,
                "sortValues": [],
                "content": {
                    "userId": "3",
                    "name": "迪士尼在逃仙柔",
                    "loginName": "dsnzxr",
                    "age": 10,
                    "birthday": 1308672000000,
                    "desc": "我是一名五年级的小学生,每天专车接专车送,中午在学校入伙,食堂菜可好了,上学期期末考试我拿了三好学生奖",
                    "headUrl": "https://www.zhuifengren.cn/img/dsnzxr.jpg"
                },
                "highlightFields": {
                    "desc": [
                        "我是<span>一名</span>五年级的<span>小学生</span>,每天专车接专车送,中午在学校入伙,食堂菜可好了,上学期期末考试我拿了三好<span>学生</span>奖"
                    ]
                },
                "innerHits": {},
                "nestedMetaData": null,
                "routing": null,
                "explanation": null,
                "matchedQueries": []
            },
            {
                "index": "index_user",
                "id": "1",
                "score": 0.5957724,
                "sortValues": [],
                "content": {
                    "userId": "1",
                    "name": "僵尸猎手",
                    "loginName": "jsls",
                    "age": 25,
                    "birthday": 636220800000,
                    "desc": "我是一名房产经纪人,现在转行了,目前是一名运输工人",
                    "headUrl": "https://www.zhuifengren.cn/img/jsls.jpg"
                },
                "highlightFields": {
                    "desc": [
                        "我是<span>一名</span>房产经纪人,现在转行了,目前是<span>一名</span>运输工人"
                    ]
                },
                "innerHits": {},
                "nestedMetaData": null,
                "routing": null,
                "explanation": null,
                "matchedQueries": []
            },
            {
                "index": "index_user",
                "id": "2",
                "score": 0.46563908,
                "sortValues": [],
                "content": {
                    "userId": "2",
                    "name": "夏维尔",
                    "loginName": "xwe",
                    "age": 28,
                    "birthday": 707760000000,
                    "desc": "我是一名高级开发经理,每天坐地铁上班,在北京住,从不堵车",
                    "headUrl": "https://www.zhuifengren.cn/img/xwe.jpg"
                },
                "highlightFields": {
                    "desc": [
                        "我是<span>一名</span>高级开发经理,每天坐地铁上班,在北京住,从不堵车"
                    ]
                },
                "innerHits": {},
                "nestedMetaData": null,
                "routing": null,
                "explanation": null,
                "matchedQueries": []
            }
        ],
        "aggregations": null,
        "empty": false
    }
    复制代码

    3.11 自定义排序的实现

    复制代码
    import cn.zhuifengren.myelasticsearch.pojo.User;
    import cn.zhuifengren.myelasticsearch.utils.JsonUtils;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
    import org.elasticsearch.search.sort.FieldSortBuilder;
    import org.elasticsearch.search.sort.SortBuilder;
    import org.elasticsearch.search.sort.SortOrder;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.domain.PageRequest;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
    import org.springframework.data.elasticsearch.core.SearchHits;
    import org.springframework.data.elasticsearch.core.document.Document;
    import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
    import org.springframework.data.elasticsearch.core.query.*;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.HashMap;
    import java.util.Map;
    
    @SpringBootTest(classes = MyelasticsearchApplication.class)
    public class ElasticsearchTest {
    
        @Autowired
        private ElasticsearchRestTemplate elasticsearchRestTemplate;
    
        @Test
        public void sort() {
    
            Pageable pageable = PageRequest.of(0,10);  // page 从第 0 页开始
    
            HighlightBuilder.Field highlightField = new HighlightBuilder.Field("desc")
                    .preTags("<span>")
                    .postTags("</span>");
    
            SortBuilder<FieldSortBuilder> sortBuilder
                                = new FieldSortBuilder("age").order(SortOrder.DESC);
    
            Query query = new NativeSearchQueryBuilder()
                    .withQuery(QueryBuilders.matchQuery("desc", "一名小学生"))
                    .withHighlightFields(highlightField)
                    .withSort(sortBuilder)  // 排序可加多个
                    .withPageable(pageable)
                    .build();
    
            SearchHits<User> result = elasticsearchRestTemplate.search(query, User.class);
            System.out.println(JsonUtils.objectToJson(result));
        }
    }
  • 相关阅读:
    Gradle 是什么
    Spring AOP知识
    Spring IOC常用注解
    spring 依赖注入
    Java实现基数排序
    Java实现基数排序(解决负数也可以排序)
    2020/4/10安卓开发:Spinner下拉框
    Spring ioc使用
    java实现:归并排序
    centos中docker的安装
  • 原文地址:https://www.cnblogs.com/zhaisd/p/15545333.html
Copyright © 2011-2022 走看看