• ElasticSearch从入门到精通--第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)


    ElasticSearch从入门到精通–第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

    ElasticSearch从入门到精通–第一话(入门篇)
    ElasticSearch从入门到精通–第二话(原生API调用–纯代码篇)
    ElasticSearch从入门到精通–第三话(集群环境搭建篇)
    ElasticSearch从入门到精通–第四话(核心概念篇)
    ElasticSearch从入门到精通–第五话(整合SpringBoot高效开发、分页高亮等、Kibana使用篇)

    Kibana

    Kibana是一个开源的图形化管理界面,能够对Elasticsearch的数据进行可视化管理,且可在Elastic Stack中进行导航,可以完成各种操作,从跟踪查询负载,到理解请求如何流经应用都能轻松完成。

    windows版7.3.0版本kibana下载(最好和es版本相同的)

    1. 下载好后,解压(解压了2个多小时。。。)

    2. 修改config/kibana.yml文件

      # 服务端口
      server.port: 5601
      # ES服务器/集群的地址
      elasticsearch.hosts: ["http://localhost:1001","http://localhost:1002","http://localhost:1003"]
      # 索引名
      kibana.index: ".kibana"
      # 编码格式
      i18n.locale: "zh-CN"
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
    3. 启动bin下的执行文件

    4. 访问http://localhost:5601

    在这里插入图片描述

    可到Console控制台中,直接通过json接口处理数据

    在这里插入图片描述

    详细kibana入门教程请看

    整合Spring Data

    SpringData是一个用于简化数据库、非关系数据库、索引库访问,支持云服务的开源框架。Spring Data 的使命是给各种数据访问提供统一的编程接口,不管是关系型数据库(如MySQL),还是非关系数据库(如Redis),或者类似Elasticsearch这样的索引数据库。从而简化开发人员的代码,提高开发效率。

    我们要使用的就是 Spirng Data Elasticsearch模块项目。

    项目特性:

    • 支持Spring的基于@Configuration的java配置方式,或者XML配置方式
    • 提供了用于操作ES的便捷工具类ElasticsearchTemplate。包括实现文档到POJO之间的自动智能映射。
      利用Spring的数据转换服务实现的功能丰富的对象映射
    • 基于注解的元数据映射方式,而且可扩展以支持更多不同的数据格式
    • 根据持久层接口自动生成对应实现方法,无需人工编写基本操作代码(类似mybatis,根据接口自动得到实现)。当然,也支持人工定制查询

    那么大概也看了一下,整合SpringData后,可以使用几种方式去操作es索引,都可以使用,但是有些方法已经过时了,建议通常情况下涉及复杂业务查询时,还是使用自定义方法查询原生API查询(代码较多,未封装),有几种方式可使用(注意:引入spring-boot-starter-data-elasticsearch后,这几种方式都可以用的):

    • 使用原生API,RestHighLevelClient高级客户端,但是使用起来还是有些复杂的
    • 使用springdata提供的模板工具类ElasticsearchRestTemplate,这个直接引入就可以了(是spring容器中的组件),对这个工具类了解不多,有兴趣可以查阅资料
    • (个人推荐使用)使用继承自ElasticsearchRepository的接口类,ElasticsearchRepository类提供了一些常用的增删改查,这些增删改查的操作是指针对文档数据的,若要对索引操作,还是用上面两种方法;且我们可以在ElasticsearchRepository子接口中,像使用jpa一样,自定义方法名且不需要具体实现,springdata会帮我们自动生成实现内容(开发效率非常高,像复杂查询、高亮、分页都可以使用这种方式实现,非常好用)

    集成前,注意版本

    在这里插入图片描述

    创建一个项目,然后引入相关依赖pom.xml

    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.3.6.RELEASEversion>
    parent>
    
    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>
    
    <dependencies>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
        dependency>
    
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-elasticsearchartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-testartifactId>
        dependency>
    
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-configuration-processorartifactId>
        dependency>
    
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    做些配置,application.yml文件

    # es相关
    elasticsearch:
      host: 127.0.0.1
      port: 9200
    # 日志相关
    logging:
      level:
        com.wlh.es: info
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    然后创建一个数据实体类,通过注解方式进行java类和es索引数据的双向关联

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    /**
     * indexName:索引名称
     * shards:分片数量
     * replicas:副本数,默认1
     */
    @Document(indexName = "shopping", shards = 3, replicas = 1)
    public class Product {
    
        // 标明是id主键
        @Id
        private Long id;
    
        /**
         * 标明是文档中的字段field
         *   type:设置字段的映射类型是text类型,那么会被分词器拆解词条
         *   analyzer:设置使用的分词器
         *   index:是否能被索引查询
         */
        @Field(type = FieldType.Text)
        private String title;
    
        // 设置为Keyword类型,不会被分词,是作为一个整体存在
        @Field(type = FieldType.Keyword)
        private String category;
        
        // 浮点数类型
        @Field(type = FieldType.Double)
        private Double price;
    
        // Keyword类型,且不能被索引查询
        @Field(type = FieldType.Keyword, index = false)
        private String images;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    搞个es的config配置类做个配置

    @Configuration
    @ConfigurationProperties(prefix = "elasticsearch")
    @Data
    public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
    
        private String host;
        private Integer port;
    
        @Override
        public RestHighLevelClient elasticsearchClient() {
            return new RestHighLevelClient(RestClient.builder(new HttpHost(host, port)));
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    创建个数据访问对象,可直接继承spring data es提供的,然后直接用里面的定义好的访问方法即可。

    @Repository
    // 有两个泛型,第一是要操作的数据对象类,第二个是序列化的id
    public interface ProductDao extends ElasticsearchRepository<Product, Long> {
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    测试执行下试试

    索引

    创建索引

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringDataTest {
    
        @Autowired
        private ElasticsearchRestTemplate template;
    
        @Test
        public void createIndex() {
            // 当项目启动时,索引如果不存在则会被自动创建
            System.out.println("索引被创建啦");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    通常项目启动时,会去找数据索引类,然后去es服务器看看有没有索引,没有的话会自动创建一个索引,执行下试试。

    执行完毕

    在这里插入图片描述

    然后去kibana看看创建的索引

    在这里插入图片描述

    已经创建完毕啦。

    删除索引

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringDataTest {
    
        @Autowired
        private ElasticsearchRestTemplate template;
    
        @Test
        public void deleteIndex() {
            template.deleteIndex(Product.class);
            System.out.println("删除索引啦");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    deleteIndex()方法是一个过时方法了,有兴趣可以自行查阅资料。

    在这里插入图片描述

    文档

    新增文档

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringDocTest {
    
        @Autowired
        private ProductDao productDao;
    
        /**
         * 新增文档
         */
        @Test
        public void save() {
            Product product = new Product(1L, "小米手机", "手机", 2999.99, "http://localhost/a.jpeg");
            productDao.save(product);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行完毕,到kibana看下数据情况

    在这里插入图片描述

    修改文档

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringDocTest {
    
        @Autowired
        private ProductDao productDao;
        /**
         * 修改文档
         * 实际只要是和文档有相同id的,继续调用save方法,即可完成修改
         */
        @Test
        public void update() {
            Product product = new Product(1L, "华为的手机", "手机", 3999.99, "http://localhost/a.jpeg");
            productDao.save(product);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    执行下,到kibana看看,数据已经变更了

    在这里插入图片描述

    查询文档

    /**
     * 根据id查询
     */
    @Test
    public void getById() {
        Product product = productDao.findById(1L).get();
        System.out.println(product);
    }
    
    /**
     * 查所有
     */
    @Test
    public void findAll() {
        Iterable<Product> all = productDao.findAll();
        for (Product product : all) {
            System.out.println(product);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    Product(id=1, title=华为的手机, category=手机, price=3999.99, images=http://localhost/a.jpeg)
    
    .......
    Product(id=1, title=华为的手机, category=手机, price=3999.99, images=http://localhost/a.jpeg)
    
    • 1
    • 2
    • 3
    • 4

    删除文档

    @Test
    public void delete() {
        Product product = new Product();
        product.setId(1L);
        productDao.delete(product);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    批量新增

    /**
     * 批量新增
     */
    @Test
    public void saveBatch() {
        List<Product> products = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            Product product = new Product((long) i, "【"+i+"】华为手机", "手机", 2000.00 + i, "http://localhost/a.jpeg");
            products.add(product);
        }
        productDao.saveAll(products);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    新增完,查询一下看看

    在这里插入图片描述

    排序+分页查询

    /**
     * 排序+分页查询
     */
    @Test
    public void findByPageable() {
        // 设置排序(根据id升序排序)
        Sort sort = Sort.by(Sort.Direction.ASC, "id");
        int page = 0;
        int size = 5;
        PageRequest pageRequest = PageRequest.of(page, size, sort);
        Page<Product> all = productDao.findAll(pageRequest);
        all.getContent().forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    结果排序+分页

    Product(id=0, title=【0】华为手机, category=手机, price=2000.0, images=http://localhost/a.jpeg)
    Product(id=1, title=【1】华为手机, category=手机, price=2001.0, images=http://localhost/a.jpeg)
    Product(id=2, title=【2】华为手机, category=手机, price=2002.0, images=http://localhost/a.jpeg)
    Product(id=3, title=【3】华为手机, category=手机, price=2003.0, images=http://localhost/a.jpeg)
    Product(id=4, title=【4】华为手机, category=手机, price=2004.0, images=http://localhost/a.jpeg)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:上面的page为0表示是查询第一页,如果要查询第二页数据,那么page=1

    自定义查询

    继承自ElasticsearchRepository类后,能继承一些基本的索引、文档的操作,但是涉及到复杂查询时,我们就需要去自定义一些查询了

    自定义查询的方式挺多,简单介绍下类似jpa方式的查询,在继承ElasticsearchRepository的子接口中,定义相关的方法即可。

    条件查询

    在这里插入图片描述

    并且在编写方法名称时,会自动提示,用起来嘎嘎爽。

    接口层方法

    @Repository
    public interface ProductDao extends ElasticsearchRepository<Product, Long> {
    
        List<Product> findByTitle(String title);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    处理层

    @Test
    public void termQuery() {
        List<Product> products = productDao.findByTitle("为华");
        products.forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    结果

    Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg)
    Product(id=0, title=【0】华为手机, category=手机, price=2000.0, images=http://localhost/a.jpeg)
    Product(id=2, title=【2】华为手机, category=手机, price=2002.0, images=http://localhost/a.jpeg)
    Product(id=3, title=【3】华为手机, category=手机, price=2003.0, images=http://localhost/a.jpeg)
    Product(id=4, title=【4】华为手机, category=手机, price=2004.0, images=http://localhost/a.jpeg)
    Product(id=1, title=【1】华为手机, category=手机, price=2001.0, images=http://localhost/a.jpeg)
    Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    并且有分词器的存在,查询时,虽然是写的为华,但是查询时,会将为华拆解为为、华,然后去倒排表中查询,所有匹配到的数据都会被查询出来。

    条件+分页+排序查询

    接口层

    Page<Product> findByTitleOrderByIdAsc(String title, Pageable pageable);
    
    • 1

    处理层

    要注意:es这边分页查询时,页数从0开始的

    @Test
    public void query() {
        PageRequest pageRequest = PageRequest.of(1, 5);
        Page<Product> order = productDao.findByTitleOrderByIdAsc("华", pageRequest);
        order.forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    结果

    Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg)
    Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg)
    
    • 1
    • 2

    过多不再介绍,遇到复杂的业务场景时,可以查阅官方文档

    自定义查询官方文档定位

    高亮查询❤

    这个处理起来也比较简单了,先给个官方地址吧,方便查阅,高亮查询注解版

    接口层,一个@Highligh注解搞定,注意配置高亮标签参数

    @Highlight(fields = {
        @HighlightField(name = "title")},
               parameters = 
               @HighlightParameters(preTags = "", postTags = "", fragmentSize = 500, numberOfFragments = 3)
              )
    SearchPage<Product> findByTitleOrderByIdAsc(String title, Pageable pageable);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    处理层

    @Test
    public void query() {
        PageRequest pageRequest = PageRequest.of(1, 5);
        SearchPage<Product> productSearchPage = productDao.findByTitleOrderByIdAsc("华", pageRequest);
        productSearchPage.getSearchHits().forEach(System.out::println);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    高亮字段在highlightFields中

    SearchHit{id='5', score=NaN, sortValues=[5], content=Product(id=5, title=【5】华为手机, category=手机, price=2005.0, images=http://localhost/a.jpeg), highlightFields={title=[【5】为手机]}}
    SearchHit{id='6', score=NaN, sortValues=[6], content=Product(id=6, title=【6】华为手机, category=手机, price=2006.0, images=http://localhost/a.jpeg), highlightFields={title=[【6】为手机]}}
    
    • 1
    • 2

    如果查询时,不进行分页,那么Dao这么写

    @SuppressWarnings("SpringDataRepositoryMethodReturnTypeInspection")	// 压制警告
    @Highlight(fields = {
        @HighlightField(name = "title")},
               parameters =
               @HighlightParameters(preTags = "", postTags = "", fragmentSize = 500, numberOfFragments = 3)
              )
    List<SearchHit<Product>> findByTitle(String title);
    // 或这么写
    SearchHits<Product> findByTitle(String title);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    旅行商问题(TSP)的相关论文总结
    HC32 IIC/I2C读写
    layui table表格使用table.resize()方法 重置表格尺寸
    开发H5程序或者小程序的时候,后端Web API项目在IISExpress调试中使用IP地址,便于开发调试
    【分布式技术专题】「架构实践于案例分析」总结和盘点目前常用分布式技术特别及问题分析
    ROS1学习笔记:服务中的Service和Client(ubuntu20.04)
    柯桥英语口语学校,商务英语BEC考前须知
    Small Pipefish
    9大性能优化经验总结,强烈建议收藏!
    中国氢能汽车商业化之路,还要开多远?
  • 原文地址:https://blog.csdn.net/weixin_45248492/article/details/127781979