ElasticSearch 官方提供了各种不同语言的客户端,用来操作 ElasticSearch。这些客户端的本质就是组装 DSL 语句,通过 http 请求发送给 ElasticSearch。官方文档地址
其中的 Java Rest Client 又包括两种:
- Java Low Level Rest Client
- Java High Level Rest Client
我们学习的是 Java HighLevel Rest Client 客户端 API
创建测试环境
初始化项目
创建数据库,建立数据表
CREATE TABLE `tb_hotel` (`id` bigint(20) NOT NULL COMMENT '酒店id',`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店名称',`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店地址',`price` int(10) NOT NULL COMMENT '酒店价格',`score` int(2) NOT NULL COMMENT '酒店评分',`brand` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '酒店品牌',`city` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所在城市',`star_name` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '酒店星级,1星到5星,1钻到5钻',`business` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商圈',`latitude` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '纬度',`longitude` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '经度',`pic` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '酒店图片',PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
mapping 映射分析
创建索引库,最关键的是 mapping 映射,而 mapping 映射要考虑的信息包括:
- 字段名
- 字段数据类型
- 是否参与搜索
- 是否需要分词
- 如果分词,分词器是什么?
其中:
- 字段名、字段数据类型,可以参考数据表结构的名称和类型
- 是否参与搜索要分析业务来判断,例如图片地址,就无需参与搜索
- 是否分词呢要看内容,内容如果是一个整体就无需分词,反之则要分词
- 分词器,我们可以统一使用 ik_max_word
来看下酒店数据的索引库结构:
PUT /hotel
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"name":{
"type": "text",
"analyzer": "ik_max_word",
"copy_to": "all"
},
"address":{
"type": "keyword",
"index": false
},
"price":{
"type": "integer"
},
"score":{
"type": "integer"
},
"brand":{
"type": "keyword",
"copy_to": "all"
},
"city":{
"type": "keyword",
"copy_to": "all"
},
"starName":{
"type": "keyword"
},
"business":{
"type": "keyword"
},
"location":{
"type": "geo_point"
},
"pic":{
"type": "keyword",
"index": false
},
"all":{
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
几个特殊字段说明:
- location:地理坐标,里面包含精度、纬度
- all:一个组合字段,其目的是将多字段的值 利用 copy_to 合并,提供给用户搜索
ES 中支持两种地理坐标数据类型:
- geo_point:由纬度(latitude)和经度(longitude)确定的一个点。例如:”32.8752345, 120.2981576”
- geo_shape:有多个 geo_point 组成的复杂几何图形。例如一条直线,”LINESTRING (-77.03653 38.897676, -77.009051 38.889939)”
字段拷贝可以使用 copy_to 属性将当前字段拷贝到指定字段。示例:
"all": {
"type": "text",
"analyzer": "ik_max_word"
},
"brand": {
"type": "keyword",
"copy_to": "all"
}
初始化 RestClient
在 ElasticSearch 提供的 API 中,与 ElasticSearch 一切交互都封装在一个名为 RestHighLevelClient 的类中,必须先完成这个对象的初始化,建立与 ElasticSearch 的连接。
分为三步:
① 引入 ElasticSearch 的 RestHighLevelClient 依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
② 因为 SpringBoot 默认的 ElasticSearch 版本是 7.6.2,所以我们需要覆盖默认的 ElasticSearch 版本,与 ElasticSearch 版本保持一致
<properties>
<java.version>1.8</java.version>
<elasticsearch.version>7.14.1</elasticsearch.version>
</properties>
③ 初始化 RestHighLevelClient,初始化的代码如下:
RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://halo:9200")));
这里为了单元测试方便,我们创建一个测试类 HotelIndexTest,然后将初始化的代码编写在 @BeforeEach 方法中:
public class HotelIndexTest {
private RestHighLevelClient client;
@Test
void testInit() {
System.out.println("client = " + client);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://halo:9200")));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
创建索引库

代码分为三步:
- 创建 Request 对象。因为是创建索引库的操作,因此 Request 是 CreateIndexRequest
- 添加请求参数,其实就是 DSL 的 JSON 参数部分。因为 JSON 字符串很长,这里是定义了静态字符串常量 MAPPING_TEMPLATE,让代码看起来更加优雅。
- 发送请求,
client.indices()方法的返回值是 IndicesClient 类型,封装了所有与索引库操作有关的方法。
在 hotel-demo 中的 HotelIndexTest 测试类中,编写单元测试,实现创建索引:
@Test
void createHotelIndex() throws IOException {
// 1.创建Request对象
CreateIndexRequest request = new CreateIndexRequest("hotel");
// 2.准备请求的参数:DSL语句
request.source(MAPPING_TEMPLATE, XContentType.JSON);
// 3.发送请求
client.indices().create(request, RequestOptions.DEFAULT);
}
删除索引库
删除索引库的 DSL 语句非常简单:
DELETE /hotel
与创建索引库相比:
- 请求方式从 PUT 变为 DELTE
- 请求路径不变
- 无请求参数
所以代码的差异,注意体现在 Request 对象上。依然是三步走:
- 创建 Request 对象。这次是 DeleteIndexRequest 对象
- 准备参数。这里是无参
- 发送请求。改用 delete 方法
在 hotel-demo 中的 HotelIndexTest 测试类中,编写单元测试,实现删除索引:
@Test
void testDeleteHotelIndex() throws IOException {
// 1.创建Request对象
DeleteIndexRequest request = new DeleteIndexRequest("hotel");
// 2.发送请求
client.indices().delete(request, RequestOptions.DEFAULT);
}
判断索引库是否存在
判断索引库是否存在,本质就是查询,对应的 DSL 是:
GET /hotel
因此与删除的 Java 代码流程是类似的。依然是三步走:
- 创建 Request 对象。这次是 GetIndexRequest 对象
- 准备参数。这里是无参
- 发送请求。改用 exists 方法
@Test void testExistsHotelIndex() throws IOException { // 1.创建Request对象 GetIndexRequest request = new GetIndexRequest("hotel"); // 2.发送请求 boolean exists = client.indices().exists(request, RequestOptions.DEFAULT); // 3.输出 System.err.println(exists ? "索引库已经存在!" : "索引库不存在!"); }RestAPI 小结
JavaRestClient 操作 ElasticSearch 的流程基本类似。核心是client.indices()方法来获取索引库的操作对象。
索引库操作的基本步骤:
- 初始化 RestHighLevelClient
- 创建 XxxIndexRequest。Xxx 是 Create、Get、Delete
- 准备 DSL( Create时需要,其它是无参)
- 发送请求。调用
RestHighLevelClient#indices().xxx()方法,xxx 是 create、exists、delete
