建议
建议直接阅读我的博客原文
10.4 Java API Client
操作-索引库/文档
客户端更新
ES为不同语言提供了用于操作ES的客户端,截至2023年7月4日,根据官网Java REST Client
已经被弃用,取而代之的是Java API Client
,黑马的教程里都是环境是es7.12.1
和RestClient
,版本太旧了,我的笔记用es 8.8.1
和Java API Client
,但也会提供部分旧版本代码。ES官网也提供了兼容性支持,restclient7.17
版本仍然可以操作es8.x
版本。
API Client更新说明
为什么要抛弃High Level Rest:
-
客户端"too heavy",相关依赖超过 30 MB,且很多都是非必要相关的;api 暴露了很多服务器内部接口
-
一致性差,仍需要大量的维护工作。
-
客户端没有集成 json/object 类型映射,仍需要自己借助字节缓存区实现。
Java API Client最明显的特征:
- 支持lambda表达式操作ES
- 支持Builder建造者模式操作ES,链式代码具有较强可读性.
- 应用程序类能够自动映射为Mapping.
可以浅浅感受下两者不同:
RestHighLevelClient:
导入本地项目
1.服务器mysql容器导入数据
# 本地sql文件上传到服务器
scp D:\...\tb_hotel.sql root@my_ip:/root/tmp
# 复制文件到容器内
docker cp tmp/tb_hotel.sql mysql:/tmp/tb_hotel.sql
# 进入容器
docker exec -it mysql bash
mysql -u root -p
# 容器内执行sql
use my_db;
source /tmp/tb_hotel.sql
# 删除临时文件
docker exec -it mysql rm /tmp/tb_hotel.sql
2.导入hotel-demo
数据结构分析
- 需要分词:type=text,并设置分词器
- 不需要索引:index=false
- 特殊数据类型:geo_point表示具体经纬度,geo_shape表示经纬范围,如1所示
- 优化搜索,如2所示⭐
- 多条件索引的效率低于单条件索引
- "copy_to"属性可将当前字段copy到指定字段
- 创建条件"all",将多条件索引的条件都"copy_to"新条件"all",达成单条件索引
初始化JavaClient
1.导入es的Client依赖,这里要注意jackson-core
版本,原因看这篇
<!--旧版本HLRC依赖-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<!--es7.17可以操作es8.x-->
<version>7.17.4</version>
</dependency>
<!--新版本Java API Client依赖-->
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>8.8.1</version>
</dependency>
<!--java api client需要有json对象映射库,springboot-web自带jackson-databind依赖,可以不引入-->
<!--
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.7.1</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
</exclusions>
</dependency>
-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.0</version>
</dependency>
<!--如果报错找不到jakarta还需要引入如下依赖-->
<dependency>
<groupId>jakarta.json</groupId>
<artifactId>jakarta.json-api</artifactId>
<version>2.0.1</version>
</dependency>
2.覆盖ES默认版本(Spring Boot默认ES版本7.6.2)
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>8.8.1</elasticsearch.version>
</properties>
3.初始化Client
//旧版本RestHighLevelClient
@Bean
public RestHighLevelClient restHighLevelClient(){
return new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://xx.xx.xx.xx:9200")
));
}
//新版本Java API Client
//新版版还支持创建安全连接,使用SSLContext
@Bean
public ElasticsearchClient elasticsearchClient(){
//创建低级客户端,负责所有传输级问题:连接池、重试、节点发现等
RestClient restClient = RestClient.builder(
new HttpHost(IP,9200)).build();
//使用Jackson映射器创建传输层,方便ES与应用程序类集成
ElasticsearchTransport transport = new RestClientTransport(
restClient,new JacksonJsonpMapper());
//创建API 客户端
//阻塞
return new ElasticsearchClient(transport);
//异步非阻塞
//return new ElasticsearchAsyncClient(transport);
}
索引库
创建索引测试
@SpringBootTest
class HotelIndexTest {
// private RestHighLevelClient client;
private RestClient restClient;
private ElasticsearchTransport transport;
private ElasticsearchClient client;
@Test
void testCreateIndex() throws IOException {
//准备Request,并指定index name和请求参数
CreateIndexRequest request = CreateIndexRequest.of(builder ->
builder.index("hotel")
.withJson(new StringReader(MAPPING_TEMPLATE))
);
//发送请求
client.indices().create(request);
}
//官方还提供了其他方法创建mappings
//mappings是字符串
@Test
void testCreateIndex1() throws IOException {
JsonpMapper jsonpMapper = client._transport().jsonpMapper();
//这里的MAPPING_TEST字符串只需要包含{"properties":{}}内容
JsonParser parser = Json.createParser(new StringReader(MAPPING_TEST));
client.indices().create(
new CreateIndexRequest.Builder()
.index("hotel")
.mappings(TypeMapping._DESERIALIZER.deserialize(parser,jsonpMapper))
.build()
);
}
//mappings是json文件
@Test
public void testCreateIndex2(){
String mappingPath = System.getProperty("user.dir") + "/mappings.json";
JsonpMapper mapper = client._transport().jsonpMapper();
String mappings_str = new String(Files.readAllBytes(Paths.get(mappingPath)));
System.out.println("mappings are: " + mappings_str);
JsonParser parser = mapper.jsonProvider()
.createParser(new StringReader( mappings_str ));
client.indices()
.create(createIndexRequest -> createIndexRequest.index("test")
.mappings(TypeMapping._DESERIALIZER.deserialize(parser, mapper)));
}
@BeforeEach
void setUp() {
restClient = RestClient.builder(new HttpHost(IP,9200)).build();
transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
client = new ElasticsearchClient(transport);
}
@AfterEach
void tearDown() throws IOException {
//关闭连接
restClient.close();
transport.close();
}
}
API Client使用client.indices()
操作索引.
判断索引是否存在
@Test
void testExistsIndex() throws IOException {
BooleanResponse isExists = client.indices().exists(
new ExistsRequest.Builder()
.index("hotel")
.build()
);
System.out.println(isExists.value()?"exist":"not exist");
}
其实代码是什么不重要,完全可以按提示写,例如删除index:
提供了两种方式,上面判断是否存在用的是第二种,也就是XXIndexRequest的方式,删除可以试下第一种:
改写成lambda表达式:
文档
API Client使用client.xx()
操作文档.
了解规则之后,根据代码提示直接写,不需要手动转换格式,极度舒适~
bulk批量请求⭐
这个有点难猜,卡了一下
实在不行可以使用最原始的withJson()
方法,把批量数据放在json中读取后作为请求参数传上去.但是不够优雅…