【问题标题】:Store time related data in ElasticSearch在 ElasticSearch 中存储时间相关数据
【发布时间】:2021-02-15 04:43:59
【问题描述】:

我想在 ElasticSearch 中存储与时间相关的数据。 每个文档都有一个开始时间和一个结束时间,它们定义了它的相关时间(例如打开的工单)。 然后我希望能够运行以下查询:

  1. 显示 1 月 5 日至 2 月 2 日期间开放的所有门票。
  2. 在多个字段中显示在某个时间范围内打开的所有工单的构面

由于我将有每月索引,因此跨越一个月的文档将存储在多个索引中。
例如,在 1 月和 4 月之间打开的工单需要存储在所有 4 个月索引的索引中。
我想知道是否有一种简单的方法可以稍后在跨索引的聚合上运行,它会知道每张票只考虑一次(用于分面等)。

例如,如果我有以下票:

  1. 门票 A 在 2021 年 1 月 1 日至 2021 年 1 月 1 日之间开放
  2. 门票 B 在 15/1/2021-16/2/2021 之间开放
  3. 门票 C 于 2021 年 12 月 1 日至 2021 年 16 月 3 日之间开放

我们将有以下文件/索引:

Index January:  
  {id: A, StartDate: 1/1/2021, EndDate: 17/1/2021}
  {id: B, StartDate: 15/1/2021}
  {id: C, StartDate: 12/1/2021}
Index February:  
  {id: B, StartDate: 15/1/2021, EndDate: 16/2/2021}
  {id: C, StartDate: 12/1/2021}
Index March:  
  {id: C, StartDate: 12/1/2021, endDate: 16/3/2021}

欢迎任何与使用 ElasticSearch 实现此类事情的最佳方式相关的意见。 如果还有其他首选数据库可以用于具有高规模和快速聚合的工作,我也很乐意听到替代方案。

【问题讨论】:

  • 跨越多个月的文档看起来如何?另外,在未创建或关闭票证的月份(2 月、3 月)内,您会存储什么?
  • 添加了一些示例数据来回答您的问题。 @Joe Sorocin

标签: elasticsearch elasticsearch-aggregation


【解决方案1】:

如果满足两个这两个条件,这将非常简单:

  1. 每个文档都有一个 StartDate 值。
  2. 每个具有EndDate的文档都有一个StartDate

所以,如果我们设置一个 index template 涵盖我们所有未来的月度指数:

PUT _index_template/monthly-indices
{
  "index_patterns": [
    "index-2021-*"
  ],
  "template": {
    "mappings": {
      "properties": {
        "id": {
          "type": "keyword"
        },
        "StartDate": {
          "type": "date",
          "format": "d/M/yyyy"
        },
        "EndDate": {
          "type": "date",
          "format": "d/M/yyyy"
        }
      }
    }
  }
}

然后我们可以根据您的问题添加示例文档:

POST index-2021-01/_doc/A
{
  "id": "A",
  "StartDate": "1/1/2021",
  "EndDate": "17/1/2021"
}

POST index-2021-01/_doc/B
{
  "id": "B",
  "StartDate": "15/1/2021"
}

POST index-2021-02/_doc/B
{
  "id": "B",
  "StartDate": "15/1/2021",
  "EndDate": "16/2/2021"
}

POST index-2021-02/_doc/C
{
  "id": "C",
  "StartDate": "12/2/2021"
}

POST index-2021-03/_doc/C
{
  "id": "C",
  "StartDate": "12/2/2021",
  "EndDate": "16/3/2021"
}

之后,问题“2021 年 1 月 1 日至 2021 年 3 月 31 日之间有哪些门票开放?”然后可以通过以下方式回答:

POST index-2021-*/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "StartDate": {
              "gte": "1/1/2021"
            }
          }
        },
        {
          "range": {
            "EndDate": {
              "lte": "31/3/2021"
            }
          }
        }
      ]
    }
  }
}

它返回文档 ABC——但显然只有那些同时具有开始日期和结束日期的条目。

展望未来,可以使用scripted date_histogram 聚合构建一个简单的“方面”统计数据,表示“每月有多少张票打开”:

POST index-2021-*/_search
{
  "size": 0,
  "aggs": {
    "open_count_by_months": {
      "date_histogram": {
        "interval": "month",
        "format": "MMMM yyyy", 
        "script": """
          def start = doc['StartDate'].value;
          def end = doc['EndDate'].size() == 0 ? null : doc['EndDate'].value;
          
          if (end == null) {
            return start
          }
          
          return end
        """
      }
    }
  }
}

屈服

"aggregations" : {
  "open_count_by_months" : {
    "buckets" : [
      {
        "key_as_string" : "January 2021",
        "key" : 1609459200000,
        "doc_count" : 2
      },
      {
        "key_as_string" : "February 2021",
        "key" : 1612137600000,
        "doc_count" : 2
      },
      {
        "key_as_string" : "March 2021",
        "key" : 1614556800000,
        "doc_count" : 1
      }
    ]
  }
}

总结一下,如果您设法对跨多个索引“传播”的文档内容进行可靠控制,那就没问题了。

但是,如果您只是让 cronjob 每天同步工单并构建您的文档,使它们的行为类似于“宣布”当前工单状态的消息,即:

{
  "ticket_id": A,
  "status": "OPEN"
  "timestamp": 1613428738570
}

它会引入一些令人讨厌的复杂性,我在不久前讨论过 herehere

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-14
    • 2020-10-10
    • 2016-01-01
    • 2013-07-11
    • 1970-01-01
    • 2017-10-10
    相关资源
    最近更新 更多