es如何通过两个字段差值进行查询?

576 阅读1分钟

参考铭毅天下ElasticStack B站视频,笔记记录

步骤1:构建索引

 PUT test-20221119-10
 {
   "mappings": {
     "properties": {
       "start_time": {
         "type": "date" 
       },
       "end_time": {
         "type": "date" 
       }
     }
   }
 }
 ​
 PUT test-20221119-10-02
 {
   "settings": {
     "default_pipeline": "mytx_20221119_10"
   },
   "mappings": {
     "properties": {
       "start_time": {
         "type": "date"
       },
       "end_time": {
         "type": "date"
       }
     }
   }
 }

步骤2:导入数据

 PUT test-20221119-10/_doc/1
 {
   "start_time": "2022-01-01T12:00:30Z",
   "end_time": "2022-01-01T12:15:30Z"
 } 
 ​
 PUT test-20221119-10-02/_doc/1
 {
   "start_time": "2022-01-01T12:00:30Z",
   "end_time": "2022-01-01T12:15:30Z"
 } 

步骤3:执行差值的方案

方案一:expression脚本实现

类似:TIMESTAMPDIFF方式实现
 POST test-20221119-10/_search
 {
   "query": {
     "bool": {
       "filter": {
         "script": {
           "script": {
             "source": "doc['end_time'].date.minuteOfDay - doc['start_time'].date.minuteOfDay >= 15",
             "lang": "expression"
           }
         }
       }
     }
   }
 }

方案二:painless脚本实现+ingest pipeline预处理实现

 PUT _ingest/pipeline/mytx_20221119_10
 {
   "processors": [
     {
       "script": {
         "lang": "painless",
         "source": """
         String start_data_time = ctx.start_time;
         ZonedDateTime start_zdt = ZonedDateTime.parse(start_data_time);
         long start_millis_date_time = start_zdt.toInstant().toEpochMilli();
         
         String end_data_time = ctx.end_time;
         ZonedDateTime end_zdt = ZonedDateTime.parse(end_data_time);
         long end_millis_date_time = end_zdt.toInstant().toEpochMilli();
         
         long lspan = (end_millis_date_time - start_millis_date_time)/1000/60;
         ctx.span = lspan;
         """
       }
     }
   ]
 }
 ​
 POST /test-20221119-10-02/_search
 {
   "query": {
     "range": {
       "span": {
         "gte": 15
       }
     }
   }
 }

方案三:runtime field类型实现

 POST test-20221119-10/_search
 {
   "fields": [
     "*"
   ], 
   "runtime_mappings": {
     "span_runtime": {
       "type": "long",
       "script": {
         "source": "emit((doc['end_time'].value.toInstant().toEpochMilli() - doc['start_time'].value.toInstant().toEpochMilli())/1000/60)"
       }
     }
   }
 }

小结

1.方案二 ingest + default pipeline

针对数据量大,追求检索效率

2.方案一、三

数据量小,简单实现,时间效率无要求