Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.efficient.elasticsearch.service.ElasticSearchService Maven / Gradle / Ivy
package com.efficient.elasticsearch.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.efficient.common.page.Page;
import com.efficient.common.util.JackSonUtil;
import com.efficient.elasticsearch.entity.ElasticSearchRangeEntity;
import com.efficient.elasticsearch.entity.ElasticSearchRequestEntity;
import com.efficient.elasticsearch.entity.RangeEntity;
import com.efficient.elasticsearch.entity.ResponseEntity;
import com.efficient.elasticsearch.parser.SqlParser;
import com.efficient.elasticsearch.parser.TableNameParser;
import com.efficient.elasticsearch.properties.ElasticSearchProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.*;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentType;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* @author TMW
* @since 2024/5/15 10:06
*/
@Slf4j
public class ElasticSearchService implements Serializable {
private static final long serialVersionUID = -7686867207799800071L;
public RestHighLevelClient restHighLevelClient = null;
private String pkFieldName;
private Long maxBuckets;
private boolean dateToTimestamp = false;
private RestClient restClient = null;
private SqlParser sqlParser = null;
private ElasticSearchProperties properties;
/**
* 初始化
*/
public void init(ElasticSearchProperties elasticSearchProperties) {
this.properties = elasticSearchProperties;
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(properties.getUsername(), properties.getPassword()));
RestClientBuilder builder = RestClient.builder(new HttpHost(properties.getIp(), properties.getPort()))
.setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
.setDefaultCredentialsProvider(credentialsProvider)
.setMaxConnTotal(properties.getMaxConnectNum())
.setMaxConnPerRoute(properties.getMaxConnectPerRoute())
)
.setRequestConfigCallback(restClientBuilder -> {
restClientBuilder.setConnectTimeout(properties.getConnectTimeout());
restClientBuilder.setSocketTimeout(properties.getSocketTimeout());
restClientBuilder.setConnectionRequestTimeout(properties.getConnectionRequestTimeout());
return restClientBuilder;
});
restClient = builder.build();
restHighLevelClient = new RestHighLevelClient(builder);
sqlParser = new SqlParser(properties);
dateToTimestamp = properties.isDateToTimestamp();
pkFieldName = properties.getPkFieldName();
maxBuckets = properties.getMaxBuckets();
// 启用打印
if (elasticSearchProperties.isPrintDist()) {
Long printDistInterval = elasticSearchProperties.getPrintDistInterval();
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
try {
this.printDisk();
} catch (IOException e) {
log.error("监控ES服务器磁盘异常", e);
}
}, 0, printDistInterval, TimeUnit.SECONDS);
}
}
public void printDisk() throws IOException {
// 执行 Cat API 请求
Request request = new Request("GET", "/_cat/allocation?v=true&pretty");
Response response = restClient.performRequest(request);
if (response.getStatusLine().getStatusCode() != 200) {
log.warn("监控ES服务器磁盘请求失败");
}
// 解析响应并存储为 Map
Map resultMap = new HashMap<>();
try (Scanner scanner = new Scanner(response.getEntity().getContent())) {
String title = scanner.nextLine();
String value = scanner.nextLine();
if (!title.trim().isEmpty() && !title.startsWith("id")) { // 过滤掉标题行和空行
String[] parts = title.split("\\s+", 9); // 使用空格分割,限制为2个元素,以避免索引和值中可能存在的空格干扰
String[] values = value.split("\\s+", 10); // 使用空格分割,限制为2个元素,以避免索引和值中可能存在的空格干扰
for (int i = 0; i < parts.length; i++) {
resultMap.put(parts[i], values[i + 1]);
}
}
}
log.info("resultMap:{}", resultMap);
String diskUsed = resultMap.get("disk.used");
String diskAvail = resultMap.get("disk.avail");
String diskTotal = resultMap.get("disk.total");
double diskPercent = Double.parseDouble(resultMap.get("disk.percent"));
if (diskPercent < 80) {
log.info("磁盘空间已使用:{},占比:{}%", diskUsed, diskPercent);
} else if (diskPercent >= 95) {
log.error("磁盘空间已使用:{},占比:{}%,磁盘空间已超过95%,ElasticSearch 将不能写入数据,只能读取!", diskUsed, diskPercent);
} else {
log.warn("磁盘空间已使用:{},占比:{}%,磁盘空间一旦超过95%,ElasticSearch 将不能写入数据,只能读取!", diskUsed, diskPercent);
}
}
/**
* 注销
*/
public boolean destroy() {
try {
if (Objects.nonNull(restClient)) {
restClient.close();
}
if (Objects.nonNull(restHighLevelClient)) {
restHighLevelClient.close();
}
} catch (Exception e) {
log.error("关闭 restHighLevelClient 失败 ", e);
return false;
}
return true;
}
/**
* 创建索引
*
* 指标解释
*
* @param index 索引名称
* @return 是否成功
*/
public boolean createIndex(String index) throws IOException {
if (isIndexExist(index)) {
log.error("Index is exits!");
return false;
}
CreateIndexRequest request = new CreateIndexRequest(index);
request.settings(Settings.builder()
.put("number_of_shards", 1)
.put("number_of_replicas", 0)
// 关闭自动刷新,实时刷新会降低索引速度
// .put("refresh_interval ", 10)
.put("max_result_window", 20000000)
.build());
CreateIndexResponse response = restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
log.info("创建索引{}成功", index);
return response.isAcknowledged();
}
/**
* 判断索引是否存在
*
* @param index 索引名称
* @return 是否成功
*/
public boolean isIndexExist(String index) throws IOException {
GetIndexRequest request = new GetIndexRequest(index);
return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
}
/**
* 删除索引
*
* @param index 索引名称
* @return 是否成功
*/
public boolean deleteIndex(String index) throws IOException {
if (!isIndexExist(index)) {
log.error("Index is not exits!");
return false;
}
// 删除索引请求
DeleteIndexRequest request = new DeleteIndexRequest(index);
// 执行客户端请求
AcknowledgedResponse delete = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
log.info("删除索引{}成功", index);
return delete.isAcknowledged();
}
/**
* 保存
*
* @param index 索引名称
* @param data 数据集合
* @return 是否成功
*/
public boolean save(String index, Map data) {
if (Objects.isNull(data)) {
return false;
}
IndexRequest request = new IndexRequest(index);
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
formatMap(data);
request.source(data).opType(DocWriteRequest.OpType.INDEX);
final IndexResponse response;
try {
response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
final DocWriteResponse.Result result = response.getResult();
if (Objects.equals(result, DocWriteResponse.Result.UPDATED)) {
log.warn("新增文档已存在,默认执行了修改操作:" + JackSonUtil.toJson(data));
return true;
}
log.info("索引为: {}, 新增数据成功", index);
return Objects.equals(result, DocWriteResponse.Result.CREATED);
} catch (IOException e) {
log.error(index + " 批量保存失败", e);
return false;
}
}
/**
* 格式化 数据
*
* @param map 数据
* @return 格式化后数据
*/
private Map formatMap(Map map) {
map.keySet().forEach(key -> map.compute(key, (k, value) -> formatValue(value)));
return map;
}
private Object formatValue(Object value) {
if (Objects.isNull(value)) {
return null;
} else if (value instanceof java.sql.Date) {
final long dateLong = ((java.sql.Date) value).getTime();
if (dateToTimestamp) {
return processDateLong(dateLong);
}
return new Date(dateLong);
} else if (value instanceof java.sql.Timestamp) {
final long dateLong = ((java.sql.Timestamp) value).getTime();
if (dateToTimestamp) {
return processDateLong(dateLong);
}
return new Date(dateLong);
} else if (value instanceof Date) {
final Date date = (Date) value;
if (dateToTimestamp) {
return DateUtil.beginOfDay(date).getTime();
}
return date;
}
return value;
}
private Long processDateLong(long dateLong) {
return DateUtil.beginOfDay(new Date(dateLong)).getTime();
}
/**
* 保存
*
* @param index 索引名称
* @param data 数据集合
* @return 是否成功
*/
public boolean saveByPkField(String index, Map data) {
return saveByPkField(index, pkFieldName, data);
}
/**
* 保存
*
* @param index 索引名称
* @param data 数据集合
* @param pkFieldName 主键字段名称
* @return 是否成功
*/
public boolean saveByPkField(String index, String pkFieldName, Map data) {
if (Objects.isNull(data)) {
return false;
}
IndexRequest request = new IndexRequest(index);
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
formatMap(data);
request.source(data).opType(DocWriteRequest.OpType.INDEX);
if (StrUtil.isNotBlank(pkFieldName)) {
request.id(String.valueOf(data.get(pkFieldName)));
}
final String id = request.id();
final IndexResponse response;
try {
response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
final DocWriteResponse.Result result = response.getResult();
if (Objects.equals(result, DocWriteResponse.Result.UPDATED)) {
log.warn("新增文档已存在,默认执行了修改操作:" + JackSonUtil.toJson(data));
return true;
}
log.info("索引为: {}, id为: {} 新增数据成功", index, id);
return Objects.equals(result, DocWriteResponse.Result.CREATED);
} catch (IOException e) {
log.error(index + " 批量保存失败", e);
return false;
}
}
/**
* 批量保存
*
* @param index 索引名称
* @param recordList 数据集合
* @return 是否成功
*/
public boolean batchSaveWithRecord(String index, List> recordList) {
if (CollUtil.isEmpty(recordList)) {
return false;
}
BulkRequest request = new BulkRequest();
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
recordList.forEach(record -> request.add(new IndexRequest(index).source(record)));
final BulkResponse bulk;
try {
bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
return !bulk.hasFailures();
} catch (IOException e) {
log.error(index + " 批量保存失败", e);
return false;
}
}
/**
* 批量保存
*
* @param index 索引名称
* @param mapList 数据集合
* @return 是否成功
*/
public boolean batchSave(String index, List> mapList) {
if (CollUtil.isEmpty(mapList)) {
return false;
}
BulkRequest request = new BulkRequest();
mapList.forEach(record -> request.add(new IndexRequest(index).source(formatMap(record))));
final BulkResponse bulk;
try {
bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
return !bulk.hasFailures();
} catch (IOException e) {
log.error(index + " 批量保存失败", e);
return false;
}
}
/**
* 批量保存
*
* @param index 索引名称
* @param mapList 数据集合
* @return 是否成功
*/
public boolean batchSaveByPkField(String index, List> mapList) {
return batchSaveByPkField(index, pkFieldName, mapList);
}
/**
* 批量保存
*
* @param index 索引名称
* @param mapList 数据集合
* @param pkFieldName 主键字段名称
* @return 是否成功
*/
public boolean batchSaveByPkField(String index, String pkFieldName, List> mapList) {
if (CollUtil.isEmpty(mapList)) {
return false;
}
BulkRequest request = new BulkRequest();
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
mapList.forEach(map -> {
final IndexRequest indexRequest = new IndexRequest(index)
.source(formatMap(map));
if (StrUtil.isNotBlank(pkFieldName)) {
indexRequest.id(String.valueOf(map.get(pkFieldName)));
}
request.add(indexRequest);
});
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
final BulkResponse bulk;
try {
bulk = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
log.info("索引为: {}, 批量新增数据条数: {}, {}", index, mapList.size(), !bulk.hasFailures());
return !bulk.hasFailures();
} catch (IOException e) {
log.error(index + " 批量保存失败", e);
return false;
}
}
/**
* 根据条件修改数据
*
* @param index 索引
* @param pkFieldName 主键字段
* @param documentList 更新文档
* @return 更新条数
*/
public boolean batchUpdateByPkField(String index, String pkFieldName, List> documentList) {
if (CollUtil.isEmpty(documentList)) {
return false;
}
BulkRequest bulkRequest = new BulkRequest(index);
// 刷新策略
bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
for (Map map : documentList) {
formatMap(map);
bulkRequest.add(new UpdateRequest(index, String.valueOf(map.get(pkFieldName))).doc(map));
}
BulkResponse response;
try {
response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("索引为: {}, 批量修改数据数据量: {}, {}", index, documentList.size(), !response.hasFailures());
return !response.hasFailures();
} catch (IOException e) {
log.error(index + " 根据主键修改数据", e);
return false;
}
}
/**
* 根据条件修改数据
*
* @param index 索引
* @param query 查询条件
* @param document 更新文档
* @return 更新条数
* @throws Exception
*/
public long updateWithQuery(String index, QueryBuilder query, Map document) throws Exception {
if (Objects.isNull(document)) {
return 0L;
}
UpdateByQueryRequest updateByQueryRequest = new UpdateByQueryRequest(index);
updateByQueryRequest.setQuery(query);
formatMap(document);
StringBuilder script = new StringBuilder();
Set keys = document.keySet();
for (String key : keys) {
String appendValue = "";
Object value = formatValue(document.get(key));
if (value instanceof Number) {
appendValue = value.toString();
} else if (value instanceof String) {
appendValue = "'" + value + "'";
} else if (value instanceof List) {
appendValue = JackSonUtil.toJson(value);
} else {
appendValue = value.toString();
}
script.append("ctx._source.").append(key).append("=").append(appendValue).append(";");
}
updateByQueryRequest.setScript(new Script(script.toString()));
final BulkByScrollResponse bulkByScrollResponse = restHighLevelClient.updateByQuery(updateByQueryRequest, RequestOptions.DEFAULT);
return bulkByScrollResponse.getTotal();
}
/**
* 根据主键修改数据
*
* @param index 索引
* @param document 更新文档
* @return 更新条数
*/
public boolean updateByPkField(String index, Map document) {
return updateByPkField(index, pkFieldName, document);
}
/**
* 根据主键修改数据
*
* @param index 索引
* @param pkFieldName 文档主键名称
* @param document 更新文档
* @return 更新条数
*/
public boolean updateByPkField(String index, String pkFieldName, Map document) {
if (Objects.isNull(document)) {
return false;
}
final String id = String.valueOf(document.get(pkFieldName));
UpdateRequest updateRequest = new UpdateRequest(index, id);
// 刷新策略
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
formatMap(document);
updateRequest.doc(document);
final ActionListener listener = new ActionListener() {
@Override
public void onResponse(UpdateResponse updateResponse) {
log.info("索引为: {}, id为: {} 修改数据成功", index, id);
}
@Override
public void onFailure(Exception e) {
log.error("索引为: {}, id为: {} 修改数据失败, 异常信息: {}", index, id, e.getMessage());
}
};
restHighLevelClient.updateAsync(updateRequest, RequestOptions.DEFAULT, listener);
return true;
}
/**
* 根据主键修改数据
*
* @param index 索引
* @param id 文档主键
* @param document 更新文档
* @return 更新条数
*/
public boolean updateById(String index, String id, Map document) {
if (Objects.isNull(document)) {
return false;
}
UpdateRequest updateRequest = new UpdateRequest(index, id);
// 刷新策略
updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
formatMap(document);
updateRequest.doc(document);
final UpdateResponse response;
try {
response = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
log.info("索引为: {}, id为: {} 修改数据成功", index, id);
return Objects.equals(response.getResult(), DocWriteResponse.Result.UPDATED);
} catch (IOException e) {
log.error(index + " 根据主键修改数据", e);
return false;
}
}
/**
* 通过ID删除数据
*
* @param index 索引,类似数据库
* @param id 数据ID
*/
public boolean deleteDataById(String index, String id) {
try {
DeleteRequest request = new DeleteRequest(index, id);
// 刷新策略
request.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
restHighLevelClient.delete(request, RequestOptions.DEFAULT);
log.info("索引为: {}, id为: {} 删除数据成功", index, id);
return true;
} catch (IOException e) {
log.error("索引为: " + index + ", id为: " + id + " 删除数据失败", e);
return false;
}
}
/**
* 根据条件修改数据
*
* @param index 索引
* @param ids 主键字段集合
* @return 更新条数
*/
public boolean batchDelete(String index, List ids) {
BulkRequest bulkRequest = new BulkRequest(index);
// 刷新策略
bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
if (CollUtil.isEmpty(ids)) {
return true;
}
ids.forEach(id -> bulkRequest.add(new DeleteRequest(index, id)));
BulkResponse response;
try {
response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("索引为: {}, 批量删除数据条数: {} 成功", index, ids.size());
return !response.hasFailures();
} catch (IOException e) {
log.error(index + " 根据主键删除数据异常", e);
return false;
}
}
public ResponseEntity initTest() throws Exception {
log.info("EsPlugin Init Test ...");
Request request = new Request("POST", "/_sql?format=json");
final JSONObject jsonObject = new JSONObject();
jsonObject.put("query", "show tables");
jsonObject.put("fetch_size", 100);
final String json = jsonObject.toString();
request.setJsonEntity(json);
final Response response = restClient.performRequest(request);
final String resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return JackSonUtil.toObject(resultStr, ResponseEntity.class);
}
/**
* 查找当前最大桶数量
*
* @return 最大桶数量
* @throws Exception
*/
public Long findMaxBuckets() throws Exception {
Request request = new Request("GET", "/_cluster/settings");
final Response response = restClient.performRequest(request);
final String resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return JSONUtil.parseObj(resultStr).getByPath("persistent.search.max_buckets", Long.class);
}
/**
* 设置最大桶数量
*
* @param maxBuckets 最大桶数量
* @return 是否成功
* @throws Exception
*/
public boolean putMaxBuckets(Integer maxBuckets) throws Exception {
Request request = new Request("PUT", "/_cluster/settings");
final JSONObject json = new JSONObject();
final JSONObject jsonObject = new JSONObject();
jsonObject.set("search.max_buckets", maxBuckets);
json.set("persistent", jsonObject);
final String jsonStr = json.toString();
request.setJsonEntity(jsonStr);
final Response response = restClient.performRequest(request);
final String resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return JSONUtil.parseObj(resultStr).getByPath("acknowledged", Boolean.class);
}
/**
* 根据 sql 分页查询
*
* @param tableName 表名
* @param pageNum 当前页
* @param pageSize 每页数量
* @param sql sql语句
* @param includeFieldList 包含字段
* @return Page> 查询结果
*/
public Page> findPageBySql(String tableName, Integer pageNum, Integer pageSize, String sql, List includeFieldList) {
SearchResponse searchResponse = null;
try {
SearchSourceBuilder searchSourceBuilder = sqlParser.parse(sql);
/*
* 跟踪总点击量
* 该 trackTotalHits参数允许您控制应如何跟踪总命中数
* 设置为true搜索响应时,将始终准确跟踪与查询匹配的匹配数 反之返回命中数的下限10000
* 如果您不需要很准确的跟踪命中数 那么此处可设置为false,以便于加速搜索
*/
searchSourceBuilder.trackTotalHits(true);
searchSourceBuilder.from((pageNum - 1) * pageSize);
searchSourceBuilder.size(pageSize);
if (CollUtil.isNotEmpty(includeFieldList)) {
// 过滤字段
final FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includeFieldList.toArray(new String[]{}), Strings.EMPTY_ARRAY);
searchSourceBuilder.fetchSource(fetchSourceContext);
}
log.info("query dsl: " + searchSourceBuilder);
SearchRequest searchRequest = new SearchRequest(tableName);
searchRequest.source(searchSourceBuilder);
RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
builder.setHttpAsyncResponseConsumerFactory(
new HttpAsyncResponseConsumerFactory
.HeapBufferedResponseConsumerFactory(1000 * 1024 * 1024));
searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
} catch (Exception e) {
log.error("sql to dsl fail!", e);
}
// return searchResponse;
return this.responseToPage(pageNum, pageSize, searchResponse);
}
/**
* 转成分页数据
*
* @param pageNum 当前页
* @param pageSize 每页数
* @param searchResponse 查询结果
* @return 返回分页数据
*/
private Page> responseToPage(Integer pageNum, Integer pageSize, SearchResponse searchResponse) {
Page> recordPage = new Page<>(pageNum, pageSize, -1, null);
if (Objects.isNull(searchResponse)) {
return recordPage;
}
final SearchHits hits = searchResponse.getHits();
final int total = Math.toIntExact(hits.getTotalHits().value);
List> mapList = new ArrayList<>(pageSize);
Arrays.stream(hits.getHits()).forEach(hit -> mapList.add(hit.getSourceAsMap()));
recordPage.setPages(((total - 1) / pageSize));
recordPage.setTotal(total);
recordPage.setCurrent(pageNum);
recordPage.setCurrent(pageSize);
recordPage.setRecords(mapList);
return recordPage;
}
/**
* 根据 sql 语法查询数据
*
* @param sql sql 语句
* @return ResponseEntity 结果
*/
public ResponseEntity findBySql(String sql) {
Request request = new Request("POST", "/_sql?format=json");
final JSONObject jsonObject = new JSONObject();
jsonObject.put("query", sql);
jsonObject.put("fetch_size", maxBuckets);
final String json = jsonObject.toString();
request.setJsonEntity(json);
try {
final Response response = restClient.performRequest(request);
final String resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
return JackSonUtil.toObject(resultStr, ResponseEntity.class);
} catch (Exception e) {
log.error("执行查询语句失败:" + sql, e);
}
return ResponseEntity.EMPTY_OBJ;
}
/**
* 根据 sql 语法查询数据
*
* @param sql sql 语句
* @return 结果
* @see Elastic Count API
*/
public Number findCountBySql(String sql) {
// 添加索引 多个年度数据同时存在es单节点中时,不传表名会从全部文档中进行查询,造成数据重复
Collection tableList = new TableNameParser(sql).tables();
Optional optional = tableList.stream().findFirst();
String tableName = "";
if (optional.isPresent()) {
tableName = optional.get().replaceAll("\"", "");
}
// 通过CountRequest查询获得count
CountRequest countRequest = new CountRequest();
try {
SearchSourceBuilder searchSourceBuilder = sqlParser.parse(sql);
if (StrUtil.isNotBlank(tableName)) {
countRequest.indices(tableName);
}
countRequest.source(searchSourceBuilder);
CountResponse response = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
long count = response.getCount();
return new Long(count).intValue();
} catch (Exception e) {
log.error("执行查询语句失败:" + sql, e);
return 0;
}
}
private String processDateStr(long dateLong) {
return DateUtil.formatDate(new Date(dateLong));
}
private Date processDate(long dateLong) {
return DateUtil.beginOfDay(new Date(dateLong)).toJdkDate();
}
/**
* 通过ID获取数据
*
* @param index 索引,类似数据库
* @param id 数据ID
* @return 查询结果
*/
public Map findById(String index, String id) throws IOException {
return findById(index, id, null);
}
/**
* 通过ID获取数据
*
* @param index 索引,类似数据库
* @param id 数据ID
* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
* @return 查询结果
*/
public Map findById(String index, String id, String fields) throws IOException {
GetRequest request = new GetRequest(index, id);
if (StrUtil.isNotEmpty(fields)) {
// 只查询特定字段。如果需要查询所有字段则不设置该项。
request.fetchSourceContext(new FetchSourceContext(true, fields.split(","),
Strings.EMPTY_ARRAY));
}
GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
Map map = response.getSource();
// 为返回的数据添加id
map.put("_id", response.getId());
return map;
}
/**
* 获取索引名称
*
* @param indexName 索引名称
* @throws IOException
*/
public String getMappings(String indexName) throws IOException {
// 构建请求
GetMappingsRequest request = new GetMappingsRequest().indices(indexName);
// 使用RestHighLevelClient发起请求
GetMappingsResponse response = restHighLevelClient.indices().getMapping(request, RequestOptions.DEFAULT);
Map mappingMap = response.mappings();
MappingMetadata indexMapping = mappingMap.get(indexName);
Map mapping = indexMapping.sourceAsMap();
return JackSonUtil.toJson(mapping);
}
/**
* 创建 mappings
*
* https://www.cnblogs.com/xiaoyh/p/16061594.html
*
* @param indexName 索引名称
* @param mappings 映射
* @return 是否成功
* @throws IOException
*/
public boolean createMappings(String indexName, String mappings) throws IOException {
// 创建索引对象
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
// 设置参数
createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));
// 指定映射
createIndexRequest.mapping(mappings, XContentType.JSON);
// 额外参数
// 设置超时时间
createIndexRequest.setTimeout(TimeValue.timeValueMinutes(2));
// 设置主节点超时时间
createIndexRequest.setMasterTimeout(TimeValue.timeValueMinutes(1));
// 在创建索引API返回响应之前等待的活动分片副本的数量,以int形式表示
createIndexRequest.waitForActiveShards(ActiveShardCount.from(2));
createIndexRequest.waitForActiveShards(ActiveShardCount.DEFAULT);
// 执行创建索引库
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
// 得到响应(全部)
boolean acknowledged = createIndexResponse.isAcknowledged();
// 得到响应 指示是否在超时前为索引中的每个分片启动了所需数量的碎片副本
boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
return acknowledged;
}
/**
* 创建 mappings
*
* https://www.cnblogs.com/xiaoyh/p/16061594.html
*
* @param indexName 索引名称
* @param contentBuilder 映射
* @return 是否成功
* @throws IOException
*/
public boolean createMappings(String indexName, XContentBuilder contentBuilder) throws IOException {
// 创建索引对象
CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
// 设置参数
createIndexRequest.settings(Settings.builder().put("number_of_shards", "1").put("number_of_replicas", "0"));
// 指定映射
createIndexRequest.mapping(contentBuilder);
// 额外参数
// 设置超时时间
createIndexRequest.setTimeout(TimeValue.timeValueMinutes(2));
// 设置主节点超时时间
createIndexRequest.setMasterTimeout(TimeValue.timeValueMinutes(1));
// 在创建索引API返回响应之前等待的活动分片副本的数量,以int形式表示
createIndexRequest.waitForActiveShards(ActiveShardCount.from(2));
createIndexRequest.waitForActiveShards(ActiveShardCount.DEFAULT);
// 执行创建索引库
CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
// 得到响应(全部)
boolean acknowledged = createIndexResponse.isAcknowledged();
// 得到响应 指示是否在超时前为索引中的每个分片启动了所需数量的碎片副本
boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();
return acknowledged;
}
/**
* 修改索引mappings
*
* @param indexName 索引名称
* @param mappings 映射
* @return
* @throws IOException
*/
public boolean putMappings(String indexName, String mappings) throws IOException {
// 创建修改索引映射的请求
PutMappingRequest request = new PutMappingRequest(indexName)
.source(mappings, XContentType.JSON);
// 发送请求并获取响应
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);
return acknowledgedResponse.isAcknowledged();
}
/**
* 修改索引mappings
*
* @param indexName 索引名称
* @param contentBuilder 映射
* @return
* @throws IOException
*/
public boolean putMappings(String indexName, XContentBuilder contentBuilder) throws IOException {
// 创建修改索引映射的请求
PutMappingRequest request = new PutMappingRequest(indexName)
.source(contentBuilder);
// 发送请求并获取响应
AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().putMapping(request, RequestOptions.DEFAULT);
return acknowledgedResponse.isAcknowledged();
}
/**
* 根据列值查询数据
*
* @return ResponseEntity 结果
*/
public SearchResponse findByMultipleFields(List requestEntityList, String indexName, Integer pageSize) throws IOException {
// 构建查询
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
if (CollUtil.isNotEmpty(requestEntityList)) {
requestEntityList.forEach(et -> {
if (Objects.equals(et.getSearchType(), 2)) {
boolQueryBuilder.must(QueryBuilders.wildcardQuery(et.getKey(), et.getValue()));
} else {
boolQueryBuilder.must(QueryBuilders.matchQuery(et.getKey(), et.getValue()));
}
});
}
sourceBuilder.query(boolQueryBuilder);
// 设置文档返回大小 默认值是10
sourceBuilder.size(pageSize);
// 执行查询
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
}
/**
* 范围查找
*
* @param rangeEntityList
* @param requestEntityList
* @param indexName
* @return
*/
public SearchResponse findByRangeAndMatch(List rangeEntityList, List requestEntityList, String indexName, Integer pageSize) throws IOException {
// 构建查询
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
// 添加范围查询
if (CollUtil.isNotEmpty(rangeEntityList)) {
rangeEntityList.forEach(et -> {
RangeEntity rangeEntity = et.getRangeEntity();
boolQueryBuilder.must(QueryBuilders.rangeQuery(et.getKey())
.from(rangeEntity.getFrom())
.to(rangeEntity.getTo()));
});
}
// 添加单值匹配查询
if (CollUtil.isNotEmpty(requestEntityList)) {
requestEntityList.forEach(et -> {
if (Objects.equals(et.getSearchType(), 2)) {
boolQueryBuilder.must(QueryBuilders.wildcardQuery(et.getKey(), et.getValue()));
} else {
boolQueryBuilder.must(QueryBuilders.matchQuery(et.getKey(), et.getValue()));
}
});
}
sourceBuilder.query(boolQueryBuilder);
// 设置文档返回大小 默认值是10
sourceBuilder.size(pageSize);
// 执行查询
SearchRequest searchRequest = new SearchRequest(indexName);
searchRequest.source(sourceBuilder);
return restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
}
}