栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

Springboot 集成 ElasticSearch 7.14.1 ,ElasticsearchRestTemplate是个啥?

Springboot 集成 ElasticSearch 7.14.1 ,ElasticsearchRestTemplate是个啥?

Springboot + ElasticSearch 7.14.1
  • 从一个案例开始分析
    • pom
    • applicantion.yml
    • pojo
      • document 注解
      • 映射注释概述(摘自官网)
      • 索引设置(摘自官网)
    • 实体类 - 官方案例
    • Repository
    • Query 注解(摘自官网)
    • 继承 ElasticsearchRepository 得到的方法
    • 测试 ProductDao ElasticsearchRestTemplate
  • 核心类
    • ElasticsearchRestTemplate
      • ElasticsearchOperations
    • ElasticsearchRepository
      • 官网解释 CrudRepository
  • ElasticsearchRestTemplate 的关系
  • 文章说明

从一个案例开始分析 pom


    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.5.4
         
    
    com.dongua
    es-springboot-demo
    0.0.1-SNAPSHOT
    es-springboot-demo

    
        11
        7.14.1
    
    
     
        
            org.springframework.boot
            spring-boot-starter-data-elasticsearch
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.projectlombok
            lombok
        
        
            org.springframework.boot
            spring-boot-configuration-processor
        
        
            com.alibaba
            fastjson
            1.2.75
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    



applicantion.yml
spring:
  elasticsearch:
    rest:
    # es 的 uri
      uris: http://localhost:9200
      # 连接超时时间
      connection-timeout: 1
      # 读取超时时间
      read-timeout: 30

当然也可以根据自己的配置类定义

@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "elasticsearch")
@Data
@Configuration
public class RestHighClientConfig extends AbstractElasticsearchConfiguration {

    private String host;
    private int port;

    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        return new RestHighLevelClient
                (RestClient.builder(new HttpHost(host, port, "http")));
    }


// 这个也行
    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {

        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();

        return RestClients.create(clientConfiguration).rest();
    }
}

elasticsearch:
  host: 127.0.0.1
  port: 9200
pojo
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
// 别名,不设置的话,_class 的值就是 其全路径,例如 com.xxx.pojo.Product
@TypeAlias("product")
// index 的名字
@document(indexName = "product")
// 设置分片数量为 3个
@Setting(shards = 3)
public class Product {
	// 唯一标识,重复会被覆盖
    @Id
    private Long id;
    // text 类型,可被分词查询
    @Field(type = FieldType.Text)
    private String title;
    // 关键字 类型,根据整个词进行查询
    @Field(type = FieldType.Keyword)
    private String category;
    // Double 类型
    @Field(type = FieldType.Double)
    private Double price;
    // 该字段不作为索引,默认为索引,此处设为 false
    @Field(type = FieldType.Keyword, index = false)
    private String images;
}

document 注解

映射注释概述(摘自官网)

在MappingElasticsearchConverter使用元数据驱动的对象的映射文件。元数据取自可以注释的实体属性。

以下注释可用:

@document: 应用于类级别,表示该类是映射到数据库的候选。最重要的属性是:

indexName:存储该实体的索引名称。这可以包含一个 SpEL 模板表达式,如 “log-#{T(java.time.LocalDate).now().toString()}”

type:映射类型。如果未设置,则使用类的小写简单名称。(自 4.0 版起已弃用)

createIndex: 标记是否在存储库引导时创建索引。默认值为true。请参阅使用相应映射自动创建索引

versionType: 版本管理的配置。默认值为EXTERNAL。

@Id:应用于字段级别以标记用于标识目的的字段。

@Transient: 默认情况下,所有字段在存储或检索时都映射到文档,此注释不包括该字段。

@PersistenceConstructor: 标记给定的构造函数 - 甚至是受包保护的构造函数 - 在从数据库实例化对象时使用。构造函数参数按名称映射到检索到的文档中的键值。

@Field:应用于字段级别,定义字段的属性,大部分属性映射到各自的Elasticsearch Mapping定义

name: 字段名称,因为它将在 Elasticsearch 文档中表示,如果未设置,则使用 Java 字段名称。

