随着业务量的增加,以及其他厂商数据的对接整个,我们的数据量从每天gb到pb的增加,实现了千亿级别的经济方案。
疼点:Elasticsearch在新建索引都需要指定shard分片数,当索引数据量增加不好扩容,业务代码需要调整等等;
Elasticsearch中的API在针对特定索引时接受索引名称,并在适用时接受多个索引。索引别名API允许使用名称别名化索引,所有API都自动将别名转换为实际索引名称。别名也可以映射到多个索引,并且在指定别名时,别名将自动扩展为别名索引。别名还可以与在搜索和路由值时自动应用的过滤器相关联。别名不能与索引同名。
官方文档定义:
https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-aliases.html
1.数据增量横向扩展(我们每天的数据增量几十亿,以前老的架构每天需要建一个分区表,前期在别名使用不好的时候,评估3个月的数据存储量,建好索引,不太方便)。
2.每一个索引(三个月每天的索引的别名都使用同一个,查询方案,删除数据方案,主要是3个月以前的时间我们需要删除操作,使用java api的方式简直是没法做的)。
3.在一个集群中的数据非常好的对接到新的索引上面(我们在做数据迁移的时候,比如我们迁移率16年的数据到一个索引,17年的数据在一个索引,后面要做合并操作,有了别名就太方案)。
索引通过上面的方式很好的解决了我们数据扩容的问题,数据清除的问题。
1.创建索引
下面的代码我分别创建了 log2017,log2018,log2019三个索引,按照我们业务的划分,17,18,19年的数据会单独存放到对应的所有库中;
private static Logger log = Logger.getLogger(LogIndex.class);
//分别建log2017,log2018,log2019索引名
//索引名称
private static String indexName = "log2017";
//索引类型
private static String indexType = "t_log2017";
/**
* 创建标签mapping
* @return
*/
public static XContentBuilder createMapping() {
XContentBuilder mapping = null;
try {
mapping = XContentFactory.jsonBuilder().startObject()
// properties 声明字段
// string 类型 如果analyzed的话结果是text;如果not_analyzed的话结果是keyword
.startObject("properties")
.startObject("id").field("type", "string").field("index", "not_analyzed").endObject()
.startObject("name").field("type", "string").field("index", "not_analyzed").endObject()
.startObject("idCard").field("type", "string").field("index", "not_analyzed").endObject()
.startObject("createtime").field("type", "date").field("format","yyyy-MM-dd HH:mm:ss").field("index", "not_analyzed").endObject()
.startObject("LOCATION").field("type", "geo_point").endObject()
.endObject().endObject();
} catch (Exception e) {
e.printStackTrace();
}
return mapping;
}
2.分别倒入17,18,19三个索引库数据
/**
* 插入数据
* @throws Exception
*/
public static void insertTestDataEs() throws Exception {
String[] idCards = {"522121198568523581","522121198568523582","522121198568523583"};
List list = getDataList(size);
BulkRequestBuilder builder = trClient.prepareBulk();
for(LogModel logModel : list) {
XContentBuilder xContentBuilder = XContentFactory.jsonBuilder().startObject();
int index = (int) (Math.random()*idCards.length);
String idCard = idCards[index];
xContentBuilder.field("id", logModel.getId());
xContentBuilder.field("name", logModel.getName());
xContentBuilder.field("idCard", idCard);
xContentBuilder.field("createtime", logModel.getCreatetime());
xContentBuilder.endObject();
builder.add(trClient.prepareIndex(indexName, indexType).setSource(xContentBuilder));
}
BulkResponse bulkResponse = builder.execute().actionGet();
System.out.println(bulkResponse);
}
/**
* 生成数据
* @param szie
* @return
*/
public static List getDataList(int szie){
List list = new ArrayList();
String[] names = {"系统登录","数据查询","我的订单","我的消息","购买中心","信息查询","审批中心"};
for(int i = 0 ;i < szie ; i++) {
String id = UUID.randomUUID().toString().replaceAll("-", "");
int index = (int) (Math.random()*names.length);
String name = names[index];
String createtime = randomDate(startTime, endTime);
System.out.println(id + " " + name + " " + createtime + " ");
LogModel logModel = new LogModel();
logModel.setId(id);
logModel.setName(name);
logModel.setCreatetime(createtime);
list.add(logModel);
}
return list;
}
private static String randomDate(String beginDate,String endDate){
try {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date start = format.parse(beginDate);
Date end = format.parse(endDate);
if(start.getTime() >= end.getTime()){return null;}
long date = random(start.getTime(),end.getTime());
return format.format(new Date(date));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
private static long random(long begin, long end) {
long rtn = begin + (long)(Math.random() * (end - begin));
if(rtn == begin || rtn == end){
return random(begin,end);
}
return rtn;
}
3.分别给三个索引添加别名
trClient.admin().indices().prepareAliases().addAlias("log2017", "logAll").execute().actionGet();
trClient.admin().indices().prepareAliases().addAlias("log2018", "logAll").execute().actionGet();
trClient.admin().indices().prepareAliases().addAlias("log2019", "logAll").execute().actionGet();
4.我们通过别名logAll查询数据
我们通过idCard=522121198568523583查询三年的数据,查看下面的截图我们看见查询出来了,17/18/19年的数据,业务层面我们还使用geo_point帮助我们做地图分析,展示。
GET /logAll/_search
{
"query": {
"match": {
"idCard":"522121198568523583"
}
}
}
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 15,
"successful": 15,
"failed": 0
},
"hits": {
"total": 22,
"max_score": 1.1631508,
"hits": [
{
"_index": "log2019",
"_type": "t_log2019",
"_id": "AWiD9SM5BXRto4xedAgI",
"_score": 1.1631508,
"_source": {
"id": "c44e4f2d1d5b42af80cddc543dde4b08",
"name": "系统登录",
"idCard": "522121198568523583",
"createtime": "2018-01-25 08:25:55"
}
},
{
"_index": "log2019",
"_type": "t_log2019",
"_id": "AWiD9UlBXgDYyKQPhMWV",
"_score": 0.9808292,
"_source": {
"id": "3257512c2d2446b38643ec4584afe295",
"name": "我的消息",
"idCard": "522121198568523583",
"createtime": "2018-05-18 05:34:53"
}
},
{
"_index": "log2019",
"_type": "t_log2019",
"_id": "AWiD9Y6EBXRto4xedAgS",
"_score": 0.9808292,
"_source": {
"id": "bdc598477d454f73bdb5cc16e2fe34eb",
"name": "购买中心",
"idCard": "522121198568523583",
"createtime": "2017-08-29 16:21:10"
}
},
{
"_index": "log2019",
"_type": "t_log2019",
"_id": "AWiD9OXMXgDYyKQPhMWL",
"_score": 0.8266786,
"_source": {
"id": "1339d9ef87cd49aaa29359a021a7cb37",
"name": "我的消息",
"idCard": "522121198568523583",
"createtime": "2019-11-13 10:11:06"
}
}
]
}
}
详细代码见:https://github.com/444728248/elasticsearch-alias.git