如何根据已保存搜索中的日期字段显示到期、过期和未到期

tv6aics1  于 2021-06-10  发布在  ElasticSearch
关注(0)|答案(2)|浏览(269)

例如,我有一个日期字段 delivery_datetime 在索引中,我必须向用户显示当前一天的某个包裹是今天到期还是过期或未到期
我不能创建一个单独的字段并重新编制索引,因为它是基于当前日期的,并且每天都在变化,例如,如果我必须在编制索引时进行计算,我必须每天重新编制索引,这是不可行的,因为我有很多数据。
我可以使用updatebyquery,但是我的索引经常通过python脚本更新,虽然这里没有acid属性,但是会有版本冲突。
就我所知,我认为我唯一的选择是使用脚本字段。
如果我必须用伪代码编写逻辑:

Due - delivery_datetime.dateOnly == now.dateOnly
Over Due - delivery_datetime.dateOnly < now.dateOnly
Not Due - delivery_datetime.dateOnly > now.dateOnly

我认为如果我生成csv,我有很多数据,我不希望脚本字段对集群性能产生重大影响。
所以我需要一些帮助来在脚本领域有效地做到这一点,或者如果有任何完全不同的解决方案也会非常有帮助。
如果脚本化字段是唯一的解决方案,则希望通过提供无痛脚本获得帮助。

qco9c6ql

qco9c6ql1#

一旦我们排除了文档升级/更新的可能性,基本上有两种方法: script_fields 或者 filter aggregations .
首先假设您的Map类似于:

{
  "mappings": {
    "properties": {
      "delivery_datetime": {
        "type": "object",
        "properties": {
          "dateOnly": {
            "type": "date",
            "format": "dd.MM.yyyy"
          }
        }
      }
    }
  }
}

现在,如果我们根据包的id过滤所有包,并想知道它处于哪个到期状态,我们可以创建3个脚本字段,如下所示:

GET parcels/_search
{
  "_source": "timeframe_*",
  "script_fields": {
    "timeframe_due": {
      "script": {
        "source": "doc['delivery_datetime.dateOnly'].value.dayOfMonth == params.nowDayOfMonth",
        "params": {
          "nowDayOfMonth": 8
        }
      }
    },
    "timeframe_overdue": {
      "script": {
        "source": "doc['delivery_datetime.dateOnly'].value.dayOfMonth < params.nowDayOfMonth",
        "params": {
          "nowDayOfMonth": 8
        }
      }
    },
    "timeframe_not_due": {
      "script": {
        "source": "doc['delivery_datetime.dateOnly'].value.dayOfMonth > params.nowDayOfMonth",
        "params": {
          "nowDayOfMonth": 8
        }
      }
    }
  }
}

它将返回以下内容:

...
"fields" : {
  "timeframe_due" : [
    true
  ],
  "timeframe_not_due" : [
    false
  ],
  "timeframe_overdue" : [
    false
  ]
}

这是琐碎的,日期数学有一个明显的弱点,这将在下面讨论。
或者,我们可以使用3个过滤器聚合,类似地只过滤出1个有问题的文档,如下所示:

GET parcels/_search
{
  "size": 0,
  "query": {
    "ids": {
      "values": [
        "my_id_thats_due_today"
      ]
    }
  },
  "aggs": {
    "due": {
      "filter": {
        "range": {
          "delivery_datetime.dateOnly": {
            "gte": "now/d",
            "lte": "now/d"
          }
        }
      }
    },
    "overdue": {
      "filter": {
        "range": {
          "delivery_datetime.dateOnly": {
            "lt": "now/d"
          }
        }
      }
    },
    "not_due": {
      "filter": {
        "range": {
          "delivery_datetime.dateOnly": {
            "gt": "now/d"
          }
        }
      }
    }
  }
}

顺从的

...
"aggregations" : {
  "overdue" : {
    "doc_count" : 0
  },
  "due" : {
    "doc_count" : 1
  },
  "not_due" : {
    "doc_count" : 0
  }
}

第二种方法的优点如下:
没有脚本参与->更快的执行。
更重要的是,你不必担心12月15日比11月20日晚,但是琐碎的月日比较会产生相反的结果。您可以在脚本中实现类似的东西,但是越复杂,执行速度就越差。
您可以放弃id筛选,在内部 Jmeter 板中使用这些聚合计数。甚至可能是一个客户 Jmeter 盘,但老客户很少有大量的包裹,这将是合理的聚合。

bt1cpqcv

bt1cpqcv2#

回答我自己的问题,以下是对我有效的方法。
脚本字段脚本:

def DiffMillis = 0;
if(!doc['delivery_datetime'].empty) {
    // Converting each to days, 1000*60*60*24 = 86400000
    DiffMillis = (new Date().getTime() / 86400000) - (doc['delivery_datetime'].value.getMillis() / 86400000);
}
doc['delivery_datetime'].empty ? "No Due Date": (DiffMillis==0?"Due": (DiffMillis>0?"Over Due":"Not Due") )

我特别使用了三元运算符,因为如果我使用 if else 那我得用 return ,如果我使用 return 我面对 search_phase_execution_exception 为脚本字段添加筛选器时。

相关问题