type:字段类型,可以是Text、Keyword、Long、Integer、Short、Byte、Double、Float、Half_Float、Scaled_Float、Date、Date_Nanos、Boolean、Binary、Integer_Range、Float_Range、Long_Range、Double_Range、Date_Range、Ip_Range、Object之一, 嵌套, Ip, TokenCount, Percolator, Flattened, Search_As_You_Type。查看Elasticsearch 映射类型

format:一种或多种内置日期格式

pattern:一种或多种自定义日期格式

store: 标志是否应将原始字段值存储在 Elasticsearch 中,默认值为false。

索引设置(摘自官网)

使用 Spring Data Elasticsearch 创建 Elasticsearch 索引时,可以使用@Setting注释定义不同的索引设置。以下参数可用:

useServerConfiguration 不发送任何设置参数,因此 Elasticsearch 服务器配置确定它们。

settingPath 是指定义必须在类路径中解析的设置的 JSON 文件

shards要使用的分片数,默认为1

replicas副本数,默认为1

refreshIntervall, 默认为“1s”

indexStoreType, 默认为"fs"

也可以定义索引排序

@Setting 源码和解释

@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface Setting {

	
	String settingPath() default "";

	
	boolean useServerConfiguration() default false;

	
	short shards() default 1;

	
	short replicas() default 1;

	
	String refreshInterval() default "1s";

	
	String indexStoreType() default "fs";

	
	String[] sortFields() default {};

	
	SortOrder[] sortOrders() default {};

	
	SortMode[] sortModes() default {};

	
	SortMissing[] sortMissingValues() default {};

	// 提供内部枚举供使用
	enum SortOrder {
		asc, desc
	}

	enum SortMode {
		min, max
	}

	enum SortMissing {
		_last, _first
	}
}

实体类 - 官方案例
@document(indexName = "entities")
@Setting(
  sortFields = { "secondField", "firstField" },                                    // 1处  
  sortModes = { Setting.SortMode.max, Setting.SortMode.min },                      // 2处
  sortOrders = { Setting.SortOrder.desc, Setting.SortOrder.asc },
  sortMissingValues = { Setting.SortMissing._last, Setting.SortMissing._first })
class Entity {
    @Nullable
    @Id private String id;

    @Nullable
    @Field(name = "first_field", type = FieldType.Keyword)
    private String firstField;

    @Nullable @Field(name = "second_field", type = FieldType.Keyword)
    private String secondField;

    // getter and setter...
}

1.处:定义排序字段时,使用 Java 属性的名称 ( firstField ),而不是可能为 Elasticsearch 定义的名称 ( first_field )
2.处 sortModes,sortOrders和sortMissingValues是可选的,但如果设置了它们,则条目数必须与sortFields元素数匹配

就是命名,驼峰和下划线的区分,java的属性用驼峰,数据库用下划线的意思

@Filed 注解源码

Repository
import com.dongua.pojo.Product;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

// 这里面就是咱 CRUD 一些封装的核心,一会再探究一番
@Repository
public interface ProductDao extends ElasticsearchRepository {

}

Query 注解(摘自官网)

继承 ElasticsearchRepository 得到的方法

测试 ProductDao ElasticsearchRestTemplate

按照官网以及代码的提示,先测几个 api

@SpringBootTest
public class SpringDataESProductDaoTest {

	// ElasticsearchRestTemplate  实际上 实现的是 ElasticsearchOperations接口
    @Resource
    ElasticsearchRestTemplate restTemplate;

    @Resource
    private ProductDao productDao;

	// 在初始已经创建了该索引,再用此方法不能再创建一次,这会报错
    @Test
    public void createIndex() {
        boolean b = restTemplate.indexOps(Product.class).create();
        System.out.println("b = " + b);
    }

