java集成ES的基本使用
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("==============================");
}
}
版权声明:
本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
寻梦!
喜欢就支持一下吧