import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.mapping.IntegerNumberProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
import co.elastic.clients.elasticsearch.cat.IndicesResponse;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
import co.elastic.clients.elasticsearch.core.search.TotalHits;
import co.elastic.clients.elasticsearch.core.search.TotalHitsRelation;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.example.elasticsearch.model.AddressMessageResponse;
import com.example.elasticsearch.model.AddressRequest;
import com.example.elasticsearch.model.User;
import com.mayabot.nlp.utils.CharNormUtils;
import jakarta.json.Json;
import jakarta.json.stream.JsonParser;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RequestOptions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* @version 1.0.0
* @className: IndexTest
* @description: 索引测试
* @author: LiJunYi
* @create: 2022/8/8 10:03
*/
@SpringBootTest
@Slf4j
public class IndexTest
{
@Resource
private ElasticsearchClient elasticsearchClient;
/**
* 创建索引
*
* @throws IOException ioexception
*/
@Test
void createIndex() throws IOException {
CreateIndexResponse response = elasticsearchClient.indices().create(c -> c.index("products"));
//响应状态
boolean acknowledged = response.acknowledged();
boolean shardsAcknowledged = response.shardsAcknowledged();
String index = response.index();
log.info("创建索引状态:{}",acknowledged);
log.info("已确认的分片:{}",shardsAcknowledged);
log.info("索引名称:{}",index);
}
/**
* 创建索引并设置字段使用IK分词器
*
* @throws IOException ioexception
*/
@Test
void createIndexAndIk() throws IOException {
// 创建一个Map来存储文档的属性
Map<String, Property> documentMap = new HashMap<>();
// 添加userName属性,使用text类型,并指定分词器为ik_max_word
documentMap.put("userName", Property.of(p -> p
.text(TextProperty.of(textProperty ->
textProperty.index(true).analyzer("ik_max_word")))));
// 添加userName属性,使用text类型,并指定分词器为ik_max_word
documentMap.put("aa", Property.of(p -> p
.text(TextProperty.of(textProperty ->
textProperty.index(true).analyzer("ik_max_word")))));
// 添加age属性,使用integer类型
documentMap.put("age", Property.of(property ->
property.integer(IntegerNumberProperty.of(integerNumberProperty ->
integerNumberProperty.index(true)))
)
);
// 创建索引并设置映射和别名
CreateIndexResponse response = elasticsearchClient.indices().create(createIndexBuilder ->
createIndexBuilder.index("user_202456") // 指定索引名称为"user"
.mappings(mappings ->
mappings.properties(documentMap)) // 设置文档属性
.aliases("User2", aliases ->
aliases.isWriteIndex(true)) // 设置别名并指定为写入索引
);
// 获取响应状态
boolean acknowledged = response.acknowledged(); // 确认索引是否已创建
boolean shardsAcknowledged = response.shardsAcknowledged(); // 确认分片是否已创建
String index = response.index(); // 获取创建的索引名称
// 记录日志信息
log.info("创建索引状态:{}", acknowledged);
log.info("已确认的分片:{}", shardsAcknowledged);
log.info("索引名称:{}", index);
}
/**
* 创建索引--方式三,使用model创建索引
* 对于字段,可以提前指定全部或者指定部分字段,也可以不指定,在插入文档的时候交给es自动生成
*/
@Test
public void createIndexWithModel() throws IOException {
// 构建索引设置,包括分析器
IndexSettings settingsOther = IndexSettings.of(sBuilder -> sBuilder
.index(iBuilder -> iBuilder
// 2个分片
.numberOfShards("2")
// 1个副本
.numberOfReplicas("1")
// 设置刷新间隔
.refreshInterval(t -> t.time("1s"))
)
);
// 3.创建索引
CreateIndexResponse response = elasticsearchClient
.indices()
.create(c -> c
.index("users2024")
.settings(settingsOther)
.mappings(mBuilder -> mBuilder
// 格式化日期
.dynamicDateFormats("yyyy-MM-dd HH:mm:ss")
.dateDetection(true)
// .properties(IndexTestModel.ID, pBuilder -> pBuilder.keyword(keywordPropertyBuilder -> keywordPropertyBuilder.ignoreAbove(30)))
// .properties(IndexTestModel.NAME, pBuilder -> pBuilder.keyword(keywordPropertyBuilder -> keywordPropertyBuilder.ignoreAbove(30)))
)
);
log.info("创建索引状态:{}", response.acknowledged());
}
/**
* 获取索引
*/
@Test
void getIndex() throws IOException {
//是否存在索引
ExistsRequest existsRequest = ExistsRequest.of(s -> s.index("products*"));
boolean exists = elasticsearchClient.indices().exists(existsRequest).value();
System.out.println(exists);
boolean existsed = elasticsearchClient.indices().exists(s -> s.index("products")).value();
System.out.println("existsed:"+existsed);
// 查看指定索引
GetIndexResponse getIndexResponse = elasticsearchClient.indices().get(s -> s.index("products"));
Map<String, IndexState> result = getIndexResponse.result();
result.forEach((k, v) -> log.info("\n key = {},\n value = {}",k ,v));
// 查看全部索引
IndicesResponse indicesResponse = elasticsearchClient.cat().indices();
indicesResponse.valueBody().forEach(
info -> log.info("\n 索引名称: {}\n 健康状态: {}\n 状态: {}\n UUID: {}\n",
info.index(), info.health(), info.status(), info.uuid())
);
}
/**
* 删除索引
*
* @throws IOException ioexception
*/
@Test
void deleteIndex() throws IOException {
// DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices().delete(s -> s.index("kit"));
// log.info("删除索引操作结果:{}",deleteIndexResponse.acknowledged());
// try {
// DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices().delete(
// DeleteIndexRequest.of(s -> s.index("book"))
// );
// log.info("删除索引操作结果:{}", deleteIndexResponse.acknowledged());
// } catch (ElasticsearchException e) {
// if (e.status() == 404) {
// log.info("索引 kit 不存在,无需删除");
// } else {
// log.error("删除索引 kit 时发生错误", e);
// }
// } catch (IOException e) {
// log.error("与Elasticsearch通信时发生I/O错误", e);
// }
try {
// 创建删除索引请求
DeleteIndexRequest request = DeleteIndexRequest.of(s -> s
.index("kit").timeout(a->a.time("3s"))
);
// 执行删除索引操作
DeleteIndexResponse response = elasticsearchClient.indices().delete(request);
// 检查删除操作是否被确认
if (response.acknowledged()) {
log.info("索引 {} 删除成功", "kit");
} else {
log.warn("索引 {} 删除未被确认", "kit");
}
} catch (ElasticsearchException e) {
if (e.status() == 404) {
log.info("索引 kit 不存在,无需删除");
} else {
log.error("删除索引 kit 时发生错误", e);
}
} catch (IOException e) {
log.error("与Elasticsearch通信时发生I/O错误", e);
}
}
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.SearchTemplateResponse;
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 co.elastic.clients.json.JsonData;
import com.example.elasticsearch.model.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
/**
* @version 1.0.0
* @className: SearchTest
* @description: 查询测试
* @author: LiJunYi
* @create: 2022/8/8 11:04
*/
@SpringBootTest
@Slf4j
public class SearchTest
{
@Autowired
private ElasticsearchClient elasticsearchClient;
/**
* 批量添加文档
*
* @throws IOException ioexception
*/
@Test
void batchAddDocument () throws IOException
{
List<User> users = new ArrayList<>();
users.add(new User("11","zhaosi",20,"男"));
users.add(new User("22","awang",25,"男"));
users.add(new User("33","liuyifei",22,"女"));
users.add(new User("44","dongmei",20,"女"));
users.add(new User("55","zhangya",30,"女"));
users.add(new User("66","liuyihu",32,"男"));
BulkRequest.Builder br = new BulkRequest.Builder();
for (User user : users) {
br.operations(op -> op
.index(idx -> idx
.index("users")
.id(user.getId())
.document(user)));
}
BulkResponse result = elasticsearchClient.bulk(br.build());
// Log errors, if any
if (result.errors()) {
log.error("Bulk had errors");
for (BulkResponseItem item: result.items()) {
if (item.error() != null) {
log.error(item.error().reason());
}
}
}
}
/**
* 简单的搜索查询
*
* @throws IOException ioexception
*/
@Test
void searchOne() throws IOException {
String searchText = "liuyihu";
SearchResponse<User> response = elasticsearchClient.search(s -> s
// 我们要搜索的索引的名称
.index("users")
// 搜索请求的查询部分(搜索请求也可以有其他组件,如聚合)
.query(q -> q
// 在众多可用的查询变体中选择一个。我们在这里选择匹配查询(全文搜索)
.match(t -> t
// name配置匹配查询:我们在字段中搜索一个词
.field("name")
.query(searchText)
)
),
// 匹配文档的目标类
User.class
);
TotalHits total = response.hits().total();
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");
}
List<Hit<User>> hits = response.hits().hits();
for (Hit<User> hit: hits) {
User user = hit.source();
assert user != null;
log.info("Found userId " + user.getId() + ", name " + user.getName());
}
}
/**
* 多条件查询(IN )
*
* @throws IOException ioexception
*/
@Test
void searchIn() throws IOException {
/*方式一:terms多条件查询*/
List<FieldValue> values = new ArrayList<>();
values.add(FieldValue.of("zhaosi"));
values.add(FieldValue.of("liuyifei"));
Query queryIn = TermsQuery.of(t -> t.field("name.keyword").terms(new TermsQueryField.Builder()
.value(values).build()))._toQuery();
SearchResponse<User> response = elasticsearchClient.search(s -> s
// 我们要搜索的索引的名称
.index("users")
// 搜索请求的查询部分(搜索请求也可以有其他组件,如聚合)
.query(q -> q
.bool(b -> b
.must(queryIn)
.should(sh -> sh
.match(t -> t.field("name")
.query("")))
)
),
// 匹配文档的目标类
User.class
);
/*方式二,使用模板化搜索,直接编写 terms 语句
* 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.3/search-template.html#search-template-convert-json
* */
/*elasticsearchClient.putScript(r -> r
// 要创建的模板脚本的标识符
.id("query-script")
.script(s -> s
.lang("mustache")
.source("{\"query\":{\"terms\":{\"{{field}}\": {{#toJson}}values{{/toJson}} }}}")
));
String field = "name.keyword";
List<String> values = Arrays.asList("liuyifei","zhangya");
String v = String.join(",",values);
SearchTemplateResponse<User> response = elasticsearchClient.searchTemplate(r -> r
.index("users")
// 要使用的模板脚本的标识符
.id("query-script")
// 模板参数值
.params("field", JsonData.of(field))
.params("values", JsonData.of(values)),
User.class
);*/
List<Hit<User>> hits = response.hits().hits();
for (Hit<User> hit: hits) {
User user = hit.source();
assert user != null;
log.info("Found userId " + user.getId() + ", name " + user.getName());
}
}
/**
* 嵌套搜索查询
*/
@Test
void searchTwo() throws IOException {
// String searchText = "liuyihu";
// int maxAge = 30;
// // byName、byMaxAge:分别为各个条件创建查询
// Query byName = MatchQuery.of(m -> m
// .field("name")
// .query(searchText)
// )
// //MatchQuery是一个查询变体,我们必须将其转换为 Query 联合类型
// ._toQuery();
// Query byMaxAge = RangeQuery.of(m -> m
// .field("age")
// // Elasticsearch 范围查询接受大范围的值类型。我们在这里创建最高价格的 JSON 表示。
// .gte(JsonData.of(maxAge))
// )._toQuery();
// SearchResponse<User> response = elasticsearchClient.search(s -> s
// .index("users")
// .query(q -> q
// .bool(b -> b
// // 搜索查询是结合了文本搜索和最高价格查询的布尔查询
// .must(byName)
// .should(byMaxAge)
// )
// ),
// User.class
// );
// List<Hit<User>> hits = response.hits().hits();
// for (Hit<User> hit: hits) {
// User user = hit.source();
// assert user != null;
// log.info("Found userId " + user.getId() + ", name " + user.getName());
// }
}
/**
* 模板化搜索
* 模板化搜索是存储的搜索,可以使用不同的变量运行它。搜索模板让您无需修改应用程序代码即可更改搜索。
* 在运行模板搜索之前,首先必须创建模板。这是一个返回搜索请求正文的存储脚本,通常定义为 Mustache 模板
*/
@Test
void templatedSearch() throws IOException {
elasticsearchClient.putScript(r -> r
// 要创建的模板脚本的标识符
.id("query-script")
.script(s -> s
.lang("mustache")
.source("{\"query\":{\"match\":{\"{{field}}\":\"{{value}}\"}}}")
));
// 开始使用模板搜索
String field = "name";
String value = "liuyifei";
SearchTemplateResponse<User> response = elasticsearchClient.searchTemplate(r -> r
.index("users")
// 要使用的模板脚本的标识符
.id("query-script")
// 模板参数值
.params("field", JsonData.of(field))
.params("value", JsonData.of(value)),
User.class
);
List<Hit<User>> hits = response.hits().hits();
for (Hit<User> hit: hits) {
User user = hit.source();
assert user != null;
log.info("Found userId " + user.getId() + ", name " + user.getName());
}
}
/**
* 分页+排序条件搜索
*
* @throws IOException ioexception
*/
@Test
void paginationQuerySearch() throws IOException
{
// int maxAge = 20;
// Query byMaxAge = RangeQuery.of(m -> m
// .field("age")
// .gte(JsonData.of(maxAge))
// )._toQuery();
// SearchResponse<User> response = elasticsearchClient.search(s -> s
// .index("users")
// .query(q -> q
// .bool(b -> b
// .must(byMaxAge)
// )
// )
// //分页查询,从第0页开始查询4个document
// .from(0)
// .size(4)
// //按age降序排序
// .sort(f -> f.field(o -> o.field("age")
// .order(SortOrder.Desc))),
// User.class
// );
// List<Hit<User>> hits = response.hits().hits();
// List<User> userList = new ArrayList<>(hits.size());
// for (Hit<User> hit: hits) {
// User user = hit.source();
// userList.add(user);
// }
// log.info(JSONUtil.toJsonStr(userList));
}
/**
* 分页+排序所有数据
*
* @throws IOException ioexception
*/
@Test
void paginationAllSearch() throws IOException
{
SearchResponse<User> response = elasticsearchClient.search(s -> s
.index("users")
// 这里的 query 可忽略
.query(q -> q
.matchAll( m -> m)
)
.from(0)
.size(10)
.sort(f -> f.field(o -> o.field("age")
.order(SortOrder.Desc))),
User.class
);
List<Hit<User>> hits = response.hits().hits();
List<User> userList = new ArrayList<>(hits.size());
for (Hit<User> hit: hits) {
User user = hit.source();
userList.add(user);
}
log.info(JSONUtil.toJsonStr(userList));
}
/**
* 过滤字段
*
* @throws IOException ioexception
*/
@Test
void filterFieldSearch() throws IOException
{
SearchResponse<User> response = elasticsearchClient.search(s -> s
.index("users")
.query(q -> q
.matchAll( m -> m)
)
.sort(f -> f
.field(o -> o
.field("age")
.order(SortOrder.Desc)
)
)
.source(source -> source
.filter(f -> f
.includes("name","id")
.excludes(""))),
User.class
);
List<Hit<User>> hits = response.hits().hits();
List<User> userList = new ArrayList<>(hits.size());
for (Hit<User> hit: hits) {
User user = hit.source();
userList.add(user);
}
log.info("过滤字段后:{}",JSONUtil.toJsonStr(userList));
}
/**
* 模糊查询
*
* @throws IOException ioexception
*/
@Test
void fuzzyQuerySearch() throws IOException
{
SearchResponse<User> response = elasticsearchClient.search(s -> s
.index("users")
.query(q -> q
// 模糊查询
.fuzzy(f -> f
// 需要判断的字段名称
.field("name.keyword")
// 需要模糊查询的关键词
.value("liuyi")
// fuzziness代表可以与关键词有误差的字数,可选值为0、1、2这三项
.fuzziness("2")
)
)
.source(source -> source
.filter(f -> f
.includes("name","id")
.excludes(""))),
User.class
);
List<Hit<User>> hits = response.hits().hits();
List<User> userList = new ArrayList<>(hits.size());
for (Hit<User> hit: hits) {
User user = hit.source();
userList.add(user);
}
log.info("模糊查询结果:{}",JSONUtil.toJsonStr(userList));
}
/**
* 高亮查询
*
* @throws IOException ioexception
*/
@Test
void highlightQueryQuery() throws IOException
{
SearchResponse<User> response = elasticsearchClient.search(s -> s
.index("users")
.query(q -> q
.term(t -> t
.field("name")
.value("zhaosi"))
)
.highlight(h -> h
.fields("name", f -> f
.preTags("<font color='red'>")
.postTags("</font>")))
.source(source -> source
.filter(f -> f
.includes("name","id")
.excludes(""))),
User.class
);
List<Hit<User>> hits = response.hits().hits();
List<User> userList = new ArrayList<>(hits.size());
for (Hit<User> hit: hits) {
User user = hit.source();
userList.add(user);
for(Map.Entry<String, List<String>> entry : hit.highlight().entrySet())
{
System.out.println("Key = " + entry.getKey());
entry.getValue().forEach(System.out::println);
}
}
log.info(JSONUtil.toJsonStr(userList));
}
/**
* 指定字段查询
*/
@Test
void specifyFieldQuery() throws IOException {
// int maxAge = 20;
// Query byMaxAge = RangeQuery.of(m -> m
// .field("age")
// .gte(JsonData.of(maxAge))
// )._toQuery();
// SearchResponse<User> response = elasticsearchClient
// .search(s -> s
// .index("users")
// .query(q -> q
// .bool(b -> b
// .must(byMaxAge)
// )
// )
// //分页查询,从第0页开始查询3个document
// .from(0)
// .size(4)
// //按age降序排序
// .sort(f -> f.field(o -> o.field("age")
// .order(SortOrder.Desc))),
// User.class
// );
// List<Hit<User>> hits = response.hits().hits();
// List<User> userList = new ArrayList<>(hits.size());
// for (Hit<User> hit: hits) {
// User user = hit.source();
// userList.add(user);
// }
// log.info(JSONUtil.toJsonStr(userList));
}
/**
* 糅合查询,将以上方法整合进行查询
* 部分字段索引中不存在,该方法只提供写法,不保证成功运行
*/
@Test
public void specifyFieldQuery1() throws IOException, ParseException {
// BoolQuery.Builder boolQuery = QueryBuilders.bool();
// // 精确查询
// boolQuery.must(TermQuery.of(t -> t.field("address.keyword").value("提瓦特"))._toQuery());
//
// // 多条件 in 查询
// // in 构建方式一
// List<FieldValue> nameList = Arrays.asList(FieldValue.of("霄"), FieldValue.of("甘雨"), FieldValue.of("心海"));
// boolQuery.must(TermsQuery.of(t -> t.field("name.keyword").terms(new TermsQueryField.Builder().value(nameList).build()))._toQuery());
// // in 构建方式二
//// List<String> nameList = Arrays.asList("霄", "甘雨", "心海");
//// boolQuery.must(TermsQuery.of(t -> t.field("name.keyword").terms(new TermsQueryField.Builder().value(nameList.stream().map(FieldValue::of).collect(Collectors.toList())).build()))._toQuery());
//
// SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// SimpleDateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd");
// String startDateParam = dateFormatter.format(dateParser.parse("date"));
// boolQuery.must(RangeQuery.of(t -> t.field("signTime").gte(JsonData.of(startDateParam)))._toQuery());
//
// SearchResponse<User> search = elasticsearchClient.search(s -> s
// .index("users")
// .query(q -> q
// .bool(boolQuery.build())
// )
// .from(0)
// .size(4)
// .sort(sortOptionsBuilder -> sortOptionsBuilder
// .field(fieldSortBuilder -> fieldSortBuilder
// .field("signTime").order(SortOrder.Desc)
// )
// )
// , User.class);
//
// List<User> signRecordList = search.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
// log.info(JSONUtil.toJsonStr(signRecordList));
}
}
package com.example.elasticsearch;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import com.example.elasticsearch.model.Products;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.Collections;
/**
* Script的简单使用
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting-using.html">官方文档</a>
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.6/search-fields.html#script-fields">官方文档</a>
* <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/scripts-and-search-speed.html">官方文档</a>
* @author LiJY
* @date 2024/01/23
*/
@SpringBootTest
@Slf4j
public class ScriptTest {
@Autowired
private ElasticsearchClient elasticsearchClient;
/**
* 添加示例商品索引
*
* @throws IOException ioexception
*/
@Test
void addOneDocument () throws IOException
{
// 1、using the fluent DSL
Products products = new Products();
products.setId("5");
products.setCounter(240);
products.setTags(Collections.singletonList("yellow"));
IndexResponse indexResponse = elasticsearchClient.index(s ->
// 索引
s.index("products")
// ID
.id(products.getId())
// 文档
.document(products)
);
log.info("result:{}",indexResponse.result().jsonValue());
}
/**
* 脚本修改商品 counter 属性
*/
@Test
public void updateProductsCounter(){
// String indexName = "products";
// int fromCounter = 1;
// Integer newCounter = 666;
// Map<String, JsonData> map = Maps.newHashMap("newCounter", JsonData.of(newCounter));
// try {
// elasticsearchClient.updateByQuery(d -> d
// .index(indexName)
// .query(q -> q
// .term(t -> t
// .field("counter")
// .value(fromCounter)
// ))
// .script(s -> s
// .inline(src -> src
// .lang("painless")
// .source("ctx._source.counter += params.newCounter")
// .params(map)
// )
// )
// );
// } catch (IOException e) {
// log.error(e.getMessage());
// }
}
/**
* 脚本修改商品 tag 属性
*/
@Test
public void updateProductsTags(){
// String indexName = "products";
// String fromTag = "red";
// String addTag = "yellow";
// Map<String, JsonData> map = Maps.newHashMap("addTag", JsonData.of(addTag));
// try {
// elasticsearchClient.updateByQuery(d -> d
// .index(indexName)
// .query(q -> q
// .term(t -> t
// .field("tags")
// .value(fromTag)
// ))
// .script(s -> s
// .inline(src -> src
// .lang("painless")
// .source("ctx._source.tags.add(params.addTag)")
// .params(map)
// )
// )
// );
// } catch (IOException e) {
// log.error(e.getMessage());
// }
}
@Test
public void removeProductTags(){
// String indexName = "products";
// // String fromTag = "red,blue";
// String deleteTag = "blue";
// Map<String, JsonData> map = Maps.newHashMap("deleteTag", JsonData.of(deleteTag));
// try {
// elasticsearchClient.updateByQuery(d -> d
// .index(indexName)
//// .query(q -> q
//// .term(t -> t
//// .field("tags")
//// .value(fromTag)
//// ))
// .script(s -> s
// .inline(src -> src
// .lang("painless")
// .source("if (ctx._source.tags.contains(params.deleteTag)) { ctx._source.tags.remove(ctx._source.tags.indexOf(params.deleteTag)) }")
// .params(map)
// )
// )
// );
// } catch (IOException e) {
// log.error(e.getMessage());
// }
}
/**
* 搜索全部订单并排序
* 通过脚本进行排序,指定某个值始终在第一个,其余的数据按照别的字段排序
* @throws IOException ioexception
*/
@Test
void searchAllToOrder() throws IOException {
// int searchText = 667;
// SearchResponse<Products> response = elasticsearchClient.search(s -> s
// // 我们要搜索的索引的名称
// .index("products")
// // 搜索请求的查询部分(搜索请求也可以有其他组件,如聚合)
// .query(q -> q.matchAll(matchAll -> matchAll))
// .size(100)
// .sort(sort ->
// sort.script(sortScript ->
// sortScript.type(ScriptSortType.Number)
// .order(SortOrder.Desc)
// .script(script ->
// script.inline(inline ->
// inline.source("if(params['_source']['counter'] == params.counter){\n" +
// " 1\n" +
// " } else {\n" +
// " 0\n" +
// " }")
// .params("counter",JsonData.of(searchText))
// )
// )
// )
// )
// .sort(sort -> sort.field(filed ->
// filed.field("counter").order(SortOrder.Asc))
// ),
// // 匹配文档的目标类
// Products.class
// );
// TotalHits total = response.hits().total();
// 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");
// }
//
// List<Hit<Products>> hits = response.hits().hits();
// for (Hit<Products> hit: hits) {
// Products products = hit.source();
// assert products != null;
// log.info("Found id " + products.getId() + ", counter " + products.getCounter());
// }
}
/**
* 转换字典值简单示例
*
* @throws IOException ioexception
*/
@Test
void convertDictionaryValues() throws IOException {
// SearchRequest request = SearchRequest.of(searchRequest ->
// searchRequest.index("users")
// .query(query -> query.matchAll(matchAll -> matchAll))
// // 不加这句,则 _source 不会返回,值返回 fields
// .source(config -> config.filter(filter -> filter.includes("*")))
// .scriptFields("age_format",field ->
// field.script(script ->
// script.inline(inline ->
// inline.lang(ScriptLanguage.Painless)
// .source(" // 判断 age 字段是否存在\n" +
// " if(doc['age'].size() == 0){\n" +
// " return \"--\";\n" +
// " }\n" +
// " \n" +
// " if(doc['age'].value < 20){\n" +
// " return \"青年\";\n" +
// " }else if(doc['age'].value < 40){\n" +
// " return \"中年\";\n" +
// " }else if(doc['age'].value == ''){\n" +
// " return \"未知\";\n" +
// " }else{\n" +
// " return \"**\";\n" +
// " }")
// )
// )
// )
// .size(100)
// );
// SearchResponse<User> response = elasticsearchClient.search(request, User.class);
// List<Hit<User>> hits = response.hits().hits();
// List<User> userList = new ArrayList<>(hits.size());
// for (Hit<User> hit: hits) {
// User user = hit.source();
// userList.add(user);
// log.info("user {}: age_format:{}",user.getName(),hit.fields().get("age_format"));
// }
// log.info(JSONUtil.toJsonStr(userList));
}
}
package com.example.elasticsearch;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
/**
* @version 1.0.0
* @className: SearchTest
* @description: 聚合查询测试
* @author: LiJunYi
* @create: 2022/8/8 11:04
*/
@SpringBootTest
@Slf4j
public class PartyTest
{
@Autowired
private ElasticsearchClient elasticsearchClient;
/**
* 获取最大年龄用户测试
*/
@Test
void getMaxAgeUserTest() throws IOException {
SearchResponse<Void> response = elasticsearchClient.search(b -> b
.index("users")
.size(0)
.aggregations("maxAge", a -> a
.max(MaxAggregation.of(s -> s
.field("age"))
)
),
Void.class
);
MaxAggregate maxAge = response.aggregations()
.get("maxAge")
.max();
log.info("maxAge.value:{}",maxAge.value());
}
/**
* 年龄分组测试
*
* @throws IOException ioexception
*/
@Test
void groupByAgeTest() throws IOException {
SearchResponse<Void> response = elasticsearchClient.search(b -> b
.index("users")
.size(0)
.aggregations("groupName", a -> a
.terms(TermsAggregation.of(s -> s
.field("age")))
),
Void.class
);
LongTermsAggregate longTermsAggregate = response.aggregations()
.get("groupName")
.lterms();
log.info("multiTermsAggregate:{}",longTermsAggregate.buckets());
}
/**
* 性别分组测试
*
* @throws IOException ioexception
*/
@Test
void groupBySexTest() throws IOException {
SearchResponse<Void> response = elasticsearchClient.search(b -> b
.index("users")
.size(0)
.aggregations("groupSex", a -> a
.terms(TermsAggregation.of(s -> s
.field("sex.keyword")))
),
Void.class
);
StringTermsAggregate stringTermsAggregate = response.aggregations()
.get("groupSex")
.sterms();
log.info("stringTermsAggregate:{}",stringTermsAggregate.buckets());
}
}
package com.example.elasticsearch;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import com.example.elasticsearch.model.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @version 1.0.0
* @className: DocTest
* @description: 文档操作测试
* @author: LiJunYi
* @create: 2022/8/8 10:19
*/
@SpringBootTest
@Slf4j
public class DocTest
{
@Autowired
private ElasticsearchClient elasticsearchClient;
/**
* 添加一个文档
* https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/8.3/indexing.html#indexing
* @throws IOException ioexception
*/
@Test
void addOneDocument () throws IOException
{
// 1、using the fluent DSL
User user = new User("1","王五",28,"男");
IndexResponse indexResponse = elasticsearchClient.index(s ->
// 索引
s.index("users")
// ID
.id(user.getId())
// 文档
.document(user)
);
log.info("result:{}",indexResponse.result().jsonValue());
// 2、You can also assign objects created with the DSL to variables. Java API Client classes have a static of() method for this, that creates an object with the DSL syntax.
IndexRequest<User> request = IndexRequest.of(i -> i
.index("users")
.id(user.getId())
.document(user));
IndexResponse response = elasticsearchClient.index(request);
log.info("Indexed with version " + response.version());
// 3、Using classic builders
IndexRequest.Builder<User> indexReqBuilder = new IndexRequest.Builder<>();
indexReqBuilder.index("users");
indexReqBuilder.id(user.getId());
indexReqBuilder.document(user);
IndexResponse responseTwo = elasticsearchClient.index(indexReqBuilder.build());
log.info("Indexed with version " + responseTwo.version());
}
/**
* 更新文档
*
* @throws IOException ioexception
*/
@Test
void updateDocument () throws IOException
{
// 构建需要修改的内容,这里使用了Map
Map<String, Object> map = new HashMap<>();
map.put("name", "liuyife");
// 构建修改文档的请求
UpdateResponse<Test> response = elasticsearchClient.update(e -> e
.index("users")
.id("33")
.doc(map),
Test.class
);
// 打印请求结果
log.info(String.valueOf(response.result()));
}
/**
* 批量添加文档
*
* @throws IOException ioexception
*/
@Test
void batchAddDocument () throws IOException
{
List<User> users = new ArrayList<>();
users.add(new User("1","赵四",20,"男"));
users.add(new User("2","阿旺",25,"男"));
users.add(new User("3","刘菲",22,"女"));
users.add(new User("4","冬梅",20,"女"));
List<BulkOperation> bulkOperations = new ArrayList<>();
users.forEach(u ->
bulkOperations.add(BulkOperation.of(b ->
b.index(
c ->
c.id(u.getId()).document(u)
)))
);
BulkResponse bulkResponse = elasticsearchClient.bulk(s -> s.index("users").operations(bulkOperations));
bulkResponse.items().forEach(i ->
log.info("i = {}" , i.result()));
log.error("bulkResponse.errors() = {}" , bulkResponse.errors());
// 2、use BulkRequest
BulkRequest.Builder br = new BulkRequest.Builder();
for (User user : users) {
br.operations(op -> op
.index(idx -> idx
.index("users")
.id(user.getId())
.document(user)));
}
BulkResponse result = elasticsearchClient.bulk(br.build());
// Log errors, if any
if (result.errors()) {
log.error("Bulk had errors");
for (BulkResponseItem item: result.items()) {
if (item.error() != null) {
log.error(item.error().reason());
}
}
}
}
/**
* 获取文档
* https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/8.3/reading.html#reading
* @throws IOException ioexception
*/
@Test
void getDocument () throws IOException
{
// co.elastic.clients.elasticsearch.core.get.GetResult<TDocument>
GetResponse<User> getResponse = elasticsearchClient.get(s -> s.index("users").id("e051445c-ae8c-47ef-ab18-97b34025d49a"),User.class);
log.info("getResponse:{}",getResponse.source());
// Reading a domain object
if (getResponse.found())
{
User user = getResponse.source();
assert user != null;
log.info("user name={}",user.getName());
}
// Reading raw JSON
// if (getResponse.found())
// {
// ObjectNode json = getResponse.source();
// String name = json.get("name").asText();
// log.info("Product name " + name);
// }
// 判断文档是否存在
BooleanResponse booleanResponse = elasticsearchClient.exists(s -> s.index("users").id("e051445c-ae8c-47ef-ab18-97b34025d49a"));
log.info("判断Document是否存在:{}",booleanResponse.value());
}
/**
* 删除文档
*
* @throws IOException ioexception
*/
@Test
void deleteDocument () throws IOException
{
DeleteResponse deleteResponse = elasticsearchClient.delete(s -> s.index("users").id("e051445c-ae8c-47ef-ab18-97b34025d49a"));
log.info("删除文档操作结果:{}",deleteResponse.result());
}
/**
* 批量删除文档
*
* @throws IOException ioexception
*/
@Test
void batchDeleteDocument () throws IOException
{
// 1、use BulkOperation
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
List<BulkOperation> bulkOperations = new ArrayList<>();
list.forEach(a ->
bulkOperations.add(BulkOperation.of(b ->
b.delete(c -> c.id(a))
))
);
BulkResponse bulkResponse = elasticsearchClient.bulk(a -> a.index("users").operations(bulkOperations));
bulkResponse.items().forEach(a ->
log.info("result = {}" , a.result()));
log.error("bulkResponse.errors() = {}" , bulkResponse.errors());
// 2、use BulkRequest
BulkRequest.Builder br = new BulkRequest.Builder();
for (String s : list) {
br.operations(op -> op
.delete(c -> c.id(s)));
}
BulkResponse bulkResponseTwo = elasticsearchClient.bulk(br.build());
bulkResponseTwo.items().forEach(a ->
log.info("result = {}" , a.result()));
log.error("bulkResponse.errors() = {}" , bulkResponseTwo.errors());
}
}