[JAVA]elasticsearchrepository中的所有方法都已弃用
版本选择
要升级到Elasticsearch8.2,首先要选择合适的版本。
在pom.xml里修改SpringBoot依赖的版本为2.6.6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
Spring Data Elasticsearch的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
遇到的问题
在application.yml中,原来我们用来配置Elasticsearch访问路径和集群名称的配置已经不建议使用了,应该如下所配置:
server:
port: 8090
spring:
redis:
database: 0
port: 6379
host: 192.168.69.201
password: wtl1992
elasticsearch:
password: 'XXXXXXXXXXXX'
username: elastic
# uris:是个以,分隔的数组
uris: http://ljxwtl.cn:9200
最大的问题还是ElasticsearchTemplate已经过时了,不建议使用了!!!
使用ElasticsearchRestTemplate的search()方法来代替
总之:
Elasticsearch从6.x升级到7.x改动还真不是一般的大,ElasticsearchTemplate不建议使用了,改为使用ElasticsearchRestTemplate,ElasticsearchRepository实现复杂查询的方法也不建议使用了。从此我们简单的数据操作可以使用ElasticsearchRepository,而复杂的数据操作只能使用ElasticsearchRestTemplate了。
API的使用:
Person.java:
package ljxwtl;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.io.Serializable;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "person",createIndex = true)
public class Person implements Serializable {
@Id
@Field(type = FieldType.Auto)
private String id;
@Field(type = FieldType.Text,index = true)
private String name;
@Field(type = FieldType.Integer,index = true)
private Integer age;
@Field(type = FieldType.Keyword,index = true)
private String sex;
@Field(type = FieldType.Keyword,index = true)
private String tel;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Field(type = FieldType.Date, format = DateFormat.date_time, pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
}
PersonRepository.java:
package ljxwtl.dao;
import ljxwtl.Person;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
/**
* @author: wtl
* @License: (C) Copyright 2022, wtl Corporation Limited.
* @Contact: 1050100468@qq.com
* @Date: 2022/4/10 8:20
* @Version: 1.0
* @Description:
*/
public interface PersonRepository extends ElasticsearchRepository<Person,String> {
}
测试类:
package ljxwtl;
import ljxwtl.dao.PersonRepository;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.clients.elasticsearch7.ElasticsearchAggregations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
import org.springframework.data.elasticsearch.core.query.UpdateResponse;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @author: wtl
* @License: (C) Copyright 2022, wtl Corporation Limited.
* @Contact: 1050100468@qq.com
* @Date: 2022/4/10 7:43
* @Version: 1.0
* @Description:
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = SpringBootApplicationMain.class)
public class ApplicationMainTest {
@Resource
private PersonRepository personRepository;
@Resource
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void test(){
System.out.println(personRepository);
System.out.println(elasticsearchRestTemplate);
}
@Test
public void createIndex(){
IndexCoordinates indexCoordinates = IndexCoordinates.of("person");
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);
boolean created = indexOperations.create();
System.out.println(created);
}
@Test
public void setIndexMappings(){
IndexCoordinates indexCoordinates = IndexCoordinates.of("person");
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);
boolean created = indexOperations.putMapping(Person.class);
System.out.println(created);
}
@Test
public void createIndexWithSetSettings(){
IndexCoordinates indexCoordinates = IndexCoordinates.of("person");
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);
Map<String,Object> settings = new HashMap<>();
//----------------------------------------静态设置开始----------------------------------------------
// 静态设置:只能在索引创建时或者在状态为 closed index(闭合的索引)上设置
//主分片数,默认为5.只能在创建索引时设置,不能修改
settings.put("index.number_of_shards",2);
//是否应在索引打开前检查分片是否损坏,当检查到分片损坏将禁止分片被打开
settings.put("index.shard.check_on_startup","false");//默认值
// settings.put("index.shard.check_on_startup","checksum");//检查物理损坏
// settings.put("index.shard.check_on_startup","true");//检查物理和逻辑损坏,这将消耗大量内存和CPU
// settings.put("index.shard.check_on_startup","fix");//检查物理和逻辑损坏。有损坏的分片将被集群自动删除,这可能导致数据丢失
//自定义路由值可以转发的目的分片数。默认为 1,只能在索引创建时设置。此值必须小于index.number_of_shards
settings.put("index.routing_partition_size",1);
//默认使用LZ4压缩方式存储数据,也可以设置为 best_compression,它使用 DEFLATE 方式以牺牲字段存储性能为代价来获得更高的压缩比例。
settings.put("index.codec","best_compression");
//----------------------------------------静态设置结束----------------------------------------------
//----------------------------------------动态设置开始----------------------------------------------
//每个主分片的副本数。默认为 1。
settings.put("index.number_of_replicas",0);
//基于可用节点的数量自动分配副本数量,默认为 false(即禁用此功能)
settings.put("index.auto_expand_replicas",false);
//执行刷新操作的频率,这使得索引的最近更改可以被搜索。默认为 1s。可以设置为 -1 以禁用刷新。
settings.put("index.refresh_interval","1s");
//用于索引搜索的 from+size 的最大值。默认为 10000
settings.put("index.max_result_window",10000);
// 在搜索此索引中 rescore 的 window_size 的最大值
settings.put("index.max_rescore_window",10000);
//设置为 true 使索引和索引元数据为只读,false 为允许写入和元数据更改。
settings.put("index.blocks.read_only",false);
// 设置为 true 可禁用对索引的读取操作
settings.put("index.blocks.read",false);
//设置为 true 可禁用对索引的写入操作。
settings.put("index.blocks.write",false);
// 设置为 true 可禁用索引元数据的读取和写入。
settings.put("index.blocks.metadata",false);
//索引的每个分片上可用的最大刷新侦听器数
settings.put("index.max_refresh_listeners",1000);
//----------------------------------------动态设置结束----------------------------------------------
boolean created = indexOperations.create(settings);
System.out.println(created);
}
@Test
public void deleteIndex(){
IndexCoordinates indexCoordinates = IndexCoordinates.of("person");
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);
boolean isDeleted = indexOperations.delete();
System.out.println(isDeleted);
}
@Test
public void saveOne(){
Person person = new Person();
person.setId("1");
person.setName("王天龙");
person.setAge(30);
person.setSex("man");
person.setTel("1111111");
person.setCreateTime(new Date());
Person savePerson = personRepository.save(person);
System.out.println(savePerson);
}
@Test
public void updateOne(){
Document document = Document.create();
document.setId("1");
document.put("name","天龙战神");
UpdateQuery.Builder builder = UpdateQuery.builder("1").withDocument(document).withScriptedUpsert(true);
UpdateResponse updateResponse = elasticsearchRestTemplate.update(builder.build(), IndexCoordinates.of("person"));
System.out.println(updateResponse.getResult());
}
@Test
public void saveAll(){
List<Person> personList = new ArrayList<>(3);
Person person2 = new Person();
person2.setId("2");
person2.setName("王天祥");
person2.setAge(26);
person2.setSex("男");
person2.setTel("222222222222");
person2.setCreateTime(new Date());
personList.add(person2);
Person person3 = new Person();
person3.setId("3");
person3.setName("王杰");
person3.setAge(31);
person3.setSex("女");
person3.setTel("3333333333");
person3.setCreateTime(new Date());
personList.add(person3);
personRepository.saveAll(personList);
}
@Test
public void searchMatchAll() throws IOException {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder);
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.getSearchHits().forEach(personSearchHit -> {
Person content = personSearchHit.getContent();
System.out.println(content);
});
}
@Test
public void searchBoolMustWhere(){
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.matchQuery("name","王天龙"));
boolQueryBuilder.must(QueryBuilders.matchQuery("age",30));
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder);
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.forEach(personSearchHit -> {
System.out.println(personSearchHit.getContent());
});
}
@Test
public void searchShouldWhere(){
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.should(QueryBuilders.matchQuery("name","天龙"));
boolQueryBuilder.should(QueryBuilders.matchQuery("age",26));
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder);
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.forEach(personSearchHit -> {
System.out.println(personSearchHit.getContent());
});
}
@Test
public void searchRange(){
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").gte(26).lt(31);
boolQueryBuilder.filter(rangeQueryBuilder);
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder);
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.forEach(personSearchHit -> {
System.out.println(personSearchHit.getContent());
});
}
/**
* 聚合搜索
* 聚合搜索,aggs,类似于group by,对age字段进行聚合,
*/
@Test
public void aggregations() {
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withAggregations(AggregationBuilders.terms("count").field("sex"))
.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
//取出聚合结果
ElasticsearchAggregations elasticsearchAggregations = (ElasticsearchAggregations) searchHits.getAggregations();
Aggregations aggregations = elasticsearchAggregations.aggregations();
Terms terms = (Terms) aggregations.asMap().get("count");
for (Terms.Bucket bucket : terms.getBuckets()) {
String keyAsString = bucket.getKeyAsString(); // 聚合字段列的值
long docCount = bucket.getDocCount(); // 聚合字段对应的数量
System.out.println(keyAsString + " " + docCount);
}
}
/**
* 分页实现
*/
@Test
public void searchWithPageable(){
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
//分页实现
.withPageable(PageRequest.of(0,2));
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.getSearchHits().forEach(personSearchHit -> {
Person content = personSearchHit.getContent();
System.out.println(content);
});
}
/**
* 排序实现
*/
@Test
public void searchWithSort(){
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchAllQueryBuilder());
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
//分页实现
.withPageable(PageRequest.of(0,10))
//排序
.withSorts(SortBuilders.fieldSort("createTime").order(SortOrder.DESC),SortBuilders.fieldSort("age").order(SortOrder.DESC));
NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
SearchHits<Person> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Person.class);
searchHits.getSearchHits().forEach(personSearchHit -> {
Person content = personSearchHit.getContent();
System.out.println(content);
});
}
//高并发场景下模拟ES分布式悲观锁的实现
@Test
public void highConcurrencyWithPessimisticLock() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
AtomicInteger failedCount = new AtomicInteger(0);
/**
* 在testindex未创建的前提下,并发情况下,只能有一个成功,19个失败
*/
for (int i = 0; i < 20; i++) {
new Thread(new Task(countDownLatch,failedCount,elasticsearchRestTemplate)).start();
}
countDownLatch.countDown();
TimeUnit.SECONDS.sleep(10);
System.out.println(failedCount.get());
}
private class Task implements Runnable {
private CountDownLatch countDownLatch;
private AtomicInteger failedCount;
private ElasticsearchRestTemplate elasticsearchRestTemplate;
public Task(CountDownLatch countDownLatch,AtomicInteger failedCount,ElasticsearchRestTemplate elasticsearchRestTemplate){
this.countDownLatch = countDownLatch;
this.failedCount = failedCount;
this.elasticsearchRestTemplate = elasticsearchRestTemplate;
}
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
IndexCoordinates indexCoordinates = IndexCoordinates.of("testindex");
IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(indexCoordinates);
boolean created = indexOperations.create();
System.out.println(created);
} catch (Exception e) {
failedCount.getAndIncrement();
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)