如何在Elasticsearch聚合查询中过滤当前日期减去N天?

时间:2019-09-03 17:30:39

标签: elasticsearch

我正在尝试对Elasticsearch查询中的聚合结果使用过滤器。基本上,我有数百万个具有以下格式的文档:

{
  "useraccountid": 123456,
  "purchases_history" : {
    "last_updated" : "Sat Apr 27 13:41:46 UTC 2019",
    "purchases" : [
      {
        "purchase_id" : 19854284,
        "purchase_date" : "Jan 11, 2017 7:53:35 PM"
      },
      {
        "purchase_id" : 19854285,
        "purchase_date" : "Jan 12, 2017 7:53:35 PM"
      },
      {
        "purchase_id" : 19854286,
        "purchase_date" : "Jan 13, 2017 7:53:35 PM"
      }
    ]
  }
}

首先,我需要做一个SELECT useraccountid, max(purchases_history.purchases.purchase_date) FROM my_index GROUP BY useraccountid之类的事情,它是使用以下查询完成的,该查询还补充了一个管道过滤器以添加一个HAVING max(purchases_history.purchases.purchase_date) < getdate() - 365子句,所以我只得到那些文档(即用户帐户)最近一次购买超过一年。

GET my_personal_index/_search
{
  "aggs": {
    "buckets": {
      "composite": {
        "size": 1000,
        "sources": [
          {
            "user_account_id": {
              "terms": {
                "field": "useraccountid"
              }
            }
          }
        ]
      },
      "aggs": {
        "max_purchase_date": {
          "max": {
            "field": "purchases_history.purchases.purchase_date"
          }
        },
        "max_purchase_date_filter": {
          "bucket_selector": {
            "buckets_path": { 
              "maxPurchaseDate": "max_purchase_date" 
            },
            "script": {
              "lang": "painless",
              "source": "long now = new Date().getTime(); params.maxPurchaseDate < now - 365"
            }
          }
        }
      }
    }
  }
}

运行此查询时,没有收到任何错误或警告,但结果没有任何意义。我相信是因为执行"long now = new Date().getTime(); params.maxPurchaseDate < now - 365"时可能正在比较“香蕉和苹果”。因为我实际上不是程序员或技术人员,所以我不知道如何继续绕过并正确地过滤汇总日期。

这是日期容器块的映射:

"purchases_history": {
  "properties": {
    "purchases": {
      "purchase_date": {
        "type": "date",
        "format": "EEE MMM dd HH:mm:ss z yyyy||MMM d, yyyy HH:mm:ss a"
      },
      "purchase_id": {
        "type": "long"
      },
    }
  }
}

有什么建议吗?谢谢。

2 个答案:

答案 0 :(得分:1)

想到的最简单的方法是将脚本更改为

"source": "long now = new Date().getTime(); params.maxPurchaseDate > now - 365*86400000L"

其中每天86400000的毫秒数。

请注意,根据https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-datetime.html

  

现在的约会时间

     

在大多数无痛上下文中,当前日期时间,   现在,不支持。这有两个主要原因。的   首先是脚本通常每个文档运行一次,因此每次   脚本运行不同,现在返回。第二个是脚本   通常以分布式方式运行而没有适当的方式   现在同步。而是使用以下任一方法传递用户定义的参数   字符串日期时间或数字日期时间。数字日期时间是   首选,因为无需进行解析以进行比较。

更新

更多通用脚本:

long nowMillis = new Date().getTime();
Instant instant = Instant.ofEpochMilli(nowMillis);
ZonedDateTime now = ZonedDateTime.ofInstant(instant, ZoneId.of('Z')); // if you need zones
def limit = now.plusDays(-8);
return params.maxPurchaseDate > limit.toInstant().toEpochMilli();

Date currentDate = new Date();
Calendar c = Calendar.getInstance();
c.setTime(currentDate);
c.add(Calendar.DATE, -7);
return params.maxPurchaseDate > c.getTimeInMillis();

或其他一些Java解决方案也可以工作

答案 1 :(得分:0)

您尝试过Date Math吗?我用它来过滤索引名称,不确定是否也可以将它用于日期。检查一下:

https://www.elastic.co/guide/en/elasticsearch/reference/current/date-math-index-names.html