    @Test
    public void exists() {
        // 判断 id 为 5 的文档数据有没有
        boolean product = restTemplate.exists("5", Product.class);
        System.out.println("判断 id 为 5 的文档数据有没有 " + product);
        // 判断 product 索引存不存在 (我们已经初始化是定义了 Product 的索引名字)
        boolean exists = restTemplate.indexOps(Product.class).exists();
        System.out.println("判断 product 索引存不存在 " + exists);
        boolean user = restTemplate.indexOps(IndexCoordinates.of("user")).exists();
        // 判断名字叫 user 索引存不存在
        System.out.println("判断 user 索引存不存在 " + user);

    }
    
    
    @Test
    public void save() {
        Product product = new Product();
        // 全局唯一,重复会覆盖
        product.setId(1L);
        product.setTitle("华为手机4");
        product.setCategory("手机");
        product.setPrice(2999.0);
        product.setImages("http://www.xxx/hw.jpg");
        product.setScore(1);
        productDao.save(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/1

    //修改一条文档
    @Test
    public void update() {
        Product product = new Product();
        product.setId(1L);
        product.setTitle("小米 2 手机");
        product.setCategory("手机");
        product.setPrice(9999.0);
        product.setImages("http://www.xxx/xm.jpg");
        product.setScore(8);
        productDao.save(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/1


    //根据 id 查询文档
    @Test
    public void findById() {
        Product product = productDao.findById(2L).get();
        System.out.println(product);
    }

	// 查询所有 文档
    @Test
    public void findAll() {
        Iterable products = productDao.findAll();
        for (Product product : products) {
            System.out.println(product);
        }
    }


    // 删除索引
    @Test
    public void deleteIndex() {
    	// 这里使用了 restTemplate 的 indexOps() 获取 IndexOperations 对象操作索引
    	// dao 所提供的方法不支持操作索引
        boolean delete = restTemplate.indexOps(Product.class).delete();
        System.out.println("delete = " + delete);
    }

    //删除一条文档
    @Test
    public void delete() {
        Product product = new Product();
        product.setId(2L);
        productDao.delete(product);
    }
    //POSTMAN, GET http://localhost:9200/product/_doc/2

    //批量新增文档
    @Test
    public void saveAll() {
        List productList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Product product = new Product();
            product.setId(Long.valueOf(i));
            product.setTitle("[" + i + "]小米手机");
            product.setCategory("手机");
            product.setPrice(1999.0 + i);
            product.setImages("http://www.xxx/xm.jpg");
            productList.add(product);
        }
        productDao.saveAll(productList);
    }

    //分页查询
    @Test
    public void findByPageable() {
        // 设置排序(排序方式,正序还是倒序,排序的 id)
        Sort sort = Sort.by(Sort.Direction.DESC, "id");
        int currentPage = 0;//当前页,第一页从 0 开始, 1 表示第二页
        int pageSize = 5;//每页显示多少条
        // 设置查询分页
        // 即使不提供 sort 参数,他也会自己做某种排序规则
        PageRequest pageRequest = PageRequest.of(currentPage, pageSize, sort);
        //分页查询
        Page productPage = productDao.findAll(pageRequest);
        System.out.println("总共的元素数目 = " + productPage.getTotalElements());
        for (Product Product : productPage.getContent()) {
            System.out.println(Product);
        }
        // 这个也行
        Iterable products = productDao.findAll(Pageable.ofSize(5));
        for (Product product : products) {
            System.out.println(product);
        }
    }
}

不去全部测试了

  1. 在执行除查询方法时,索引就已经被初始化了
  2. 这里只列举了部分的 api 测试,其他的大家可以自己慢慢试
  3. restTemplate.indexOps(Product.class).方法 操作索引,本质是使用了 IndexOperations 对象
核心类 ElasticsearchRestTemplate

ElasticsearchRestTemplate 继承 AbstractElasticsearchTemplate

AbstractElasticsearchTemplate 实现 ElasticsearchOperations 接口

ElasticsearchOperations 继承 documentOperations, SearchOperations

摘自官网的对于 Elasticsearch 操作 的解释:

  • IndexOperations 定义索引级别的操作,例如创建或删除索引。
  • documentOperations 定义基于 id 存储、更新和检索实体的操作。
  • SearchOperations 定义使用查询搜索多个实体的操作
  • ElasticsearchOperations结合了documentOperations和SearchOperations接口。
ElasticsearchOperations

写一个 TestController 测试一波 ElasticsearchOperations

// 测试 ElasticsearchOperations
@RestController
@RequestMapping("/")
public class TestController {

    private final ElasticsearchOperations elasticsearchOperations;

    public TestController(ElasticsearchOperations elasticsearchOperations) {
        this.elasticsearchOperations = elasticsearchOperations;
    }

    @PostMapping("/user")
    public String save(@RequestBody User user) {
		// 索引查询对象:设置查询条件
        IndexQuery indexQuery = new IndexQueryBuilder()
        		// .withVersion(2L) 设置版本号为 2
                .withId(String.valueOf(user.getId()))// 设置索引 id 为 user 的id
                .withObject(user) // 告诉他是哪个实体对象
                .build(); // 返回
                
                // IndexCoordinates.of("user") 索引 名字叫 user ,自定义
                // 若没有这个索引他会自己创建索引,并增加/更新一条 User 文档数据
        return elasticsearchOperations.index(indexQuery, IndexCoordinates.of("user"));
    }

    @PostMapping("/product")
    public String save2(@RequestBody Product product) {

        IndexQuery indexQuery = new IndexQueryBuilder()
                .withId(String.valueOf(product.getId()))
                .withObject(product)
                .build();
        return elasticsearchOperations.index(indexQuery, IndexCoordinates.of("product"));
    }

	// 根据 id 查找
    @GetMapping("/user/{id}")
    public User findById(@PathVariable("id") Long id) {
        return elasticsearchOperations.get(String.valueOf(id), User.class, IndexCoordinates.of("user"));
    }

	// 查询所有
    @GetMapping("/user/")
    public List> search() {
        SearchHits hits = elasticsearchOperations.search(Query.findAll(), User.class, IndexCoordinates.of("user"));
        hits.forEach(System.out::println);
        return hits.getSearchHits();
    }

    @GetMapping("/product/")
    public List> search2() {
        SearchHits hits = elasticsearchOperations.search(Query.findAll(), Product.class, IndexCoordinates.of("product"));
        hits.forEach(System.out::println);
        return hits.getSearchHits();
    }

}

indexQuery 的一些查询条件

  • 如果找到了对应的查询条件的文档数据,就更新这个文档(注意版本约束)
  • 如果没找到就新增


IndexOperations 部分源码

package org.springframework.data.elasticsearch.core;
 ·······


public interface IndexOperations {

	boolean create();

	boolean create(Map settings);

	boolean create(Map settings, document mapping);

	boolean createWithMapping();

	boolean delete();

	boolean exists();

	void refresh();

	document createMapping();

	document createMapping(Class clazz);

	default boolean putMapping() {
		return putMapping(createMapping());
	}

	boolean putMapping(document mapping);

	default boolean putMapping(Class clazz) {
		return putMapping(createMapping(clazz));
	}

	Map getMapping();

	Settings createSettings();

	Settings createSettings(Class clazz);

	Settings getSettings();

	Settings getSettings(boolean includeDefaults);

}

ElasticsearchRepository

ElasticsearchRepository 继承 PagingAndSortingRepository

PagingAndSortingRepository 继承 CrudRepository
CrudRepository

官网解释 CrudRepository

ElasticsearchRestTemplate 的关系
  • ElasticsearchRestTemplate是ElasticsearchOperations使用高级 REST 客户端的接口的实现。
  • ElasticsearchRestTemplate使用的还是RestHighLevelClient

我们自定义配置类继承的 AbstractElasticsearchConfiguration 抽象类源码

public abstract class AbstractElasticsearchConfiguration extends ElasticsearchConfigurationSupport {

	
	@Bean
	public abstract RestHighLevelClient elasticsearchClient();

	
	@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
	public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter,
			RestHighLevelClient elasticsearchClient) {

		ElasticsearchRestTemplate template = new ElasticsearchRestTemplate(elasticsearchClient, elasticsearchConverter);
		template.setRefreshPolicy(refreshPolicy());

		return template;
	}
}

本质上只是为 RestHighLevelClient 做了一层封装

所以我们用这个ElasticsearchRestTemplate更舒服,使用 RestHighLevelClient 就显得很多冗余了。

文章说明

第一次在官网上自学一个技术栈,希望记录所学。
有所纰漏,敬请谅解

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/281724.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号