最近需要部署elasticsearch(版本为6.4.0),存储一些日志信息。这里结合官网例子,使用提供的Java High Level REST Client API,自己编写了几个常见用例的工具类。废话不多说,下面是代码,不足之处请大家多多指教。
/**
* elasticSearh 操作类
* @author Stephen
* @version 1.0
* @date 2018/09/17 11:12:08
*/
public class ElasticClient implements Closeable {
private static final String INDEX_KEY = "index";
private static final String TYPE_KEY = "type";
private static final String INDEX = "spider";
private static final String TYPE = "doc";
private static final String TIMESTAMP = "timestamp";
private static final Logger LOGGER = LoggerFactory.getLogger(ElasticClient.class);
private String[] hosts;
protected RestHighLevelClient client;
public ElasticClient(String[] hosts) {
this.hosts = hosts;
}
@Override
public void close() throws IOException {
if (Objects.nonNull(client)) {
client.close();
}
}
/**
* 初始化配置
*/
public void configure() {
Validate.noNullElements(hosts, "Elastic连接地址不能为空!");
HttpHost[] httpHosts = Arrays.stream(hosts).map(host -> {
String[] hostParts = host.split(":");
String hostName = hostParts[0];
int port = Integer.parseInt(hostParts[1]);
return new HttpHost(hostName, port, Const.SCHEMA);
}).filter(Objects::nonNull).toArray(HttpHost[]::new);
client = new RestHighLevelClient(RestClient.builder(httpHosts));
}
/**
* 创建索引(默认分片数为5和副本数为1)
* @param indexName
* @throws IOException
*/
public void createIndex(String indexName) throws IOException {
if (checkIndexExists(indexName)) {
LOGGER.error("\"index={}\"索引已经存在!", indexName);
return;
}
CreateIndexRequest request = new CreateIndexRequest(indexName);
request.mapping(TYPE, generateBuilder());
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
// 指示是否所有节点都已确认请求
boolean acknowledged = response.isAcknowledged();
// 指示是否在超时之前为索引中的每个分片启动了必需的分片副本数
boolean shardsAcknowledged = response.isShardsAcknowledged();
if (acknowledged || shardsAcknowledged) {
LOGGER.info("创建索引成功!索引名称为{}", indexName);
}
}
/**
* 创建索引(指定 index 和 type)
* @param index
* @param type
* @throws IOException
*/
public void createIndex(String index, String type) throws IOException {
if (checkIndexExists(index)) {
LOGGER.error("\"index={}\"索引已存在!", index);
return;
}
CreateIndexRequest request = new CreateIndexRequest(index);
request.mapping(type, generateBuilder());
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
boolean acknowledged = response.isAcknowledged();
boolean shardsAcknowledged = response.isShardsAcknowledged();
if (acknowledged || shardsAcknowledged) {
LOGGER.info("索引创建成功!索引名称为{}", index);
}
}
/**
* 创建索引(传入参数:分片数、副本数)
* @param indexName
* @param shards
* @param replicas
* @throws IOException
*/
public void createIndex(String indexName, int shards, int replicas) throws IOException {
if (checkIndexExists(indexName)) {
LOGGER.error("\"index={}\"索引已存在!", indexName);
return;
}
Builder builder = Settings.builder().put("index.number_of_shards", shards).put("index.number_of_replicas", replicas);
CreateIndexRequest request = new CreateIndexRequest(indexName).settings(builder);
request.mapping(TYPE, generateBuilder());
CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
if (response.isAcknowledged() || response.isShardsAcknowledged()) {
LOGGER.info("创建索引成功!索引名称为{}", indexName);
}
}
/**
* 删除索引
* @param indexName
* @throws IOException
*/
public void deleteIndex(String indexName) throws IOException {
try {
DeleteIndexResponse response = client.indices().delete(new DeleteIndexRequest(indexName), RequestOptions.DEFAULT);
if (response.isAcknowledged()) {
LOGGER.info("{} 索引删除成功!", indexName);
}
} catch (ElasticsearchException ex) {
if (ex.status() == RestStatus.NOT_FOUND) {
LOGGER.error("{} 索引名不存在", indexName);
}
LOGGER.error("删除失败!");
}
}
/**
* 判断索引是否存在
* @param indexName
* @return
* @throws IOException
*/
public boolean checkIndexExists(String indexName) {
GetIndexRequest request = new GetIndexRequest().indices(indexName);
try {
return client.indices().exists(request, RequestOptions.DEFAULT);
} catch (IOException e) {
LOGGER.error("判断索引是否存在,操作异常!");
}
return false;
}
/**
* 开启索引
* @param indexName
* @throws IOException
*/
public void openIndex(String indexName) throws IOException{
if (!checkIndexExists(indexName)) {
LOGGER.error("索引不存在!");
return;
}
OpenIndexRequest request = new OpenIndexRequest(indexName);
OpenIndexResponse response = client.indices().open(request, RequestOptions.DEFAULT);
if (response.isAcknowledged() || response.isShardsAcknowledged()) {
LOGGER.info("{} 索引开启成功!", indexName);
}
}
/**
* 关闭索引
* @param indexName
* @throws IOException
*/
public void closeIndex(String indexName) throws IOException {
if (!checkIndexExists(indexName)) {
LOGGER.error("索引不存在!");
return;
}
CloseIndexRequest request = new CloseIndexRequest(indexName);
CloseIndexResponse response = client.indices().close(request, RequestOptions.DEFAULT);
if (response.isAcknowledged()) {
LOGGER.info("{} 索引已关闭!", indexName);
}
}
/**
* 设置文档的静态映射(主要是为 message字段 设置ik分词器)
* @param index
* @param type
* @throws IOException
*/
public void setFieldsMapping(String index, String type) {
PutMappingRequest request = new PutMappingRequest(index).type(type);
try {
request.source(generateBuilder());
PutMappingResponse response = client.indices().putMapping(request, RequestOptions.DEFAULT);
if (response.isAcknowledged()) {
LOGGER.info("已成功对\"index={}, type={}\"的文档设置类型映射!", index, type);
}
} catch (IOException e) {
LOGGER.error("\"index={}, type={}\"的文档设置类型映射失败,请检查参数!", index, type);
}
}
private XContentBuilder generateBuilder() throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.startObject("properties");
builder.startObject("message");
builder.field("type", "text");
// 为message字段,设置分词器为 ik_smart(最粗粒度)
builder.field("analyzer", "ik_smart");
builder.endObject();
builder.startObject(TIMESTAMP);
builder.field("type", "date");
// 设置 日志时间的格式为 毫秒数的long类型
builder.field("format", "epoch_millis");
builder.endObject();
builder.endObject();
builder.endObject();
return builder;
}
/**
* 增加文档
* @param indexName
* @param typeName
* @param id
* @param jsonStr
*/
public void addDocByJson(String indexName, String typeName, String id, String jsonString) throws IOException{
if (!JsonValidator.validate(jsonString)) {
LOGGER.error("非法的json字符串,操作失败!");
return;
}
if (!checkIndexExists(indexName)) {
createIndex(indexName, typeName);
}
IndexRequest request = new IndexRequest(indexName, typeName, id).source(jsonString, XContentType.JSON);
// request的opType默认是INDEX(传入相同id会覆盖原document,CREATE则会将旧的删除)
// request.opType(DocWriteRequest.OpType.CREATE)
IndexResponse response = null;
try {
response = client.index(request, RequestOptions.DEFAULT);
String index = response.getIndex();
String type = response.getType();
String documentId = response.getId();
if (response.getResult() == DocWriteResponse.Result.CREATED) {
LOGGER.info("新增文档成功! index: {}, type: {}, id: {}", index , type, documentId);
} else if (response.getResult() == DocWriteResponse.Result.UPDATED) {
LOGGER.info("修改文档成功! index: {}, type: {}, id: {}", index , type, documentId);
}
// 分片处理信息
ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
LOGGER.error("文档未写入全部分片副本!");
}
// 如果有分片副本失败,可以获得失败原因信息
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
LOGGER.error("副本失败原因:{}", reason);
}
}
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.CONFLICT) {
LOGGER.error("版本异常!");
}
LOGGER.error("文档新增失败!");
}
}
/**
* 查找文档
* @param index
* @param type
* @param id
* @return
* @throws IOException
*/
public Map getDocument(String index, String type, String id) throws IOException{
Map resultMap = new HashMap<>();
GetRequest request = new GetRequest(index, type, id);
// 实时(否)
request.realtime(false);
// 检索之前执行刷新(是)
request.refresh(true);
GetResponse response = null;
try {
response = client.get(request, RequestOptions.DEFAULT);
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.NOT_FOUND) {
LOGGER.error("文档未找到,请检查参数!" );
}
if (e.status() == RestStatus.CONFLICT) {
LOGGER.error("版本冲突!" );
}
LOGGER.error("查找失败!");
}
if(Objects.nonNull(response)) {
if (response.isExists()) { // 文档存在
resultMap = response.getSourceAsMap();
} else {
// 处理未找到文档的方案。 请注意,虽然返回的响应具有404状态代码,但仍返回有效的GetResponse而不是抛出异常。
// 此时此类响应不持有任何源文档,并且其isExists方法返回false。
LOGGER.error("文档未找到,请检查参数!" );
}
}
return resultMap;
}
/**
* 删除文档
* @param index
* @param type
* @param id
* @throws IOException
*/
public void deleteDocument(String index, String type, String id) throws IOException {
DeleteRequest request = new DeleteRequest(index, type, id);
DeleteResponse response = null;
try {
response = client.delete(request, RequestOptions.DEFAULT);
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.CONFLICT) {
LOGGER.error("版本冲突!" );
}
LOGGER.error("删除失败!");
}
if (Objects.nonNull(response)) {
if (response.getResult() == DocWriteResponse.Result.NOT_FOUND) {
LOGGER.error("不存在该文档,请检查参数!");
}
LOGGER.info("文档已删除!");
ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
LOGGER.error("部分分片副本未处理");
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
LOGGER.error("失败原因:{}", reason);
}
}
}
}
/**
* 通过一个脚本语句(如:"ctx._source.posttime=\"2018-09-18\"")更新文档
* @param index
* @param type
* @param id
* @param script
*/
public void updateDocByScript(String index, String type, String id, String script) throws IOException{
Script inline = new Script(script);
UpdateRequest request = new UpdateRequest(index, type, id).script(inline);
try {
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
if (response.getResult() == DocWriteResponse.Result.UPDATED) {
LOGGER.info("文档更新成功!");
} else if (response.getResult() == DocWriteResponse.Result.DELETED) {
LOGGER.error("\"index={},type={},id={}\"的文档已被删除,无法更新!", response.getIndex(), response.getType(), response.getId());
} else if(response.getResult() == DocWriteResponse.Result.NOOP) {
LOGGER.error("操作没有被执行!");
}
ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
LOGGER.error("部分分片副本未处理");
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
LOGGER.error("未处理原因:{}", reason);
}
}
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.NOT_FOUND) {
LOGGER.error("不存在这个文档,请检查参数!" );
} else if (e.status() == RestStatus.CONFLICT) {
LOGGER.error("版本冲突异常!" );
}
LOGGER.error("更新失败!");
}
}
/**
* 通过一个JSON字符串更新文档(如果该文档不存在,则根据参数创建这个文档)
* @param index
* @param type
* @param id
* @param jsonString
* @throws IOException
*/
public void updateDocByJson(String index, String type, String id, String jsonString) throws IOException {
if (!JsonValidator.validate(jsonString)) {
LOGGER.error("非法的json字符串,操作失败!");
return;
}
if (!checkIndexExists(index)) {
createIndex(index, type);
}
UpdateRequest request = new UpdateRequest(index, type, id);
request.doc(jsonString, XContentType.JSON);
// 如果要更新的文档不存在,则根据传入的参数新建一个文档
request.docAsUpsert(true);
try {
UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
String indexName = response.getIndex();
String typeName = response.getType();
String documentId = response.getId();
if (response.getResult() == DocWriteResponse.Result.CREATED) {
LOGGER.info("文档新增成功!index: {}, type: {}, id: {}", indexName, typeName, documentId);
} else if (response.getResult() == DocWriteResponse.Result.UPDATED) {
LOGGER.info("文档更新成功!");
} else if (response.getResult() == DocWriteResponse.Result.DELETED) {
LOGGER.error("\"index={},type={},id={}\"的文档已被删除,无法更新!", indexName, typeName, documentId);
} else if (response.getResult() == DocWriteResponse.Result.NOOP) {
LOGGER.error("操作没有被执行!");
}
ReplicationResponse.ShardInfo shardInfo = response.getShardInfo();
if (shardInfo.getTotal() != shardInfo.getSuccessful()) {
LOGGER.error("分片副本未全部处理");
}
if (shardInfo.getFailed() > 0) {
for (ReplicationResponse.ShardInfo.Failure failure : shardInfo.getFailures()) {
String reason = failure.reason();
LOGGER.error("未处理原因:{}", reason);
}
}
} catch (ElasticsearchException e) {
if (e.status() == RestStatus.NOT_FOUND) {
LOGGER.error("不存在这个文档,请检查参数!" );
} else if (e.status() == RestStatus.CONFLICT) {
LOGGER.error("版本冲突异常!" );
}
LOGGER.error("更新失败!");
}
}
/**
* 批量增加文档
* @param params
* @throws IOException
*/
public void bulkAdd(List