一、ES的别名
为什么使用ES别名?
灵活的扩容。
动态的滚动查询。 例如“在不同的索引创建窗口”。
进行索引分组。
使用别名过滤器来屏蔽文档,他们可以对正在执行的查询自动地实施过滤。
结合别名和路由,在查询或索引的时候自动地使用路由值。
二、ES的分片
分片作用:
(1)、更好的分布式存储、扩展。
(2)、高效地平行查询。
副本的作用:
(1)、保证数据完整性,节点出现异常时,充当主分片。
(2)、优化查询效率,副本的数据和主分片一致,可以充分发挥查询时的效率。
集群索引出现创建、搜索慢,如何解决?
硬件上进行节点的增加;
重建索引,重新划分主副节点数量【可以使用别名来平滑的操作】;
三、ES的别名的增删改查
插入数据
插入数据时,按照“具体index”来插入数据,同时可以设置别名。
查询数据
根据id/其他属性去搜索“具体index”。—可以查询
根据“别名”来查询所有索引的数据。—可以查询
删除数据
根据“具体index”删除,deleteByQuery方式删除;—可以删除
根据“别名”删除,deleteByQuery方式删除;—可以删除
【----原因:根据条件查询到具体索引的记录,然后对查询到的数据按照“具体index”进行删除。】
根据“具体index”及主键id,先查询数据,然后“具体index”删除。—可以删除
根据“别名”及主键id,先查询数据,然后“具体index”删除。—可以删除
3.1、创建别名/分片的代码示例
public String getIndexName(String index, String type) {
if ("month".equals(type)) {
String yyyyMM = new SimpleDateFormat("yyyyMM").format(new Date());
return index + "-" + yyyyMM;
}
if ("quarter".equals(type)) {
return getQuarterFirstMonth(index);
}
if ("year".equals(type)) {
String yyyy = new SimpleDateFormat("yyyy").format(new Date());
return index + "-" + yyyy;
}
return "";
}
public String insert(T entity) throws Exception {
//确定当前ES的索引是否需要 按时间生成新的
String newIndexName = getIndexName(entity.getIndex(),"year"); //默认生成 todo
entity.setIndex(newIndexName);
//生成 n个分片+副分片、并生成别名
//例如 Index为test_file-2023,别名是test_file
String alias = entity.getIndex().substring(0,entity.getIndex().lastIndexOf("-"));
if(!checkIndexExist(newIndexName)){ //校验具体索引是否已经创建
createIndexWithAlias(newIndexName,alias); //创建有别名的索引,并进行分片
}
IndexRequest request = new IndexRequest(newIndexName);
request.id(entity.getId())
.source(JSONObject.toJSONString(entity), XContentType.JSON)
.create(false);
IndexResponse response = client.index(request, RequestOptions.DEFAULT);
String name = response == null ? null : response.getResult().name();
log.info("ES执行插入:index:{},type:{},id:{}", newIndexName, request.type(), request.id());
return name;
}
校验索引是否已经创建
public boolean checkIndexExist(String index) throws Exception {
GetIndexRequest getIndexRequest = new GetIndexRequest(index);
boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
if (exists) {
return true;
}
return false;
}
创建别名/分片。
public boolean createIndexWithAlias(String index,String alias) throws IOException {
CreateIndexRequest indexRequest = new CreateIndexRequest(index);
indexRequest.settings(Settings.builder()
.put("index.number_of_shards", 2)
.put("index.number_of_replicas", 1));
if(StringUtils.isNotBlank(alias)){
indexRequest.alias(new Alias(alias));
}
CreateIndexResponse response = client.indices().create(indexRequest, RequestOptions.DEFAULT);
return response.isAcknowledged();
}
3.2、CRUD代码示例
public Object testTransfer( Map<String, Object> itemMap){
List<String> dmcIds = (List<String>)itemMap.get("dmc_ids");
String scene = (String)itemMap.get("scene");
List<String> ids = (List<String>)itemMap.get("ids");
JSONObject testDoc = (JSONObject)itemMap.get("file_transfer");
TransferEsDo transferDoc = JSONObject.parseObject(JSON.toJSONString(testDoc),TransferEsDo.class);
/**
* 事先有别名 file_transfer_wwy ,索引有 file_transfer_wwy-2022、file_transfer_wwy-2023
*/
//ES分片的插入数据
if("1".equals(scene)){
try{
transferElasticRepository.insert(transferDoc);
}catch (Exception e){
log.error("testTransfer scene=1 ");
}
}
//从ES查询记录
if("2".equals(scene)){//根据实际Index查询或别名查询
BoolQueryBuilder boolBuilder = new BoolQueryBuilder();
if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(ids)){
BoolQueryBuilder idBuilder = new BoolQueryBuilder()
.must(QueryBuilders.termsQuery("_id",ids));
boolBuilder.should(idBuilder);
}
if(org.apache.commons.collections4.CollectionUtils.isNotEmpty(dmcIds)){
BoolQueryBuilder fileIdBuilder = new BoolQueryBuilder()
.must(QueryBuilders.termsQuery("file_id.keyword",dmcIds));
boolBuilder.should(fileIdBuilder);
}
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolBuilder);
searchSourceBuilder.from(0);
searchSourceBuilder.size(100);
SearchRequest searchRequest = new SearchRequest(transferDoc.getIndex());
searchRequest.source(searchSourceBuilder);
List<TransferEsDo> transferReList = new ArrayList<>();
try {
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
for (SearchHit searchHit : searchResponse.getHits()) {
transferReList.add(JSON.parseObject(searchHit.getSourceAsString(), TransferEsDo.class));
}
} catch (Exception e){
log.error("testTransfer dmcIds:{},ex:{}", JSON.toJSONString(dmcIds),e.getMessage());
}
}
if("3".equals(scene)){ //根据别名或实际index删除
DeleteByQueryRequest request = new DeleteByQueryRequest(transferDoc.getIndex());
request.setQuery(QueryBuilders.termsQuery("file_id.keyword",transferDoc.getFileId()));
try{
restHighLevelClient.deleteByQuery(request, RequestOptions.DEFAULT);
}catch (Exception e){
log.error("testTransfer fileId deleteByQuery ex:{}",e.getMessage());
return false;
}
}
if("4".equals(scene)){ //根据别名或实际index删除
try{
//还是根据id,index或别名获取到记录,然后按照实际的indexName和id进行删除
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termsQuery("id", Arrays.asList(transferDoc.getId())));
sourceBuilder.size(10000);
SearchRequest searchRequest = new SearchRequest(transferDoc.getIndex());
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
List<TransferEsDo> result = new ArrayList<>();
for (SearchHit hit : hits.getHits()) {
result.add(JSON.parseObject(JSON.toJSONString(hit.getSourceAsMap()), TransferEsDo.class));
}
DeleteRequest request = new DeleteRequest(result.get(0).getIndex(), result.get(0).getId());
DeleteResponse response = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
}catch (Exception e){
log.error("testTransfer fileId deleteByQuery ex:{}",e.getMessage());
return false;
}
}
return false;
}