【问题标题】:How to display Due, Over Due and Not Due based on a date field in Saved Search如何根据已保存搜索中的日期字段显示到期、逾期和未到期
【发布时间】:2021-02-20 08:14:29
【问题描述】:

例如,我在索引中有一个日期字段delivery_datetime,我必须向用户显示当天的特定包裹是今天到期还是逾期或未到期

我不能创建一个单独的字段并重新索引,因为它基于当前日期并且每天都在变化,例如,如果我必须在索引时计算,我必须每天重新索引,这是不可行的,因为我有大量数据。

我可能会使用查询更新,但我的索引经常通过 Python 脚本更新,以为我们这里没有 ACID 属性,我们会遇到版本冲突。

据我所知,我认为我唯一的选择是使用脚本字段。

如果我必须用伪代码编写逻辑:

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

认为如果我生成 CSV 我有很多数据,我不希望脚本化字段对集群性能产生重大影响。

所以我需要一些帮助才能在脚本领域有效地做到这一点,或者如果有任何完全不同的解决方案也会非常有帮助。

如果脚本字段是唯一的解决方案,则通过提供无痛脚本来期待帮助。

【问题讨论】:

    标签: elasticsearch kibana elasticsearch-painless


    【解决方案1】:

    一旦我们排除了 doc upserts/updates,基本上有两种方法可以解决这个问题:script_fieldsfilter aggregations

    我们首先假设您的映射类似于:

    {
      "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
      }
    }
    

    现在第二种方法的优点如下:

    1. 不涉及脚本 -> 执行速度更快。

    2. 更重要的是,您不必担心像 12 月 15 日这样的月中日期计算会晚于 11 月 20 日,但微不足道的月中日期比较会产生其他结果。您可以在脚本中实现类似的功能,但更复杂的执行速度会更慢。

    3. 您可以放弃 ID 过滤并在内部仪表板中使用这些汇总计数。甚至可能是客户仪表板,但普通客户很少有大量可以合理汇总的包裹。

    【讨论】:

    • 感谢您的回复,我确实在 Kibana 数据表中使用过滤器聚合来显示到期/逾期/未到期的计数,就像您提到的那样,它的性能也非常好,但它对只计算。我必须在单个字符串字段中显示值 DueOver DueNot Due 向下钻取(已保存的搜索发现)。所以,脚本字段似乎是唯一的方法,我现在实现了,我会在社区的答案中发布它。
    【解决方案2】:

    回答我自己的问题,这对我有用。

    脚本化字段脚本:

    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 .

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-03
      • 1970-01-01
      • 2014-07-09
      • 2020-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多