DocumentTest.java
12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
package com.sl.ms.search;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;
import com.sl.SearchApplication;
import com.sl.ms.search.entity.Person;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ES文档相关测试
**/
@Slf4j
@SpringBootTest(classes = SearchApplication.class)
class DocumentTest {
@Resource
private ElasticsearchClient client;
private static final String INDEX_NAME = "person";
/**
* 新增或更新文档(传参为函数)
* 注意:这里的更新是全量更新,原来没有的字段会增加,没有数据的字段会删掉
*
* @throws IOException IO异常
*/
@Test
void createOrUpdateDoc01() throws IOException {
// 1.构造对象
Person person = new Person(18, "张三", "18912345678", "北京市昌平区西三旗街道金燕龙办公楼");
// 2.新增或更新文档数据(构造函数,使用lambda表达式形式)
IndexResponse response = client.index(i -> i
.index(INDEX_NAME)
.id("1")
// 此处传参也可以是map
.document(person));
// 3.version为1表示新增,大于1表示更新
log.info("Indexed with version " + response.version());
}
/**
* 新增或更新文档(传参为对象)
* 注意:这里的更新是全量更新,原来没有的字段会增加,没有数据的字段会删掉
*
* @throws IOException IO异常
*/
@Test
void createOrUpdateDoc02() throws IOException {
// 1.构造对象
Person person = new Person(18, "张三", "18912345678", "北京市昌平区西三旗街道金燕龙办公楼");
// 2.使用DSL语法创建对象,进行新增或更新
IndexRequest<Person> request = IndexRequest.of(i -> i
.index(INDEX_NAME)
.id("2")
// 此处传参也可以是map
.document(person));
IndexResponse response = client.index(request);
// 3.version为1表示新增,大于1表示更新
log.info("Indexed with version " + response.version());
}
/**
* 新增文档(使用对象)
*
* @throws IOException IO异常
*/
@Test
void createDoc01() throws IOException {
// 1.构造对象
Person person = new Person(18, "张三", "18912345678", "北京市昌平区西三旗街道金燕龙办公楼");
// 2.新增文档数据(若重复新增则会报错,错误码409)
CreateResponse response = client.create(c -> c
.index(INDEX_NAME)
.id("3")
.document(person));
// 3.响应结果
log.info(response.toString());
}
/**
* 新增文档(使用map)
*
* @throws IOException IO异常
*/
@Test
void createDoc02() throws IOException {
// 1.数据封装到map
Map<String, Object> doc = new HashMap<>();
doc.put("age", 78);
doc.put("name", "Joe Biden");
doc.put("phone", "1-202-456-1414");
doc.put("address", "1600 Pennsylvania Avenue NW, Washington, DC 20500");
// 2.新增文档数据(若重复新增则会报错,错误码409)
CreateResponse response = client.create(c -> c
.index(INDEX_NAME)
.id("4")
.document(doc));
// 3.响应结果
log.info(response.toString());
}
/**
* 批量新增
*
* @throws IOException IO异常
*/
@Test
void bulkCreateDoc() throws IOException {
// 1.构造数据
List<Person> personList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
Person person = new Person(18 + i, "李四", "18912345678", "北京市顺义区京顺路99号");
personList.add(person);
}
// 2.循环添加新增操作
int i = 5;
BulkRequest.Builder br = new BulkRequest.Builder();
for (Person person : personList) {
String id = String.valueOf(i++);
br.operations(op -> op.index(idx -> idx
.index(INDEX_NAME)
.id(id)
.document(person)));
}
// 3.批量新增
BulkResponse result = client.bulk(br.build());
// 4.如果出现错误,输出所有错误信息
if (result.errors()) {
log.error("Bulk had errors");
for (BulkResponseItem item : result.items()) {
if (item.error() != null) {
log.error(item.error().reason());
}
}
}
}
/**
* 更新文档(使用对象,增量更新)
*
* @throws IOException IO异常
*/
@Test
void updateDoc01() throws IOException {
// 1.构造数据(传入为null的字段不会更新)
Person person = new Person(20, null, null, null);
// 2.数据更新
UpdateResponse<Person> response = client.update(u -> u
.index(INDEX_NAME)
.id("1")
.doc(person)
, Person.class);
// 3.响应结果
log.info(response.toString());
}
/**
* 更新文档(使用map,增量更新)
*
* @throws IOException IO异常
*/
@Test
void updateDoc02() throws IOException {
// 1.构造数据(sex是原来不存在的字段,该方法会新增这个字段)
Map<String, Object> doc = new HashMap<>();
doc.put("age", 33);
doc.put("sex", "男");
// 2.数据更新
UpdateResponse response = client.update(builder -> builder
.index(INDEX_NAME)
.id("1")
.doc(doc)
, Map.class);
// 3.响应结果
log.info(response.toString());
}
/**
* 删除文档
*
* @throws IOException IO异常
*/
@Test
void deleteDoc() throws IOException {
DeleteResponse response = client.delete(d -> d
.index(INDEX_NAME)
.id("1"));
log.info(response.toString());
}
/**
* 条件删除文档(传参为函数)
*
* @throws IOException IO异常
*/
@Test
void deleteByQueryDoc01() throws IOException {
// deleteByQuery方法传参为lambda函数
DeleteByQueryResponse response = client.deleteByQuery(d -> d.index(INDEX_NAME)
.query(q -> q
.match(m -> m
.field("age")
.query("20"))));
log.info(response.toString());
}
/**
* 条件删除文档(传参为对象)
*
* @throws IOException IO异常
*/
@Test
void deleteByQueryDoc02() throws IOException {
// 构造删除条件
Query query = new Query.Builder().match(m -> m
.field("age")
.query("20")).build();
DeleteByQueryRequest searchRequest = new DeleteByQueryRequest.Builder()
.index(INDEX_NAME)
.query(query).build();
// 此处search方法传参为DeleteByQueryRequest对象
DeleteByQueryResponse response = client.deleteByQuery(searchRequest);
log.info(response.toString());
}
/**
* 查询所有文档(用对象接收)
*
* @throws IOException IO异常
*/
@Test
void getDocAll01() throws IOException {
SearchResponse<Person> response = client.search(s -> s.index(INDEX_NAME), Person.class);
log.info(response.toString());
}
/**
* 查询所有文档(用map接收)
*
* @throws IOException IO异常
*/
@Test
void getDocAll02() throws IOException {
SearchResponse<Map> response = client.search(s -> s.index(INDEX_NAME), Map.class);
log.info(response.toString());
}
/**
* 查询单个文档(使用对象接收)
*
* @throws IOException IO异常
*/
@Test
void getDoc01() throws IOException {
// 1.查询id为2的文档
GetResponse<Person> response = client.get(g -> g.index(INDEX_NAME).id("2"), Person.class);
// 2.判断响应数据是否为空
if (response.found()) {
Person person = response.source();
assert person != null;
log.info("Person name " + person.getName());
} else {
log.info("Person not found");
}
}
/**
* 查询单个文档(使用map接收)
*
* @throws IOException IO异常
*/
@Test
void getDoc02() throws IOException {
// 1.查询id为2的文档
GetResponse<Map> response = client.get(g -> g.index(INDEX_NAME).id("2"), Map.class);
// 2.判断响应数据是否为空
if (response.found()) {
Map person = response.source();
assert person != null;
log.info("Person name " + person.get("name"));
} else {
log.info("Person not found");
}
}
/**
* 简单查询(传入函数)
*
* @throws IOException IO异常
*/
@Test
void simpleSearch01() throws IOException {
// 1.构造查询条件,并进行查询(此处search方法传参为lambda函数)
SearchResponse<Person> response = client.search(s -> s.index(INDEX_NAME)
.query(q -> q
.match(m -> m
.field("name")
.query("张三")))
, Person.class);
// 2.查询结果数量
TotalHits total = response.hits().total();
assert total != null;
// 默认情况下,hits.total.value是不确切的命中计数,
// 在这种情况下,当hits.total.relation的值是eq时,hits.total.value的值是准确计数。
// 当hits.total.relation的值是gte时,hits.total.value的值是不准确的。
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
if (isExactResult) {
log.info("There are " + total.value() + " results");
} else {
log.info("There are more than " + total.value() + " results");
}
// 3.解析hit结构,输出全部结果
List<Hit<Person>> hits = response.hits().hits();
for (Hit<Person> hit : hits) {
Person person = hit.source();
assert person != null;
log.info("Found person " + person.getName() + ", score " + hit.score());
}
}
/**
* 简单查询(传入对象)
*
* @throws IOException IO异常
*/
@Test
void simpleSearch02() throws IOException {
// 1.构造查询条件,并进行查询
Query query = new Query.Builder().match(m -> m
.field("name")
.query("张三")).build();
SearchRequest searchRequest = new SearchRequest.Builder()
.index(INDEX_NAME)
.query(query).build();
// 此处search方法传参为SearchRequest对象
SearchResponse<Person> response = client.search(searchRequest, Person.class);
// 2.查询结果数量
TotalHits total = response.hits().total();
assert total != null;
// 默认情况下,hits.total.value是不确切的命中计数,
// 在这种情况下,当hits.total.relation的值是eq时,hits.total.value的值是准确计数。
// 当hits.total.relation的值是gte时,hits.total.value的值是不准确的。
boolean isExactResult = total.relation() == TotalHitsRelation.Eq;
if (isExactResult) {
log.info("There are " + total.value() + " results");
} else {
log.info("There are more than " + total.value() + " results");
}
// 3.解析hit结构,输出全部结果
List<Hit<Person>> hits = response.hits().hits();
for (Hit<Person> hit : hits) {
Person person = hit.source();
assert person != null;
log.info("Found person " + person.getName() + ", score " + hit.score());
}
}
}