前面的文章具体介绍了是索引库及文档的一些基本操作指令, 指令还是挺简单的; 那么实际应用场景下, 我们是如何操作 ElasticSearch 的呢?
其实 ElasticSearch 官方已经为我们提供了各种不同语言的客户端, 目的就是为了来操作 ElasticSearch, 这些客户端的本质就是组装 DSL 语句, 通过 http 请求发送给 ElasticSearch, ➽官方文档地址.
RestClient
❶ RestClient 的初始化操作
本文数据将借用某站的酒店数据库数据, 主要学习 RestClient 的含义及如何使用.
1.1 Mapping 映射分析
关于索引库前面的博客已经说过最关键的是 mapping 映射, 因为 mapping 里面就是索引库的结构, 字段及子字段都在 properties 中, 主要注意下面几点:
- 字段名和字段数据类型可以参照数据库表中的表结构名称和类型;
- 根据业务来分析是否要参与搜索, 如图片地址就不需要参与搜索;
- 根据内容来判断是否需要分词, 如果内容就是一个整体则无需分词;
- 分词器根据业务来选择 ik_max_word 或者 ik_smart.
1.2 初始化 RestClient
关于 RestClient 的初始化主要分为三步, 首先要做的是对 RestHighLevelClient 类的初始化, 建立与 ElasticSearch 的连接 (因为与 ElasticSearch 的一切交互都封装到了这个类中).
⅓: 引入 RestHighLevelClient 依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.7</version>
</dependency>
⅔: 检查自己的 SpringBoot 默认的 ElasticSearch 版本是哪个, 如果不是 7.17.7, 就要改成 7.17.7
1: 初始化 RestHighLevelClient
@Bean
public RestHighLevelClient client() {
return new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://172.16.**.**:9200")
));
}
1.3 创建索引库
针对索引库的操作在测试类中使用; 关于索引库的创建也是分为三步:
Ⅰ: 创建 Request 对象, CreateIndexRequest create = new CreateIndexRequest(“hotel”);
Ⅱ: 添加请求参数, 这里的参数就是 DSL 中 JSON 参数部分, 因为字符串比较长, 可以定义一个静态字符串常量;
Ⅲ: 发送请求, client.indices() 方法的返回值是 IndicesClient 类型, 封装了所有与索引库操作有关的方法.
@Test
void createHotelIndex() throws IOException {
CreateIndexRequest request = new CreateIndexRequest("hotel");
request.source(MAPPING_TEMPLATE, XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
}
// 静态字符串常量 MAPPING_TEMPLATE
public static final String MAPPING_TEMPLATE = "{\n" +
" \"mappings\": {\n" +
" \"properties\": {\n" +
" \"id\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"name\": {\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" },\n" +
" \"address\": {\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \"price\": {\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"score\": {\n" +
" \"type\": \"integer\"\n" +
" },\n" +
" \"brand\": {\n" +
" \"type\": \"keyword\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \"city\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"starName\": {\n" +
" \"type\": \"keyword\"\n" +
" },\n" +
" \"business\": {\n" +
" \"type\": \"keyword\",\n" +
" \"copy_to\": \"all\"\n" +
" },\n" +
" \"location\": {\n" +
" \"type\": \"geo_point\"\n" +
" },\n" +
" \"pic\": {\n" +
" \"type\": \"keyword\",\n" +
" \"index\": false\n" +
" },\n" +
" \"all\": {\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
}
1.4 删除索引库
上篇博客可以看的出来删除索引库的 DSL 语句比较简单, DELETE /索引库名
, 与 创建索引库相比只不过是由 PUT 变成了 DELETE, 请求路径无需改变, 也没有任何请求参数. 当然代码还是分三步走:
Ⅰ: 创建 Request 对象, 注意这次不再是 CreateIndexRequest create 对象, 而是 DeleteIndexRequest 对象;
Ⅱ: 准备参数, 当然这里无参数;
Ⅲ: 发送请求, 改成了 delete 方法; client.indices() 方法的返回值是 IndicesClient 类型, 封装了所有与索引库操作有关的方法.
@Test
void testDeleteHotelIndex() throws IOException {
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
client.indices().delete(request, RequestOptions.DEFAULT);
}
1.5 查询索引库 (判断索引库是否存在)
查询索引库操作对应的 DSL 语句是 GET /索引库名
;
Ⅰ: 创建 Request 对象, 这次是 GetIndexRequest 对象;
Ⅱ: 准备参数, 当然这里也是无参数;
Ⅲ: 发送请求, 改成了 exists 方法; client.indices() 方法的返回值是 IndicesClient 类型, 封装了所有与索引库操作有关的方法.
@Test
void testExistsHotelIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("hotel");
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.err.println(exists ? "索引库已经存在!" : "索引库不存在!");
}
1.6 总结
通过上面的创建 / 删除 / 查询 操作可以看得出来, JavaRestClient 的步骤和 ElasticSearch 的流程基本相似, 核心都在 client.indices() 这个方法上, 索引库的基本步骤如下:
- 初始化 RestHighLevelClient;
- 创建各自的 Request;
- 准备 DSL, 只有创建的时候需要用到, 查询删除都用不到;
- 发送请求, 调用 client.indices() 这个方法.
❷ RestClient 文档操作
关于 RestClient 文档的操作也是要参照已经写好的 DSL 语句, 操作并不是很难; 但是前提是要确定好自己的数据库的实体类, 其次还要定义一个新的实体类, 这个实体类要与索引库的结构吻合 (我这里的数据还是用的某站酒店的数据).
2.1 新增文档
关于文档的新增也是分为三步走, 先是创建 Request 对象, 然后准备请求的参数, 也就是 DSL 中的数据, 最后发送请求即可.
@Test
void testAddDocument() throws IOException {
Hotel hotel = hotelService.getById(1);
HotelDoc hotelDoc = new HotelDoc(hotel);
IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString());
request.source(JSON.toJSONString(hotelDoc), XContentType.JSON);
client.index(request, RequestOptions.DEFAULT);
}
我们从数据库中获取到的数据需要先查询出来, 得到数据对象, 然后需要转换为 HotelDoc 对象 (因为要与索引库的结构一致), 然后再序列化为 json 格式;
具体流程步骤:
- 根据 id 查询到产品数据;
- 将查询到的数据对象封装成 Doc 类型 (要与索引库的结构一致);
- 将 Doc 数据序列化为 JSON 格式;
- 创建 IndexRequest ,指定索引库的名称及 id;
- 准备请求参数, 也就是刚才已经转换的 JSON 文档;
- 发送请求, 注意这里不再是 client.indeces()了.
2.2 查询文档
查询文档比较简单, 只需要准备 Request 对象, 然后发送请求即可; 这里还是要注意, 查询到的是 JSON 文档, 因此需要将 JSON 数据进行解析.
@Test
void testGetDocumentById() throws IOException {
GetRequest request = new GetRequest("hotel","61083");
GetResponse response = client.get(request, RequestOptions.DEFAULT);
String json = response.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
具体步骤:
- 准备 GetRequest 对象;
- 发送请求, client.get() 进行请求, 得到的是 json 格式;
- 解析结果, 也就是将 json 文档进行反序列化.
2.3 删除文档
删除文档和查询文档基本类似, 只是将 get 改成了 delete;
@Test
void testDeleteDocument() throws IOException {
DeleteRequest request = new DeleteRequest("hotel", "1");
client.delete(request, RequestOptions.DEFAULT);
}
具体步骤:
- 准备 DeleteRequest 对象, 指定索引库的名字及 id;
- 发送请求, 使用 client.delete() 方法.
2.4 修改文档
关于文档的修改前面的文章已经说过有两种方法, 全量修改和增量修改;
- 全量修改: 本质是先根据 id 删除, 然后再新增;
- 增量修改: 就是直接修改文档中指定的字段值;
- 当然在 RestClient 的 API 中, 是根据 id 是否存在来进行判断, 如果存在就修改, 不存在就新增.
@Test
void testUpdateDocument() throws IOException {
UpdateRequest request = new UpdateRequest("hotel", "1");
request.doc(
"name", "Remake",
"age", "999"
);
client.update(request, RequestOptions.DEFAULT);
}
具体步骤:
- 准备 Request 对象, 修改用的是 UpdateRequest;
- 准备参数, 也就是 JSON 文档, 里面包含了所要修改的字段;
- 更新文档, 调用 client.update() 方法.
❸ 批量数据导入
批量数据的导入用到了 BulkRequest, 具体步骤和新增基本一致, 先查询到数据库中的数据, 然后转换为 Doc 文档数据, 利用 BulkRequest 进行批处理, 实现批量数据的新增文档.
批量数据的新增其实质就是将多个 CRUD 请求组合在一起进行发送, 其中提供了一个 add 方法, 用来添加其他的请求, 其他的请求就包含了新增, 修改和删除操作.
@Test
void testBulkRequest() throws IOException {
List<Hotel> hotels = hotelService.list();
BulkRequest request = new BulkRequest();
for (Hotel hotel : hotels) {
HotelDoc hotelDoc = new HotelDoc(hotel);
request.add(new IndexRequest("hotel")
.id(hotelDoc.getId().toString())
.source(JSON.toJSONString(hotelDoc), XContentType.JSON));
}
client.bulk(request, RequestOptions.DEFAULT);
}
具体步骤:
- 从数据库中查到批量数据;
- 创建 Request 请求, 用到了 BulkRequest;
- 准备参数, 添加多个新增的 Request, 这里也要转换为 Doc 文档 (要与索引库的结构一致) 格式;
- 发送请求.