Java Api Client 属于7.15后的新特性,用起来感觉比原来HighLevelRestClient要简化很多,而且更接近dsl语句。
我这里是某个特殊场景要用,资料不太多,只能自己摸索出的一点JAVA API Client使用方法,用作启发,作一些常用的操作应该没啥问题。
1、依赖
<dependency>
<groupId>co.elastic.clients</groupId>
<artifactId>elasticsearch-java</artifactId>
<version>7.17.6</version>
</dependency>
2、配置
这样配置,灵活一点
@ConfigurationProperties(prefix = "spring.elasticsearch.rest")
@Configuration
public class EsClientConfig {
/**
* 多个IP逗号隔开
*/
@Setter
private String uris;
/**
* 同步方式
*
* @return
*/
@Bean
public ElasticsearchClient elasticsearchClient() {
HttpHost[] httpHosts = toHttpHost();
// Create the RestClient
RestClient restClient = RestClient.builder(httpHosts).build();
// Create the transport with a Jackson mapper
RestClientTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
// create the API client
return new ElasticsearchClient(transport);
}
@Bean
public RestClient restClient() {
HttpHost[] httpHosts = toHttpHost();
// Create the RestClient
return RestClient.builder(httpHosts).build();
}
/**
* 解析配置的字符串hosts,转为HttpHost对象数组
*
* @return
*/
private HttpHost[] toHttpHost() {
if (!StringUtils.hasLength(uris)) {
throw new RuntimeException("invalid elasticsearch configuration. elasticsearch.rest.uris不能为空!");
}
// 多个IP逗号隔开
String[] hostArray = uris.split(",");
HttpHost[] httpHosts = new HttpHost[hostArray.length];
HttpHost httpHost;
for (int i = 0; i < hostArray.length; i++) {
String[] strings = hostArray[i].split(":");
httpHost = new HttpHost(strings[0], Integer.parseInt(strings[1]), "http");
httpHosts[i] = httpHost;
}
return httpHosts;
}
}
3、使用
我这里例子有runtime_mappings、有script,没那么通用,用作类比还是比较合适:
意思是查询出idaas_log-*索引中被修改过(_version>1)的记录。
原dsl语句
GET /_search?version=true
{
"runtime_mappings": {
"trusted": {
"type": "keyword",
"script": {
"source": "if (doc['_version'].value < 2 ) emit('0'); if (doc['_version'].value >= 2) emit('1');"
}
}
},
"fields": [
"trusted"
],
"query": {
"bool": {
"filter": [
{
"terms": {
"_index": [
"idaas_log-*"
]
}
},
{
"term": {
"trusted": "1"
}
}
]
}
},
"size": 10000
}
java实现
可以看到有很多java lambda 表达式写法
private final RestClient client;
private final ElasticsearchClient restClient;
private static final String TRUSTED = "trusted";
private static final String TRUSTED_VALUE = "1";
private static final String MATCH_INDEX = "_index";
private static final String FALSIFIED_SCRIPT = "if (doc['_version'].value < 2 ) emit('0'); if (doc['_version'].value >= 2) emit('1');";
//主要是这个方法,查询和上面dsl是完全一致的,看起来结构上是不是很类似
@Override
public List<FalsifiedData> queryFalsifiedDataList(List<String> indexList) throws BizException, IOException {
List<FieldValue> fieldValues = new ArrayList<>();
for (String s : indexList) {
fieldValues.add(FieldValue.of(s));
}
SearchRequest request = SearchRequest.of(s -> s
.runtimeMappings(TRUSTED, RuntimeField.of(f -> f
.type(RuntimeFieldType.Keyword)
.script(sc -> sc.inline(i -> i
.source(FALSIFIED_SCRIPT)))
))
.fields(fi -> fi.field(TRUSTED))
.query(q -> q
.bool(b -> b
.filter(f -> f
.terms(ts -> ts
.field(MATCH_INDEX)
.terms(tv -> tv.value(fieldValues))))
.filter(f -> f.term(t -> t.field(TRUSTED).value(TRUSTED_VALUE)))))
.size(10000));
SearchResponse<Map> response = restClient.search(request, Map.class);
//将查询结果解析并提取索引名,唯一id,数据内容
List<Hit<Map>> hits = response.hits().hits();
List<FalsifiedData> falsifiedDataList = new ArrayList<>();
for (Hit<Map> hit : hits) {
FalsifiedData falsifiedData = new FalsifiedData();
falsifiedData.setId(hit.id());
falsifiedData.setIndexName(hit.index());
if (Objects.nonNull(hit.source())) {
falsifiedData.setContent(hit.source().toString());
}
falsifiedDataList.add(falsifiedData);
}
tagFalsifiedData(falsifiedDataList);
return falsifiedDataList;
}
/**
* 同步给被修改的数据打上标记
*
* @param falsifiedDataList 已篡改日志记录
* @throws BizException 自定义异常
* @throws IOException IO异常
*/
public void tagFalsifiedData(List<FalsifiedData> falsifiedDataList) throws BizException {
if (CollectionUtils.isNotEmpty(falsifiedDataList)) {
for (FalsifiedData falsifiedData : falsifiedDataList) {
Map<String, Object> doc = new HashMap<>(4);
doc.put("integrity", "已篡改");
try {
restClient.update(builder -> builder
.index(falsifiedData.getIndexName())
.id(falsifiedData.getId()).doc(doc), Map.class);
} catch (Exception e) {
throw new BizException("elasticsearch更新数据(标记数据已篡改)异常");
}
}
}
}
}
普通curl命令的执行
如查询索引的几个基本属性
GET /_cat/indices/gw_audit-*?v&s=index&h=index,uuid,docs.count,docs.deleted
java实现
@Override
public List<IndexDocCountDto> queryDeletedData(List<String> indexList) throws BizException, IOException {
String str = indexList.get(0);
for (int i = 1; i < indexList.size(); i++) {
str = str.concat(",").concat(indexList.get(i));
}
Request request = new Request("GET", "/_cat/indices/".concat(str)
.concat("?s=index&h=index,uuid,docs.count,docs.deleted"));
Response response = null;
try {
response = client.performRequest(request);
} catch (Exception e) {
throw new BizException("elasticsearch日志查询异常");
}
HttpEntity entity = response.getEntity();
String resultString = EntityUtils.toString(entity);
//将查询得到的内容逐行解析,每行三个字段分别对应index、docCount、deletedCount
String[] lineStrings = resultString.split("\n");
List<IndexDocCountDto> docCountDtos = new ArrayList<>();
for (String s : lineStrings) {
String[] rowStrings = s.split("\\s+");
String index = rowStrings[0];
String esId = rowStrings[1];
String count = rowStrings[2];
String deletedCount = rowStrings[3];
IndexDocCountDto docCountDto = new IndexDocCountDto(
index, esId, Long.parseLong(count) + Long.parseLong(deletedCount), Long.valueOf(deletedCount));
docCountDtos.add(docCountDto);
}
return docCountDtos;
}