官網(wǎng)操作文檔:Elasticsearch Clients | Elastic ?????
???????? 踩坑太多了。。。這里表明一下Spring Boot2.4以上版本可能會出現(xiàn)問題,所以我降到了2.2.1.RELEASE。對于現(xiàn)在2023年6月而言,Es版本已經(jīng)到了8.8,而SpringBoot版本已經(jīng)到了3.x版本。如果是高版本的Boot在配置類的時候會發(fā)現(xiàn)RestHighLevelClient已過時。從官網(wǎng)也可以看的出來RestHighLevelClient已過時。所以這篇博文中不會用到關(guān)于RestHighLevelClient的Api。
??????? 此篇博文的對應(yīng)版本關(guān)系:Elasticsearch 8.2.0 + Spring Boot 2.7.5。在進(jìn)入到下面的案例,我需要在這之前先介紹RestClient、RestHighLevelClient、RestClientTransport、ElasticsearchClient。
RestClient
??????? 這個類主要是用作于與服務(wù)端IP以及端口的配置,在其的builder()方法可以設(shè)置登陸權(quán)限的賬號密碼、連接時長等等??偠灾褪?strong>服務(wù)端配置。
RestClientTransport
??????? 這是Jackson映射器創(chuàng)建傳輸。建立客戶端與服務(wù)端之間的連接傳輸數(shù)據(jù)。這是在創(chuàng)建ElasticsearchClient需要的參數(shù),而創(chuàng)建RestClientTransport就需要上面創(chuàng)建的RestClient。
ElasticsearchClient
??????? 這個就是Elasticsearch的客戶端。調(diào)用Elasticsearch語法所用到的類,其就需要傳入上面介紹的RestClientTransport。
引入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<!-- 高版本還需引入此依賴 -->
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.0</version>
</dependency>
修改yml
??????? 需要注意的是賬號和密碼可以不需要,看自己的Elasticsearch是否有配置賬號密碼。具體對Elasticsearch的登陸操作可以看:中偏下的位置就是對賬號密碼的設(shè)置。【Linux】Docker部署鏡像環(huán)境 (持續(xù)更新ing)_小白的救贖的博客-CSDN博客
server:
port: 8080
elasticsearch:
hostAndPort: 192.168.217.128:9200 # 低版本使用的
ip: 192.168.217.128
port: 9200
username: elastic
password: 123456
connectionTimeout: 1000
socketTimeout: 30000
配置類 ???
????????這里演示兩種情況的配置:第一個代碼塊是SpringBoot2.4以下 + 7.x版本Elasticsearch的配置。第二個代碼塊是Spring2.4以上 + 8.x版本Elasticsearch的配置。
@Configuration
public class ElasticConfig extends AbstractElasticsearchConfiguration {
@Value("${elasticsearch.hostAndPort}")
private String hostAndPort;
@Value("${elasticsearch.username}")
private String username;
@Value("${elasticsearch.password}")
private String password;
@Value("${elasticsearch.connectionTimeout}")
private String connectTimeout;
@Value("${elasticsearch.socketTimeout}")
private String socketTimeout;
/**
* create Elasticsearch client
* @return RestHighLevelClient
*/
@Bean
public RestHighLevelClient elasticsearchClient() {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(hostAndPort)
.withConnectTimeout(Long.parseLong(connectTimeout))
.withSocketTimeout(Long.parseLong(socketTimeout))
.withBasicAuth(username, password)
.build();
return RestClients.create(clientConfiguration).rest();
}
/**
* 將連接傳入 Elasticsearch在 Spring Boot的模板類中
* @return 返回 Es的模板類
*/
@Bean
public ElasticsearchRestTemplate elasticsearchRestTemplate() {
return new ElasticsearchRestTemplate(elasticsearchClient());
}
}
@Configuration
public class ElasticConfig {
@Value("${elasticsearch.ip}")
private String ip;
@Value("${elasticsearch.port}")
private String port;
@Value("${elasticsearch.username}")
private String username;
@Value("${elasticsearch.password}")
private String password;
@Value("${elasticsearch.connectionTimeout}")
private String connectTimeout;
@Value("${elasticsearch.socketTimeout}")
private String socketTimeout;
/**
* create Elasticsearch client
* @return RestHighLevelClient
*/
@Bean
public ElasticsearchClient elasticsearchClient() {
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(username, password));
RestClient restClient = RestClient.builder(
new HttpHost(ip, Integer.parseInt(port)))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider))
.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder builder) {
return builder.setConnectTimeout(Integer.parseInt(connectTimeout)).setSocketTimeout(Integer.parseInt(socketTimeout));
}
}).build();
ElasticsearchTransport transport
= new RestClientTransport(restClient, new JacksonJsonpMapper());
return new ElasticsearchClient(transport);
}
}
控制層
??????? 這里為了方便快速入門,就把所有業(yè)務(wù)代碼都放在控制層中了。這篇博文主要是對索引進(jìn)行操作,所以說獲取到ElasticsearchClient后會調(diào)用indices()方法,這個方法就是操作索引的方法。次代碼塊是展示變量以及類注解。后面逐一暫時各個測試代碼塊Api以及返回結(jié)果。
@RestController
@RequestMapping("/es")
@Slf4j
public class EsController{
@Autowired
private ElasticConfig elasticConfig;
}
創(chuàng)建索引
/**
* create index
* @return is success?
*/
@PutMapping("/createIndex")
public boolean createIndex() throws IOException {
CreateIndexRequest indexRequest
= new CreateIndexRequest.Builder().index("user").build();
CreateIndexResponse indexResponse
= elasticConfig.esClient().indices().create(indexRequest);
boolean isSuccess = indexResponse.acknowledged();
if(isSuccess) {
log.info("創(chuàng)建索引成功");
} else {
log.info("創(chuàng)建索引失敗");
}
return isSuccess;
}
查詢單個索引數(shù)據(jù)
/**
* get one index data by id
*/
@GetMapping("/getIndex")
public void getIndex() throws IOException {
GetResponse<User> response = elasticConfig.esClient().get(g -> g
.index("user")
.id("1000")
,User.class
);
if(response.found()) {
log.info("此用戶的姓名為,{}",response.source().getUsername());
} else {
log.info("未查詢到此用戶");
}
}
刪除索引
??????? 這里我測試刪除索引成功后又把索引添加了回去。為了后面的其它操作做準(zhǔn)備。
/**
* delete one index
*/
@DeleteMapping("/deleteIndex")
public boolean deleteIndex() throws IOException {
DeleteIndexRequest indexRequest
= new DeleteIndexRequest.Builder().index("user").build();
DeleteIndexResponse deleteResponse
= elasticConfig.esClient().indices().delete(indexRequest);
boolean isSuccess = deleteResponse.acknowledged();
if(isSuccess) {
log.info("刪除索引成功");
} else {
log.info("刪除索引失敗");
}
return isSuccess;
}
增加索引內(nèi)容
??????? 這里我新增了個實體類,方便添加到索引內(nèi)容中。這里大概有四種方式可以創(chuàng)建,這里我演示了三種方式,第四種是使用到了ElasticsearchAsyncClient ,這是Elastic異步客戶端。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private String sex;
private Integer age;
}
/**
* 向索引內(nèi)容插入數(shù)據(jù)
*/
@PostMapping("/insertIndexData")
public void insertIndexData() throws IOException {
User user = new User("zhangSan","男",18);
/*
第一種方式:使用DSL語法創(chuàng)建對象
IndexRequest<User> indexRequest = IndexRequest.of(i -> i
.index("user")
.id("1000")
.document(user)
IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
);
*/
/*
第二種方式:使用Elasticsearch客戶端上配置的對象映射器映射到JSON。
IndexResponse indexResponse = elasticConfig.esClient().index(i -> i
.index("user")
.id("1000")
.document(user)
);
*/
// 第三種方式:使用構(gòu)造器模式
IndexRequest.Builder<User> indexRequest = new IndexRequest.Builder<>();
indexRequest.index("user");
indexRequest.id("1000");
indexRequest.document(user);
IndexResponse indexResponse = elasticConfig.esClient().index(indexRequest.build());
log.info("index,{}",indexResponse.index());
log.info("id,{}",indexResponse.id());
log.info("version,{}",indexResponse.version());
}
批量添加索引數(shù)據(jù)
????????BulkRequest包含一組操作,每個操作都是具有多個變體的類型。為了創(chuàng)建這個請求,可以方便地將構(gòu)建器對象用于主請求,并將流利的DSL用于每個操作。下面的示例顯示了如何為列表或應(yīng)用程序?qū)ο缶幹扑饕?/p>
??????? operations是BulkOperation的生成器,BulkOperation是一種變體類型。此類型具有索引、創(chuàng)建、更新和刪除變體。
/**
* 批量插入索引數(shù)據(jù)
*/
@PostMapping("/batchInsertIndex")
public void batchInsertIndex() throws IOException {
// 將需要批量添加的數(shù)據(jù)放到List中
List<User> list = new ArrayList<>();
list.add(new User("liSi","女",20));
list.add(new User("wangWu","男",22));
// 使用BulkRequest的構(gòu)造器
BulkRequest.Builder request = new BulkRequest.Builder();
for(User user : list) {
request.operations(l -> l
.index(i -> i
.index("user")
.document(user)
)
);
}
BulkResponse response = elasticConfig.esClient().bulk(request.build());
if(response.errors()) {
log.info("批量插入報錯");
} else {
log.info("批量插入成功");
}
}
批量刪除索引數(shù)據(jù)
/**
* 批量刪除索引數(shù)據(jù)
*/
@DeleteMapping("/batchDeleteIndex")
public void batchDeleteIndex() throws IOException {
BulkRequest.Builder request = new BulkRequest.Builder();
// 根據(jù)id做到刪除索引的數(shù)據(jù)
request.operations(l -> l
.delete(i -> i
.index("user")
.id("vGK5sogBM87kk5Mw8V0P")
)
);
request.operations(l -> l
.delete(i -> i
.index("user")
.id("u2K5sogBM87kk5Mw8V0P")
)
);
BulkResponse response = elasticConfig.esClient().bulk(request.build());
if(response.errors()) {
log.info("批量刪除報錯");
} else {
log.info("批量刪除成功");
}
}
????????? 這里批量刪除接口測試完后,我又批量添加了幾行數(shù)據(jù),方便下面方法的測試。
// 以下就是我添加的數(shù)據(jù)
list.add(new User("liSi","女",20));
list.add(new User("wangWu","男",22));
list.add(new User("zhaoLiu","男",20));
list.add(new User("xiaoQi","女",21));
簡單查詢/單條件
????????可以組合多種類型的搜索查詢。我們將從簡單的文本匹配查詢開始。單條件準(zhǔn)確查詢主要用到的關(guān)鍵字是term。而模糊查詢就需要用到match。而match這里就不演示了。
/**
* 單條件查詢
*/
@GetMapping("/search")
public void search() throws IOException {
SearchResponse<User> response = elasticConfig.esClient().search(s -> s
.index("user")
.query(q -> q
.term(e -> e
.field("age")
.value("20")
)
), User.class
);
// 獲取查詢后的命中條數(shù):其中包括 TotalHitsRelation 以及 total
TotalHits total = response.hits().total();
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
if (isExactResult) {
log.info("There are " + total.value() + " results");
} else {
log.info("There are more than " + total.value() + " results");
}
// 解析查詢到的所有信息
List<Hit<User>> hits = response.hits().hits();
for(Hit<User> hit : hits) {
log.info("id,{}", hit.id());
}
}
多條件查詢 / 范圍查詢
????????Elasticsearch允許將單個查詢組合起來,以構(gòu)建更復(fù)雜的搜索請求。當(dāng)前數(shù)據(jù)有五條,為了更好的多條件查詢,我又增加了5條數(shù)據(jù)。多條件查詢用到的關(guān)鍵字主要就是bool。
// 起初的5條數(shù)據(jù)
list.add(new User("zhangSan","男",18));
list.add(new User("liSi","女",20));
list.add(new User("wangWu","男",22));
list.add(new User("zhaoLiu","男",20));
list.add(new User("xiaoQi","女",21));
// 以下就是我添加的數(shù)據(jù)
list.add(new User("zhangSan","男",20));
list.add(new User("zhangSan","男",21));
list.add(new User("zhangSan","男",22));
list.add(new User("zhangSan","男",23));
list.add(new User("zhangSan","男",24));
/**
* 多條件查詢
*/
@GetMapping("/batchSearch")
public void batchSearch() throws IOException {
// 查詢性別
Query sex = MatchQuery.of(m -> m
.field("sex")
.query("男")
)._toQuery();
// 查詢年齡區(qū)間
Query age = RangeQuery.of(r -> r
.field("age")
.lte(JsonData.of(20))
.gte(JsonData.of(18))
)._toQuery();
// 結(jié)合性別和年齡區(qū)間查詢來搜索用戶索引
SearchResponse<User> response = elasticConfig.esClient().search(s -> s
.index("user")
.query(q -> q
.bool(b -> b
.must(sex)
.must(age)
)
),User.class
);
// 獲取查詢后的命中條數(shù):其中包括 TotalHitsRelation 以及 total
TotalHits total = response.hits().total();
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
if (isExactResult) {
log.info("There are " + total.value() + " results");
} else {
log.info("There are more than " + total.value() + " results");
}
// 解析查詢到的所有信息
List<Hit<User>> hits = response.hits().hits();
for(Hit<User> hit : hits) {
log.info("id,{}", hit.id());
}
}
分頁查詢
??????? 主要就是Elasticsearch語法中的from與size表示:當(dāng)前頁的開始索引處以及每頁條數(shù)。
/**
* 分頁查詢
*/
@GetMapping("/searchByPage")
public void searchByPage() throws IOException {
// 假設(shè)每頁3條數(shù)據(jù) 那么查詢第二頁的參數(shù)就是:開始索引處為(2 - 1) * 3 = 3 以及 每頁條數(shù)3
SearchResponse<User> response = elasticConfig.esClient().search(b -> b
.index("user")
.from(3)
.size(3)
,User.class
);
log.info("查詢到的總條數(shù)為,{}",response.hits().total().value());
List<Hit<User>> hits = response.hits().hits();
for(Hit<User> hit : hits) {
log.info("查詢到的id,{}", hit.id());
}
}
文章來源:http://www.zghlxwxcb.cn/news/detail-493899.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-493899.html
查詢所有索引數(shù)據(jù)
/**
* get all index data
*/
@GetMapping("/getAllIndex")
public void getAllIndex() throws IOException {
SearchResponse<User> response = elasticConfig.esClient().search(s -> s
.index("user")
,User.class);
// 解析查詢到的所有信息
List<Hit<User>> hits = response.hits().hits();
for(Hit<User> hit : hits) {
log.info(String.valueOf(hit.source()));
}
}
到了這里,關(guān)于【SpringBoot】整合Elasticsearch 操作索引及文檔的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!