使用 Python DSL 在 Elasticsearch 中按日期范围过滤数据

Filter data by day range in Elasticsearch using Python DSL

我在下面写了这个方法来过滤最近 8 天的数据

def method_one(query) -> Query:
    gte = (datetime.datetime.now() - datetime.timedelta(days=query)).date()
    lt = (datetime.datetime.now()).date()
    print(gte, lt)
    return Q(MultiMatch(
        query=filter("range", {"lastModifiedDate": {"gte": gte, "lt": lt}}
                        ),
        fields=['lastModifiedDate']
    ))

我想通过在 Python 中形成 Elasticsearch Query 对象来基于 lastModifiedDate 字段过滤数据。 例如,如果我给 /lastModifiedDate=8(休息 API 调用),它应该 return 通过过滤最近 8 天的数据。

在 Elasticsearch 中构建日期查询不需要 datetime 模块——您可以使用 built-in date math:

from json import dumps
from elasticsearch_dsl.search import Search
from elasticsearch_dsl.query import Q, MultiMatch


def date_range_query(num_of_days):
    if not isinstance(num_of_days, int):
        raise Exception(
            'expected numeric & positive `num_of_days`, got `%s`' % str(num_of_days))

    return Q(
        "range",
        lastModifiedDate={
            "gte": "now-%dd" % num_of_days,
            "lt": "now"
        }
    )


try:
    q = date_range_query(8)
    print(dumps(q.to_dict(), indent=2))
except Exception as e:
    print(e)

哪个会打印

{
  "range": {
    "lastModifiedDate": {
      "gte": "now-8d",
      "lt": "now"
    }
  }
}

或者,如果您坚持使用datetime.date对象,您需要先将日期字符串化。现在,当您使用 str(...) 执行此操作时,您实际上是在调用 .__str()__ which then calls .isoformat() 和 returns 格式为 YYYY-MM-DD.

的字符串

现在,您的 lastModifiedDate 字段的映射可能具有不同的格式。因此,最好声明 range 查询的格式:

gte = (datetime.datetime.now() - datetime.timedelta(days=num_of_days)).date()
lt = (datetime.datetime.now()).date()

return Q(
    "range",
    lastModifiedDate={
        "gte": str(gte),
        "lt": str(lt),
        "format": "yyyy-MM-dd"  # keep in mind that the format in ES conforms to Java syntax, not python
    }
)

这会产生类似的查询,但具有具体的拼写日期:

{
  "range": {
    "lastModifiedDate": {
      "gte": "2021-02-26",
      "lt": "2021-03-06",
      "format": "yyyy-MM-dd"
    }
  }
}