背景
公司有个需要将数据从mysql导入es,要求字段b如果为0,那么将该条数据方式索引index_a,否则放入index_b, 由于数据库中存储的时间格式为date,存入es时需要转换为时间戳。
数据量大概在亿级别,这边导入数据使用的是阿里的canal,canal文档不全,还有些已经过时,笔者踩了许多坑。总之慎用
解决方案
当时接到需求以为是不可能实现的(原谅我对es知之甚少),后来在浏览canal issues 时,#3604 有人提到将数据按月切分,其中clannad2000 提出使用es pipeline的处理方案。各位可以去看看原答案,此处将我的代码放出
es 按数据动态路由至索引
//创建脚本
PUT _ingest/pipeline/fmtbfield
{
"processors": [
{
"script": {
"source": "ctx._index=ctx.b==0?'indexa':'indexb'"
}
}
]
}
//创建主索引(这个索引没什么用,不会存数据,但是必须有)
PUT /index
{
"settings": {
"index.default_pipeline": "fmtbfield"
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"myTime": {
"type": "long"//这里使用date也行,能自由接收时间戳和yyyymmdd这种形式的时间
},
"b": {
"type": "text"
}
}
}
}
//向index插入一条数据
PUT /index/_doc/1
{
"id":1,
"b":0
}
//由于脚本存在,实际插入的索引位置为indexa
GET /indexa/_search
{
"query": {
"match_all": {}
}
}
插入时转换时间戳
这里转换为时间戳只是一个引子,假设你想加减乘除等等,对脚本而言都不在话下。
PUT _ingest/pipeline/fmtFieldToTime
{
"processors": [
{
"script": {
"lang": "painless",
"source": """
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse(ctx.myTime);
ctx.acctime = date.getTime();
"""
}
}
]
}
PUT /index_time
{
"settings": {
"final_pipeline" : "fmtFieldToTime"
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"myTime": {
"type": "long"//这里使用date也行,能自由接收时间戳和yyyymmdd这种形式的时间
},
"b": {
"type": "text"
}
}
}
}
PUT /index_time/_doc/1
{
"id":1,
"myTime":"2021-09-28 10:52:41"
}
查询时时间已经被转化成时间戳了