大家好,我是老壇。?
本篇文章全部代碼資源請(qǐng)關(guān)注同名公眾號(hào):老壇聊開(kāi)發(fā)
回復(fù):"8.x模板" 即可獲取
Elasticsearch是一個(gè)分布式的RESTful 風(fēng)格的搜索和數(shù)據(jù)分析引擎,它使用方便,查詢速度快,因此也被越來(lái)越多的開(kāi)發(fā)人員使用。
在Java項(xiàng)目中,使用ES的場(chǎng)景也十分常見(jiàn)。除了作為某些特定資源的存儲(chǔ)之外也可以作為像ELK這樣的日志收集系統(tǒng)里的存儲(chǔ)引擎??傊?,對(duì)于非關(guān)系型而查找需求較多的場(chǎng)景,ES的表現(xiàn)還是非常不錯(cuò)的。
本篇文章介紹的是8.x版本的ES相關(guān)Java API操作,如果你使用的版本是7.x及其以下的話可以去看我的另一篇文章:
【ES使用】Java API操作ES寶典(7.x版本及其以下)https://blog.csdn.net/qq_34263207/article/details/127793370
目錄
1. 準(zhǔn)備工作
1.1 引入依賴
1.2 配置文件
2. ES操作
2.1 簡(jiǎn)單操作
2.1.1 插入數(shù)據(jù)
2.1.2 查詢數(shù)據(jù)
2.1.3 修改數(shù)據(jù)
2.1.4 刪除數(shù)據(jù)
2.2 復(fù)雜查詢
2.2.1 match查詢
2.2.2 term查詢
2.2.3 match_phrase查詢
2.2.4 multi_match查詢
2.2.5 fuzzy查詢
2.2.6?range查詢
2.2.7?bool查詢
2.3?排序和分頁(yè)
?3.代碼模板
4.總結(jié)
1. 準(zhǔn)備工作
在使用api之前,需要進(jìn)行一些準(zhǔn)備工作。這里我們要進(jìn)行依賴的引入與config配置文件的編寫。
1.1 引入依賴
從8.x開(kāi)始,spring boot data目前還是不支持的,需要所以沒(méi)有starter來(lái)給我們引入,這里需要引入的是兩個(gè)其它的依賴:
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.1.1</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.1</version>
</dependency>
8.1.1版本我用起來(lái)是沒(méi)有問(wèn)題的,8.0.1版本我用起來(lái)會(huì)報(bào)錯(cuò),目前也沒(méi)有查到原因,大家和我引入的版本保持一致即可。
這里我默認(rèn)大家使用的都是spring的環(huán)境,如果沒(méi)有引入spirng-web包的小伙伴請(qǐng)?jiān)僮孕幸雑ackson-core包!
關(guān)于不同版本的ES和Java API版本對(duì)應(yīng)關(guān)系大家可以查閱我的這篇文章:
【ES知識(shí)】es版本與java api版本對(duì)照一覽https://blog.csdn.net/qq_34263207/article/details/127790216
1.2 配置文件
我們先在yml里寫一下ES相關(guān)的配置信息,方便config使用:
es:
address: 127.0.0.1
port: 9200
scheme: http
username: admin
password: admin
然后寫一下config文件:
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ElasticSearchConfig {
@Value("${spring.es.address}")
String address;
@Value("${spring.es.port}")
Integer port;
@Value("${spring.es.scheme}")
String scheme;
@Value("${spring.es.username}")
String username;
@Value("${spring.es.password}")
String password;
@Bean
public ElasticsearchClient esRestClientWithCred(){
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
// 配置連接ES的用戶名和密碼,如果沒(méi)有用戶名和密碼可以不加這一行
credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost(address, port, scheme))
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
@Override
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
});
RestClient restClient = restClientBuilder.build();
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);
return client;
}
}
大家直接粘走使用即可,親測(cè)可用。
2. ES操作
我將ES操作定義為了簡(jiǎn)單操作和復(fù)雜操作兩部分。簡(jiǎn)單操作主要是圍繞ES的id去做增刪改查,而復(fù)雜操作是進(jìn)行復(fù)雜查詢時(shí)候所用到的。
2.1 簡(jiǎn)單操作
該部分主要是針對(duì)id去對(duì)ES做了增刪改查,而這里的API使用到的類也比較有特點(diǎn),我簡(jiǎn)單畫(huà)了一張圖方便大家理解:
可以看到,我們的所有操作都是基于ElasticsearchClient的,而該client定義在之前我們的config里面,要用到的時(shí)候注入過(guò)來(lái)就好了。對(duì)于增刪改查的每一種操作,都有相應(yīng)的request和response類來(lái)給我們使用,因?yàn)閷?duì)于ES的操作本質(zhì)上還是發(fā)送http請(qǐng)求。
更多優(yōu)質(zhì)文章資源請(qǐng)關(guān)注同名公眾號(hào):老壇聊開(kāi)發(fā)
?先介紹一下我用到的實(shí)體對(duì)象:
@Data
public class TextBook {
String bookName;
String author;
Integer num;
}
2.1.1 插入數(shù)據(jù)
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void insertSingle() throws IOException {
// 創(chuàng)建要插入的實(shí)體
TextBook textBook = new TextBook();
textBook.setBookName("老壇聊開(kāi)發(fā)");
textBook.setEdition("老壇");
textBook.setEditionTime("20221109");
// 方法一
IndexRequest<Object> indexRequest = new IndexRequest.Builder<>()
.index(index)
.document(textBook)
.build();
IndexResponse indexResponse1 = client.index(indexRequest);
}
}
相比于7.x版本的api,這里使用了builder的方式來(lái)創(chuàng)建request,但實(shí)際上結(jié)合java8的lambda表達(dá)式可以寫的更清爽:
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void insertSingle() throws IOException {
// 創(chuàng)建要插入的實(shí)體
TextBook textBook = new TextBook();
textBook.setBookName("老壇聊開(kāi)發(fā)");
textBook.setEdition("老壇");
textBook.setEditionTime("20221109");
// 方法二
IndexResponse indexResponse2 = client.index(b -> b
.index(index)
.document(textBook)
);
}
}
用這種方式我們甚至都不用管中間的一些類和過(guò)程,直接就可以從client出發(fā)完成整個(gè)流程拿到response,這也是我用了8.x的api后最為驚艷的地方,這里我也建議大家這樣去寫,非常簡(jiǎn)潔快速,后面的各種操作我也會(huì)用這種方式來(lái)書(shū)寫。
2.1.2 查詢數(shù)據(jù)
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepSingle(String id) throws IOException {
GetResponse<TextBook> response = client.get(g -> g
.index(index)
.id(id),
TextBook.class
);
if (response.found()) {
TextBook textBook = response.source();
log.info("返回結(jié)果 " + JSON.toJSONString(textBook));
} else {
log.info ("textBook not found");
}
}
}
這里我們使用GetResponse時(shí)要先指定一個(gè)泛型,就是我們要查詢的實(shí)體,同時(shí)該類型也作為參數(shù)傳入查詢方法中。
這里使用了GetResponse的found方法先確認(rèn)一下是否取到了數(shù)據(jù),取到了就可以進(jìn)行獲取。
2.1.3 修改數(shù)據(jù)
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void updateSingle(String id) throws IOException {
// 創(chuàng)建要更新的實(shí)體
TextBook textBook = new TextBook();
textBook.setBookName("老壇聊開(kāi)發(fā)");
textBook.setEdition("老壇");
textBook.setEditionTime("20221109");
UpdateResponse updateResponse = client.update(u -> u
.doc(textBook)
.id(id),
TextBook.class
);
}
}
2.1.4 刪除數(shù)據(jù)
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void deleteSingle(String id) throws IOException {
DeleteResponse deleteResponse = client.delete(d -> d
.index(index)
.id(id)
);
}
}
2.2 復(fù)雜查詢
下面介紹一下ES的復(fù)雜查詢,也是我們使用更多一些的查詢方式,這里面和ES的語(yǔ)法會(huì)結(jié)合的更緊密一些,強(qiáng)烈建議大家有一定的ES語(yǔ)法基礎(chǔ)之后再來(lái)閱讀。關(guān)于ES的基礎(chǔ)語(yǔ)法的學(xué)習(xí)大家可以看我的這篇文章:
【ES知識(shí)】ES基礎(chǔ)查詢語(yǔ)法一覽https://blog.csdn.net/qq_34263207/article/details/127849806
有了labmda表達(dá)式的簡(jiǎn)化加成,這部分相比于7.x的api清爽了相當(dāng)多,任何形式的查詢真的都是一行代碼搞定。
2.2.1 match查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> matchSearch = client.search(s -> s
.index(index)
.query(q -> q
.match(t -> t
.field("bookName")
.query("老壇")
)
),
TextBook.class);
for (Hit<TextBook> hit: matchSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的match查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query": {
"match": {
"bookName":"老壇"
}
}
}
大家還可以發(fā)現(xiàn)這種寫法的另一個(gè)好處就是寫起來(lái)更像是去寫原生的ES查詢命令了,隱藏了Java API復(fù)雜各種類和中間過(guò)程的使用。
2.2.2 term查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> termSearch = client.search(s -> s
.index(index)
.query(q -> q
.term(t -> t
.field("bookName")
.value("老壇")
)
),
TextBook.class);
for (Hit<TextBook> hit: termSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的term查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query": {
"term": {
"bookName":"老壇"
}
}
}
2.2.3 match_phrase查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> matchPhraseSearch = client.search(s -> s
.index(index)
.query(q -> q
.matchPhrase(m -> m
.field("bookName")
.query("老壇")
)
),
TextBook.class);
for (Hit<TextBook> hit: matchPhraseSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的match_phrase查詢,它等價(jià)的ES語(yǔ)法就是:
更多優(yōu)質(zhì)文章資源請(qǐng)關(guān)注同名公眾號(hào):老壇聊開(kāi)發(fā)
GET textbook/_search
{
"query": {
"match_phrase": {
"bookName":"老壇"
}
}
}
2.2.4 multi_match查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> multiMatchSearch = client.search(s -> s
.index(index)
.query(q -> q
.multiMatch(m -> m
.query("老壇")
.fields("author", "bookName")
)
),
TextBook.class);
for (Hit<TextBook> hit: multiMatchSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的multi_match查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query": {
"multi_match": {
"query": "老壇",
"fields": ["author","bookName"]
}
}
}
2.2.5 fuzzy查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> fuzzySearch = client.search(s -> s
.index(index)
.query(q -> q
.fuzzy(f -> f
.field("bookName")
.fuzziness("2")
.value("老壇")
)
),
TextBook.class);
for (Hit<TextBook> hit: fuzzySearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的fuzzy查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query": {
"fuzzy": {
"bookName":{
"value":"老壇",
"fuzziness":2
}
}
}
}
2.2.6?range查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> rangeSearch = client.search(s -> s
.index(index)
.query(q -> q
.range(r -> r
.field("bookName")
.gt(JsonData.of(20))
.lt(JsonData.of(20))
)
),
TextBook.class);
for (Hit<TextBook> hit: rangeSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的range查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query": {
"range": {
"num": {
"gt":20,
"lt":30
}
}
}
}
2.2.7?bool查詢
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> boolSearch = client.search(s -> s
.index(index)
.query(q -> q
.bool(b -> b
.must(m -> m
.term(t -> t
.field("author")
.value("老壇")
)
)
.should(sh -> sh
.match(t -> t
.field("bookName")
.query("老壇")
)
)
)
),
TextBook.class);
for (Hit<TextBook> hit: boolSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
?對(duì)應(yīng)了ES的bool查詢,它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query":{
"bool":{
"should":{
"match":{
"bookName":"老壇"
}
},
"must":{
"term":{
"author":"老壇"
}
}
}
}
}
2.3?排序和分頁(yè)
排序和分頁(yè)直接像ES的語(yǔ)法一樣,體現(xiàn)在和query的平級(jí)即可。這里已match為例進(jìn)行介紹。
@SpringBootTest
@Slf4j
public class ESTest {
@Resource
ElasticsearchClient client;
String index = "textbook";
@Test
public void grepTextBook() throws IOException {
SearchResponse<TextBook> matchSearch = client.search(s -> s
.index(index)
.query(q -> q
.match(t -> t
.field("bookName")
.query("老壇")
)
)
.from(1)
.size(100)
.sort(so -> so
.field(f -> f
.field("num")
.order(SortOrder.Desc)
)
),
TextBook.class);
for (Hit<TextBook> hit: matchSearch.hits().hits()) {
TextBook pd = hit.source();
System.out.println(pd);
}
}
}
這是一個(gè)根據(jù)num字段進(jìn)行降序排序的查詢,按頁(yè)容量為100對(duì)數(shù)據(jù)進(jìn)行分頁(yè),取第二頁(yè)數(shù)據(jù)。
它等價(jià)的ES語(yǔ)法就是:
GET textbook/_search
{
"query":{
"match":{
"bookName":"老壇"
}
},
"from":1,
"size":100,
"sort":{
"num":{
"order":"desc"
}
}
}
?3.代碼模板
本篇文章中介紹的全部es操作老壇已整理成模板項(xiàng)目了:
請(qǐng)關(guān)注同名公眾號(hào):老壇聊開(kāi)發(fā)
并回復(fù):"8.x模板" 獲取代碼模板
只要大家根據(jù)自己的實(shí)際環(huán)境修改配置即可直接跑起來(lái)啦,親測(cè)有效!
4.總結(jié)
到這里Java對(duì)ES的操作基本上聊的差不多了,題主這里介紹的未必詳盡,只是一些我們通常會(huì)用到的操作,如果還想詳細(xì)了解更多的內(nèi)容請(qǐng)閱讀官方文檔:
Javadoc and source code | Elasticsearch Java API Client [8.5] | Elastic文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-787554.html
另外,題主這里只是為了給大家講明白如何使用舉了幾個(gè)例子,并不一定效率最高或者使用常見(jiàn)最為恰當(dāng),還是需要大家學(xué)習(xí)一下ES的語(yǔ)法根據(jù)自己的實(shí)際業(yè)務(wù)場(chǎng)景去選用,謝謝大家~文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-787554.html
到了這里,關(guān)于【ES使用】Java API操作ES寶典(8.x版本)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!