1.项目基本配置

首先创建一个项目 `elasticsearch-demo`

依赖文件如下

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 指定父工程为 spring-boot-starter-parent -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
    </parent>

    <groupId>com.llh</groupId>
    <artifactId>elasticsearch-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

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

        <!-- springboot 集成elasticsearch 的启动器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <version>3.3.0</version>
        </dependency>

       <!-- java的对于elasticsearch的API集成 (现在我们一般都是用 springboot 集成的了,这种API的方式过于麻烦)-->
        <dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <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>
    </dependencies>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

</project>

项目的主启动类的编写

package com.llh;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Description: TODO
 * @Author lilinghao
 * @Date 2025/2/6
 **/
@SpringBootApplication
public class ElasticSearchMain {
    public static void main(String[] args) {
        SpringApplication.run(ElasticSearchMain.class, args);
    }
}

项目配置文件的编写

server:
  port: 9200
spring:
  application:
    name: "elasticsearch"
  elasticsearch:
    uris: "http://10.0.0.100:9200"

ES索引库的创建

PUT /my_index
{
  "settings": {
    "number_of_replicas": 0,
    "analysis": {
      "analyzer": {
        "ik_smart": {
          "type": "custom",
          "tokenizer": "ik_smart"
        },
        "ik_max_word": {
          "type": "custom",
          "tokenizer": "ik_max_word"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "index": true,
        "store": true,
        "analyzer": "ik_smart",
        "search_analyzer": "ik_max_word"
      },
      "category": {
        "type": "keyword",
        "index": true,
        "store": true
      },
      "images": {
        "type": "keyword",
        "index": true,
        "store": true
      },
      "price": {
        "type": "integer",
        "index": true,
        "store": true
      }
    }
  }
}

向索引库中添加文档

PUT /my_index/_doc/1
{"id":1,"title":"华为笔记本电脑","category":"华为","images":"http://www.gulixueyuan.com/xm.jpg","price":5388}

PUT /my_index/_doc/2
{"id":2,"title":"华为手机","category":"华为","images":"http://www.gulixueyuan.com/xm.jpg","price":5500}

PUT /my_index/_doc/3
{"id":3,"title":"VIVO手机","category":"vivo","images":"http://www.gulixueyuan.com/xm.jpg","price":3600}


2.springboot集成ES的使用

编写POJO实体类,这个实体类对应ES中的索引的mapping关系 (这个接类似于springboot集成mybatis-plus中需要创建一个实体类对应 数据库中的表)

package com.llh.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
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;

/**
 * @Description: TODO
 * @Author lilinghao
 * @Date 2025/2/6
 **/

@Data
@AllArgsConstructor
@Document(indexName = "my_index")        // 声明该实体类对应ES中的名为 my_index 的索引库
public class Product {
    @Id
    private Long id;
    private String category;
    private String images;
    private Integer price;
    @Field(type = FieldType.Text,analyzer = "ik_smart")
    private String title;
}

编写Repository层 (创建一个接口用来继承 ElasticsearchRepository接口,从而来获取简单的ES操作方法。这个就类似于 mybatis-plus中的mapper接口)

package com.llh.repository;

import com.llh.pojo.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

import java.util.List;

/**
 * @Description: TODO
 * @Author lilinghao
 * @Date 2025/2/7
 **/
// 创建一个继承于 ElasticsearchRepository 的接口。这个接口就类似于 mybatis-plus 中的 mapper接口,提供一些简单的增删改查功能。
    // 泛型 ElasticsearchRepository<{elasticsearch中索引对应的实体类类型},{索引中的主键类型}>
public interface ProductRepository extends ElasticsearchRepository<Product, Long> {

    // 自定义接口方法: 如果我们需要用的方法 ELasticsearchRepository 并没有提供,那么我们只需要根据方法的操作来对方法起名称,具体实现交给springboot集成的elasticsearch来实现
    List<Product> findByCategory(String categoryName);
}

为什么这里的 ProductRepository 接口并没有使用注解声明,但是仍然可以被使用@Autowired来进行让IOC自动创建Bean对象

在 Spring Data Elasticsearch 中,AlbumInfoIndexDao 接口虽然没有显式地使用 @Repository 或 @Component 等注解声明,但它仍然可以被 Spring IOC 容器管理,并通过 @Autowired 注入。这是因为 Spring Data 提供了一种特殊的机制,能够自动创建接口的实现类并注册到 Spring 容器中。以下是详细的解释:

1. Spring Data 的 Repository 自动扫描机制
Spring Data 提供了一个核心功能:自动创建 Repository 的实现类。当你定义一个接口并继承 Spring Data 提供的 Repository 接口(如 ElasticsearchRepository)时,Spring Data 会在应用启动时自动扫描这些接口,并为它们生成实现类。

关键点:
继承 ElasticsearchRepository:AlbumInfoIndexDao 继承了 ElasticsearchRepository,这告诉 Spring Data 这是一个 Elasticsearch 的 Repository 接口。

自动扫描:Spring Data 会扫描所有继承 Repository 的接口,并为它们生成实现类。

注册到 IOC 容器:生成的实现类会被自动注册到 Spring IOC 容器中,因此可以通过 @Autowired 注入。

2. Spring Data 的 Repository 实现原理
Spring Data 使用 动态代理 技术来实现 Repository 接口。具体步骤如下:

扫描接口:

Spring Data 在启动时会扫描所有继承 Repository 的接口。

如果接口继承了 ElasticsearchRepository,Spring Data 会将其识别为 Elasticsearch 的 Repository。

生成代理类:

Spring Data 使用 JDK 动态代理或 CGLIB 生成接口的实现类。

这个代理类会实现接口中定义的所有方法(包括方法名派生查询)。

注册到 IOC 容器:

生成的代理类会被注册到 Spring IOC 容器中,成为一个 Bean。

Bean 的名称通常是接口名称的首字母小写形式(如 albumInfoIndexDao)。

注入使用:

在其他组件中,可以通过 @Autowired 注入这个 Bean。

3. 为什么不需要显式注解?
@Repository 注解的作用:@Repository 是 Spring 的一个通用注解,用于标识数据访问组件(如 DAO)。它的主要作用是:

将类标记为 Spring 管理的 Bean。

提供异常转换(将特定持久化框架的异常转换为 Spring 的统一异常)。

Spring Data 的特殊处理:

Spring Data 会自动为继承 Repository 的接口生成实现类,并将其注册为 Bean。

因此,即使没有显式使用 @Repository,Spring Data 仍然会处理这些接口。

3.测试类的编写

package com.llh;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.llh.pojo.Product;
import com.llh.repository.ProductRepository;
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.Sort;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;

import java.util.List;
import java.util.Optional;

/**
 * @Description: springboot 集成 elasticsearch练习
 * @Author lilinghao
 * @Date 2025/2/6
 **/

@SpringBootTest
public class ElasticSearchTest {
    @Autowired
    // 这个是elasticsearch提供的连接elasticsearch的客户端,就类似于 redis-cli 这个工具(本质上就是一个连接服务端的工具)
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    // springboot整合ES后的 Repository接口,提供简单的功能方法(类似于MP中的mapper接口),对于简单的操作使用这个就可以
    private ProductRepository productRepository;

    @Autowired
    // 这个才是 springboot整合elasticsearch后的操作对象,就类似与 RedisTemplate
    private ElasticsearchTemplate elasticsearchTemplate;

    @Test
    // elasticsearchTemplate的练习
    public void saveProduct() throws Exception {
        Product product = new Product(4L,"大疆","https://www.dji.com/cn",5000,"大疆无人机");
        elasticsearchTemplate.save(product,IndexCoordinates.of("my_index"));
    }

    @Test
    // elasticsearchClient 的练习      (JAVA 对 ES的API整合方式)
    public void testSearch() throws Exception {
        SearchResponse<Object> search = elasticsearchClient.search(s -> {
            return s.index("my_index")
                    .query(f -> f.match(f1 -> f1.field("title").query("华为")));
        }, Object.class);
        List<Hit<Object>> hits = search.hits().hits();
        for(Hit<Object> hit : hits) {
            System.out.println(hit);
        }
    }

    @Test
    // ElasticSearchRepository练习
    public void testRepository(){
        productRepository.findById(1L)
                .ifPresent(System.out::println);
        this.partition();
        Iterable<Product> products = productRepository.findAll();
        products.forEach(System.out::println);
        this.partition();
        long count = productRepository.count();
        System.out.println("my_index索引有" + count +"条文档");
        productRepository.deleteById(4L);
        this.partition();
        productRepository.findByCategory("华为")
                .forEach(System.out::println);
    }

    public void partition(){
        // 定义一个方法,用来输出如下内容,以隔断不同方法的输出结果
        System.out.println("==============================");
        System.out.println("|                            |");
        System.out.println("|                            |");
        System.out.println("|                            |");
        System.out.println("==============================");
    }
}

文章作者: Administrator
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 寻梦
ELK技术栈
喜欢就支持一下吧