版本:ElasticSearch 8.2.3
文末有实测例子,本文为同步ES库与数据库中数据,有相同需求的朋友可以直接拿走
private ElasticsearchClient elasticsearchClient;
@Override
public void initialize() {
log.info("initElasticSearchClient ...");
RestClient restClient = RestClient.builder(
new HttpHost(GenomeApp.Config.ELASTIC_SEARCH_HOST, GenomeApp.Config.ELASTIC_SEARCH_PORT)).build();
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper());
elasticsearchClient = new ElasticsearchClient(transport);
log.info("initElasticSearchClient successfully");
}
public SearchResponse search(String index, String field, String searchText, Class targetClass) {
SearchResponse response = null;
try {
// 查询name=AAV的对象 参考链接:https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/searching.html
response = elasticsearchClient.search(s -> s
.index(index)
.query(q -> q.match(t -> t.field(field).query(searchText))),
targetClass);
}
catch (IOException e) {
e.printStackTrace();
}
return response;
}
/**
* 根据条件模糊匹配并返回记录信息
* @param index 领域资源名
* @param conditionMap 筛选条件
* @param targetClass 返回的对象类
* @param
* @return 符合筛选条件的记录
*/
public SearchResult searchResourceByCondition(String index, HashMap conditionMap, Class targetClass){
SearchResult result = new SearchResult();
SearchResponse response = null;
long totalSize = 0;
List objectList = new ArrayList<>();
// 是否模糊匹配,默认模糊查询
boolean isWildcardQuery = true;
if (conditionMap.containsKey("queryMode")) {
isWildcardQuery = conditionMap.get("queryMode").equals("wild");
conditionMap.remove("queryMode");
}
// 查询大小,默认为10000
int size = 10000;
if (conditionMap.containsKey("size")) {
size = Integer.parseInt(conditionMap.get("size"));
conditionMap.remove("size");
}
// 查询开始索引,默认为0
int from = 0;
if (conditionMap.containsKey("from")) {
from = Integer.parseInt(conditionMap.get("from"));
if (from >= 10000) {
result.setCode(-1);
result.setMessage("不支持查询10000以上的数据,请选择搜索条件,缩小查询范围!");
return result;
}
conditionMap.remove("from");
}
// 排序
List sortList = new ArrayList<>();
if(conditionMap.containsKey("sort")){
// 多个字段用","连接
String sortItems = conditionMap.get("sort");
String[] fieldItems = sortItems.split(",");
for(String fieldItem : fieldItems) {
// 字段和排序方式用"-"连接
sortList.add(fieldItem);
}
conditionMap.remove("sort");
} else {
// 没有条件,默认按第一个字段升序排列
for(String field:conditionMap.keySet()){
sortList.add(field+"-asc");
break;
}
}
BoolQuery.Builder builder = new BoolQuery.Builder();
for(String field:conditionMap.keySet()){
String value = conditionMap.get(field);
if(value.contains(",")){
// 多选
String[] values = value.split(",");
List multiQueryList = new ArrayList<>();
for(String val: values) {
if(isWildcardQuery) {
// 模糊匹配
multiQueryList.add(WildcardQuery.of(m -> m
.field(field)
.value("*"+val+"*")
)._toQuery());
} else {
// 精准匹配
multiQueryList.add(MatchQuery.of(m -> m
.field(field)
.query(val)
)._toQuery());
}
}
// 相同字段多选用or连接
BoolQuery orQuery = BoolQuery.of(o -> o.should(multiQueryList));
// 不同字段多选用must连接
builder.must(m->m.bool(orQuery));
} else{
// 单选
if(isWildcardQuery) {
// 模糊匹配
builder.must(WildcardQuery.of(m -> m
.field(field)
.value("*"+value+"*")
)._toQuery());
} else {
// 精准匹配
builder.must(MatchQuery.of(m -> m
.field(field)
.query(value)
)._toQuery());
}
}
}
BoolQuery queryES = builder.build();
// 拼装排序条件
List sortOptions = new ArrayList<>();
for(String fieldItem: sortList) {
String[] items = fieldItem.split("-");
SortOrder sortOrder = "asc".equals(items[1]) ? SortOrder.Asc : SortOrder.Desc;
SortOptions sortOption = SortOptions.of(s -> s.field(f -> f.field(items[0]).order(sortOrder)));
sortOptions.add(sortOption);
}
try {
totalSize = elasticsearchClient.count(s -> s
.index(index).query(q->q.bool(queryES))).count();
int finalSize = size;
int finalFrom = from;
response = elasticsearchClient.search(s -> s
.index(index)
.query(q->q.bool(queryES))
.from(finalFrom)
.size(finalSize)
.sort(sortOptions)
,
targetClass
);
List> hits = response.hits().hits();
for (Hit hit : hits) {
T object = hit.source();
objectList.add(object);
}
result.setCode(200);
result.setTotalSize(totalSize);
result.setResultList(objectList);
}
catch (Exception e) {
result.setCode(-1);
result.setMessage("查询失败,错误原因为:" + e.getMessage());
e.printStackTrace();
}
return result;
}
/**
* 创建索引:若索引存在,先删除再创建
*/
public void createIndex(String indexName, Map mappings) {
try {
//创建索引时创建文档类型映射
//创建索引
CreateIndexRequest createIndexRequest = CreateIndexRequest.of(e ->
e.index(indexName)
.mappings(m -> m.properties(mappings))
);
//先判断索引是否存在,存在则删除后再创建
BooleanResponse existRes = elasticsearchClient.indices().exists(ExistsRequest.of(e -> e.index(indexName)));
if (existRes.value()) {
deleteIndex(indexName);
}
CreateIndexResponse createIndexResponse = elasticsearchClient.indices().create(createIndexRequest);
if (createIndexResponse.acknowledged()) {
log.info(String.format("Index [%s] created", indexName));
}
}
catch (Exception e) {
log.info(String.format("Index [%s] creation fail", indexName) + e);
}
}
/**
* 删除索引
*
* @param indexName
* @return 成功 or 失败
* @throws IOException
*/
public boolean deleteIndex(String indexName) throws IOException {
DeleteIndexRequest deleteIndexRequest = DeleteIndexRequest.of(e -> e.index(indexName));
DeleteIndexResponse deleteRes = elasticsearchClient.indices().delete(deleteIndexRequest);
if (deleteRes.acknowledged()) {
log.info("索引:" + indexName + ",删除成功!");
}
return deleteRes.acknowledged();
}
本文使用反射获取第一个值来获得ID,各位要根据自己的id属性在对象中的位置来获取
/**
* 批量新建es数据
* @param list 数据对象
* @param name 索引名
* @param 数据对象类型
*/
public void createESData(List list, String name){
initialize();
List bulkOperations = new ArrayList<>();
try {
for (T object : list){
//通过反射获取Id属性
Field[] field = object.getClass().getDeclaredFields();
//设置对象的访问权限,保证对private的属性的访问
field[0].setAccessible(true);
String virusId = (String) field[0].get(object);
bulkOperations.add(new BulkOperation.Builder().create(d-> d.document(object).id(virusId).index(name)).build());
}// 使用bulk方法执行批量操作并获得响应
BulkResponse response = elasticsearchClient.bulk(e->e.index(name).operations(bulkOperations));
} catch (Exception e) {
e.printStackTrace();
}
}
直接传入对象的类和数据列表就可以,直接使用反射获取属性信息,防止手写mapping时出现问题
/**
* 更新es中信息
* @param clazz 类
* @param list 数据列表
* @param 数据类型
*/
public static void updateEs(ElasticSearchService elasticSearchService, Class clazz, List list, String indexName){
Map mappings = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//设置对象的访问权限,保证对private的属性的访问
field.setAccessible(true);
mappings.put(field.getName(), Property.of(p -> p.keyword(KeywordProperty.of(key -> key.nullValue(field.getName())))));
}
elasticSearchService.createIndex(indexName, mappings);
elasticSearchService.createESData(list, indexName);
}