Elasticsearch8.8.0 全网最新版教程 从入门到精通 通俗易懂
配置项目
引入依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</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>
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.8.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.1</version>
</dependency>
添加配置文件
application.yaml
spring:
elasticsearch:
rest:
scheme: https
host: localhost
port: 9200
username: elastic
password: 123456
crt: classpath:ca.crt
导入ca证书到项目中
从任意一个es容器中,拷贝证书到resources目录下
/usr/share/elasticsearch/config/certs/ca
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EXytUrDp-1691330960034)(media/16912196423122/16912204609393.jpg)]
添加配置
package com.lglbc.elasticsearch;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportUtils;
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.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;
import javax.net.ssl.SSLContext;
import java.io.IOException;
/**
* @Description TODO
* @Author 关注公众号 “乐哥聊编程” 领取资料和源码
* @Date 2023/07/14 21:04
*/
@Configuration
public class ElasticConfig {
@Value("${spring.elasticsearch.rest.scheme}")
private String scheme;
@Value("${spring.elasticsearch.rest.host}")
private String host;
@Value("${spring.elasticsearch.rest.port}")
private int port;
@Value("${spring.elasticsearch.rest.crt}")
private String crt;
@Value("${spring.elasticsearch.rest.username}")
private String username;
@Value("${spring.elasticsearch.rest.password}")
private String password;
@Autowired
private ResourceLoader resourceLoader;
@Bean
public ElasticsearchClient elasticsearchClient() throws IOException {
SSLContext sslContext = TransportUtils
.sslContextFromHttpCaCrt(resourceLoader.getResource(crt).getFile());
BasicCredentialsProvider credsProv = new BasicCredentialsProvider();
credsProv.setCredentials(
AuthScope.ANY, new UsernamePasswordCredentials(username, password)
);
RestClient restClient = RestClient
.builder(new HttpHost(host, port, scheme))
.setHttpClientConfigCallback(hc -> hc
.setSSLContext(sslContext)
.setDefaultCredentialsProvider(credsProv)
)
.build();
// Create the transport and the API client
ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);
return client;
}
}
实战操作
创建mapping
@Test
public void testCreateMapping() throws IOException {
PutMappingRequest mappingRequest = new PutMappingRequest.Builder().index("lglbc_java_demo")
.properties("order_no", builder ->
builder.keyword(type -> type)
).properties("order_time", builder ->
builder.date(type -> type.format("yyyy-MM-dd HH:mm:ss"))
).properties("good_info", type -> type.nested(
nested -> nested
.properties("good_price", builder ->
builder.double_(subType -> subType))
.properties("good_count", builder ->
builder.integer(subType -> subType))
.properties("good_name", builder ->
builder.text(subType ->
subType.fields("keyword", subTypeField -> subTypeField.keyword(subSubType -> subSubType)))
))
).properties("buyer", builder ->
builder.keyword(type -> type)
).properties("phone", builder ->
builder.keyword(type -> type)
)
.build();
ElasticsearchIndicesClient indices = elasticsearchClient.indices();
if (indices.exists(request -> request.index("lglbc_java_demo")).value()) {
indices.delete(request -> request.index("lglbc_java_demo"));
}
indices.create(request -> request.index("lglbc_java_demo"));
indices.putMapping(mappingRequest);
}
创建文档
@Test
public void testAddData() throws IOException {
OrderInfo orderInfo = new OrderInfo("1001", new Date(), "李白", "13098762567");
List<OrderInfo.GoodInfo> goodInfos = new ArrayList<>();
goodInfos.add(new OrderInfo.GoodInfo("苹果笔记本", 30.5d, 30));
goodInfos.add(new OrderInfo.GoodInfo("苹果手机", 20.5d, 10));
orderInfo.setGoodInfo(goodInfos);
IndexRequest<OrderInfo> request = IndexRequest.of(i -> i
.index("lglbc_java_demo")
.id(orderInfo.getOrderNo())
.document(orderInfo)
);
OrderInfo orderInfo2 = new OrderInfo("1002", new Date(), "苏轼", "13098762367");
List<OrderInfo.GoodInfo> goodInfos2 = new ArrayList<>();
goodInfos2.add(new OrderInfo.GoodInfo("华为笔记本", 18.5d, 15));
goodInfos2.add(new OrderInfo.GoodInfo("苹果手机", 20.5d, 10));
orderInfo2.setGoodInfo(goodInfos2);
IndexRequest<OrderInfo> request2 = IndexRequest.of(i -> i
.index("lglbc_java_demo")
.id(orderInfo2.getOrderNo())
.document(orderInfo2)
);
elasticsearchClient.index(request);
elasticsearchClient.index(request2);
}
查询更新
@Test
public void testUpdateDataByQuery() throws IOException {
UpdateByQueryRequest request = UpdateByQueryRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query.term(term -> term.field("order_no").value("1001")))
.script(script -> script.inline(inline -> inline.lang("painless").source("ctx._source['buyer'] = 'java 更新->乐哥聊编程'")))
);
elasticsearchClient.updateByQuery(request);
}
全量更新
@Test
public void testUpdateData() throws IOException {
OrderInfo orderInfo3 = new OrderInfo("1002", new Date(), "苏轼3", "13098762367");
List<OrderInfo.GoodInfo> goodInfos3 = new ArrayList<>();
goodInfos3.add(new OrderInfo.GoodInfo("华为笔记本", 18.5d, 15));
goodInfos3.add(new OrderInfo.GoodInfo("苹果手机", 20.5d, 10));
orderInfo3.setGoodInfo(goodInfos3);
UpdateRequest request = UpdateRequest.of(i -> i
.index("lglbc_java_demo")
.id(orderInfo3.getOrderNo())
.doc(orderInfo3)
);
elasticsearchClient.update(request, OrderInfo.class);
}
删除数据
@Test
public void testDelete() throws IOException {
DeleteRequest request = DeleteRequest.of(i -> i
.index("lglbc_java_demo")
.id("1002")
);
elasticsearchClient.delete(request);
}
批量操作(bulk)
@Test
public void testBulkOperation() throws IOException {
testCreateMapping();
BulkRequest.Builder br = new BulkRequest.Builder();
List<OrderInfo> orders = getOrders();
for (OrderInfo orderInfo : orders) {
br.operations(op -> op
.index(idx -> idx
.index("lglbc_java_demo")
.document(orderInfo)
)
);
}
elasticsearchClient.bulk(br.build());
}
基本搜索
@Test
public void testBaseSearch() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query.term(
term -> term.field("order_no").value("1001")
)));
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
List<OrderInfo> orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(JSONUtil.toJsonStr(orderInfos));
}
复杂布尔搜索
@Test
public void testBoolSearch() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query.bool(bool -> bool
.filter(filterQuery -> filterQuery.term(term -> term.field("buyer").value("李白")))
.must(must -> must.term(term -> term.field("order_no").value("1004"))))));
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
List<OrderInfo> orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(JSONUtil.toJsonStr(orderInfos));
}
嵌套(nested)搜索
@Test
public void testNestedSearch() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query.nested(nested -> nested
.path("good_info")
.query(nestedQuery -> nestedQuery.bool(
bool -> bool
.must(must -> must.range(range -> range.field("good_info.good_count").gte(JsonData.of("16"))))
.must(must2 -> must2.range(range -> range.field("good_info.good_price").gte(JsonData.of("30"))))
)
)
)));
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
List<OrderInfo> orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(JSONUtil.toJsonStr(orderInfos));
}
分页查询
@Test
public void testBasePageSearch() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.from(0)
.size(2).query(query -> query.matchAll(matchAll -> matchAll)));
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
List<OrderInfo> orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(orderInfos.size());
request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.from(2)
.size(2).query(query -> query.matchAll(matchAll -> matchAll)));
response = elasticsearchClient.search(request, OrderInfo.class);
hits = response.hits().hits();
orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(orderInfos.size());
request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.from(4)
.size(2).query(query -> query.matchAll(matchAll -> matchAll)));
response = elasticsearchClient.search(request, OrderInfo.class);
hits = response.hits().hits();
orderInfos = new ArrayList<>();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
System.out.println(orderInfos.size());
}
滚动分页查询
@Test
public void testScrollPageSearch() throws IOException {
String scrollId = null;
while (true) {
List<OrderInfo> orderInfos = new ArrayList<>();
if (StringUtils.isBlank(scrollId)) {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.scroll(Time.of(time -> time.time("1m")))
.size(2)
.query(query -> query.matchAll(matchAll -> matchAll)));
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
scrollId = response.scrollId();
} else {
String finalScrollId = scrollId;
ScrollRequest request = ScrollRequest.of(i -> i
.scroll(Time.of(time -> time.time("1m")))
.scrollId(finalScrollId));
ScrollResponse response = elasticsearchClient.scroll(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
}
scrollId = response.scrollId();
}
if (CollectionUtil.isEmpty(orderInfos)) {
break;
}
System.out.println(orderInfos.size());
}
}
After分页查询
@Test
public void testAfterPageSearch() throws IOException {
final List<FieldValue>[] sortValue = new List[]{new ArrayList<>()};
while (true) {
List<OrderInfo> orderInfos = new ArrayList<>();
SearchRequest request = SearchRequest.of(i -> {
SearchRequest.Builder sort1 = i
.index("lglbc_java_demo")
.size(2)
.sort(Lists.list(
SortOptions.of(sort -> sort.field(field -> field.field("order_no").order(SortOrder.Desc))))
);
if (CollectionUtil.isNotEmpty(sortValue[0])) {
sort1.searchAfter(sortValue[0]);
}
return sort1
.query(query -> query.matchAll(matchAll -> matchAll));
});
SearchResponse<OrderInfo> response = elasticsearchClient.search(request, OrderInfo.class);
List<Hit<OrderInfo>> hits = response.hits().hits();
for (Hit hit : hits) {
orderInfos.add((OrderInfo) hit.source());
sortValue[0] = hit.sort();
}
if (CollectionUtil.isEmpty(orderInfos)) {
break;
}
System.out.println(orderInfos.size());
}
}
词条(terms)聚合
@Test
public void testTermsAgg() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query
.matchAll(match->match))
.aggregations("agg_term_buyer",agg->agg
.dateHistogram(dateHistogram->dateHistogram
.field("order_time")
.calendarInterval(CalendarInterval.Day))));
SearchResponse<Void> search = elasticsearchClient.search(request, Void.class);
Map<String, Aggregate> aggregations = search.aggregations();
Aggregate aggregate = aggregations.get("agg_term_buyer")
;
Buckets<StringTermsBucket> buckets = ((StringTermsAggregate) aggregate._get()).buckets();
for (StringTermsBucket bucket : buckets.array()) {
String key = bucket.key()._toJsonString();
long l = bucket.docCount();
System.out.println(key+":::"+l);
}
}
日期聚合
@Test
public void testDateAgg() throws IOException {
SearchRequest request = SearchRequest.of(i -> i
.index("lglbc_java_demo")
.query(query -> query
.matchAll(match->match))
.aggregations("agg_date_buyer",agg->agg
.dateHistogram(dateHistogram->dateHistogram
.field("order_time")
.calendarInterval(CalendarInterval.Day))));
SearchResponse<Void> search = elasticsearchClient.search(request, Void.class);
Map<String, Aggregate> aggregations = search.aggregations();
Aggregate aggregate = aggregations.get("agg_date_buyer");
List<DateHistogramBucket> buckets = ((DateHistogramAggregate) aggregate._get()).buckets().array();
System.out.println(aggregate);
for (DateHistogramBucket bucket : buckets) {
String key = bucket.keyAsString();
long l = bucket.docCount();
System.out.println(key+":::"+l);
}
}