【发布时间】:2018-08-21 16:30:34
【问题描述】:
我有 Jenkins Job Pipeline Executions 的数据,我正在尝试根据数据中的开始和结束时间确定从开发到生产所需的平均持续时间。数据有点像事务数据库,其中 Dev 管道的执行是唯一记录,然后将同一管道执行到生产是另一个唯一记录(仅共享一个分组变量,即运行该作业的团队)。
这是我开始使用的数据示例:
job_id startTime endTime env_type Team_ID
1 100 8/4/2017 17:14:00 8/4/2017 17:16:00 DEV A
2 101 8/4/2017 17:20:00 8/4/2017 17:21:00 DEV A
3 102 8/4/2017 17:24:00 8/4/2017 17:27:00 DEV B
4 103 8/4/2017 17:38:00 8/4/2017 17:40:00 DEV B
5 104 8/4/2017 17:40:00 8/4/2017 17:42:00 DEV C
6 105 8/4/2017 17:51:00 8/4/2017 17:54:00 DEV C
在我第一次尝试开始扩展数据时,我使用 mutate 创建新列并根据 env_type 复制开始和结束时间:
df %>%
mutate(prod_job_id = ifelse(env_type == "PROD", job_id, ""),
prod_start_time = ifelse(env_type == "PROD", startTime, ""),
prod_end_time = ifelse(env_type == "PROD", endTime, ""),
dev_job_id = ifelse(env_type == "DEV", job_id, ""),
dev_start_time = ifelse(env_type == "DEV", startTime, ""),
dev_end_time = ifelse(env_type == "DEV", endTime, ""))
这让我得到了这样的结果(也使用 as.POSIXct 转换时间):
Team_ID env_type dev_start_time dev_end_time prod_start_time prod_end_time
1 A DEV 2018-08-01 12:00:00 2018-08-01 13:00:00 <NA> <NA>
2 A DEV 2018-08-02 12:00:00 2018-08-02 13:00:00 <NA> <NA>
3 A PROD <NA> <NA> 2018-08-02 14:00:00 2018-08-02 15:00:00
4 A PROD <NA> <NA> 2018-08-02 16:00:00 2018-08-02 17:00:00
5 B DEV 2018-08-01 12:00:00 2018-08-01 13:00:00 <NA> <NA>
6 B DEV 2018-08-02 12:00:00 2018-08-02 13:00:00 <NA> <NA>
7 B PROD <NA> <NA> 2018-08-02 16:00:00 2018-08-02 17:00:00
8 C DEV 2018-08-05 12:00:00 2018-08-05 13:00:00 <NA> <NA>
9 C DEV 2018-08-06 12:00:00 2018-08-06 13:00:00 <NA> <NA>
10 C TEST 2018-08-06 14:00:00 2018-08-06 15:00:00 <NA> <NA>
这是输出:
structure(list(Team_ID = structure(c(1L, 1L, 1L, 1L, 2L, 2L,
2L, 3L, 3L, 3L, 4L, 4L, 4L, 4L), .Label = c("A", "B", "C", "D"
), class = "factor"), pipeline_id = c(1000L, 1000L, 1000L, 1000L,
2000L, 2000L, 2000L, 3000L, 3000L, 3000L, 4000L, 4000L, 5000L,
5000L), env_type = structure(c(1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L,
1L, 3L, 1L, 1L, 2L, 2L), .Label = c("DEV", "PROD", "TEST"), class = "factor"),
dev_start_time = structure(c(1533142800, 1533229200, NA,
NA, 1533142800, 1533229200, NA, 1533488400, 1533574800, 1533582000,
1533142800, 1533229200, NA, NA), class = c("POSIXct", "POSIXt"
), tzone = ""), dev_end_time = structure(c(1533146400, 1533232800,
NA, NA, 1533146400, 1533232800, NA, 1533492000, 1533578400,
1533585600, 1533146400, 1533232800, NA, NA), class = c("POSIXct",
"POSIXt"), tzone = ""), prod_start_time = structure(c(NA,
NA, 1533236400, 1533243600, NA, NA, 1533243600, NA, NA, NA,
NA, NA, 1533236400, 1533243600), class = c("POSIXct", "POSIXt"
), tzone = ""), prod_end_time = structure(c(NA, NA, 1533240000,
1533247200, NA, NA, 1533247200, NA, NA, NA, NA, NA, 1533240000,
1533247200), class = c("POSIXct", "POSIXt"), tzone = "")), class = "data.frame", row.names = c(NA,
-14L))
棘手的部分是,管道可能会在进入 prod 之前多次进入 dev ,甚至可能在之后再次进入 prod 而无需返回 dev ,正如您在上面的数据框中看到的那样。
我试图弄清楚如何创建一个循环(或一系列 dplyr/purrr 命令或一些 *ply 函数)来对齐数据,以便我可以使用 diffTime 来获取部署持续时间。最终目标是获取从 dev 到 prod 的所有管道的 diffTimes,然后平均这个数字。 为了实现我的目标,我通过尝试将数据变成这样的方式来解决这个问题(在操作之后,env_type 将不再有效 - 但没关系,因为我只对 diffTime 感兴趣):
Team_ID env_type dev_start_time dev_end_time prod_start_time prod_end_time diffTime
1 A PROD 2018-08-01 12:00:00 2018-08-01 13:00:00 2018-08-02 14:00:00 2018-08-02 15:00:00 2678400
2 B PROD 2018-08-02 12:00:00 2018-08-02 13:00:00 2018-08-02 16:00:00 2018-08-02 17:00:00 18000
用英文,我想我需要的是这样的:
对于 env_type == "PROD" 的每一行,找到最接近 Dev 的时间戳,并用该值覆盖 Dev 列 - 类似于 max(dev_end_time,其中 dev_end_time 不大于 prod_start_time AND dev_end_time 大于prod_end_time 的先前值)。我知道数据需要按 Team_ID 分组并按顺序排列。我也知道我必须从查看 prod 管道开始,然后向后工作。
我是从这个开始的:
df %>%
group_by(Team_ID) %>%
arrange(Team_ID, startTime)
使数据按时间顺序分组和排列。但是我应该从这里去哪里?我首先认为 mutate 可能有效:
mutate(dev_start_time = ifelse((dev_end_time < prod_start_time) & (dev_end_time > prod_start_time -1)), dev_start_time, "") 但我不知道如何让 R 查看正确的行(prod_start_time -1 应该是 prod 的前一行,而不是时间 -1)。
我知道必须有某种方法可以做到这一点,但我只是不熟悉完成它的功能。
编辑:
对于@LetEpsilonBeLessThanZero 我试图通过 pipeline_id 了解该分组的要点,然后过滤具有至少 1 个 dev 和 1 个 prod 行的数据将删除有价值的数据。为了证明这一点,让我们看看下面的数据:
Team_ID pipeline_id env_type dev_start_time dev_end_time prod_start_time prod_end_time
1 A 1000 DEV 2018-08-01 12:00:00 2018-08-01 13:00:00 <NA> <NA>
2 A 1000 DEV 2018-08-02 12:00:00 2018-08-02 13:00:00 <NA> <NA>
3 A 1000 PROD <NA> <NA> 2018-08-02 14:00:00 2018-08-02 15:00:00
4 A 1000 PROD <NA> <NA> 2018-08-02 16:00:00 2018-08-02 17:00:00
5 B 2000 DEV 2018-08-01 12:00:00 2018-08-01 13:00:00 <NA> <NA>
6 B 2000 DEV 2018-08-02 12:00:00 2018-08-02 13:00:00 <NA> <NA>
7 B 2000 PROD <NA> <NA> 2018-08-02 16:00:00 2018-08-02 17:00:00
8 C 3000 DEV 2018-08-05 12:00:00 2018-08-05 13:00:00 <NA> <NA>
9 C 3000 DEV 2018-08-06 12:00:00 2018-08-06 13:00:00 <NA> <NA>
10 C 3000 TEST 2018-08-06 14:00:00 2018-08-06 15:00:00 <NA> <NA>
11 D 4000 DEV 2018-08-01 12:00:00 2018-08-01 13:00:00 <NA> <NA>
12 D 4000 DEV 2018-08-02 12:00:00 2018-08-02 13:00:00 <NA> <NA>
13 D 5000 PROD <NA> <NA> 2018-08-02 14:00:00 2018-08-02 15:00:00
14 D 5000 PROD <NA> <NA> 2018-08-02 16:00:00 2018-08-02 17:00:00
请注意团队 D 如何创建独特的 Dev 管道和独特的 Prod 管道。我仍然需要一种方法来链接它们并测量时间差,因为我知道部署用于同一个应用程序,但它不能按照你建议的方式通过在 pipeline_id 上分组来完成。
另一方面,我知道我们需要一种新的方式将这些团队组合在一起,以便更轻松地关联这些工作,并且现在有计划实现这一目标。但我仍然必须找到一种方法,以尽我所能利用我目前拥有的数据来获取这些数据,因此感谢所有帮助。
【问题讨论】:
-
您是否关心将 DEV 迭代分开,或者您是否可以将所有 DEV 时间合并到每个项目的单个单元中?
-
如果我正确理解您的问题,我认为我们需要将它们分开。原因是,每次都可能从 dev 到 prod 多次。
-
我认为您可以真正受益于唯一标识管道的“pipeline_id”字段。据我所知,您无法快速确定哪些行与哪些管道一起使用,这似乎将成为您前进的一个持续的荆棘。您实际上是在尝试对您当前未在数据集中收集的数据执行计算。话虽如此,如果最终目标是“确定从开发到生产所需的平均持续时间”,那么我们可以只取 DEV 行的平均开发时间吗?
-
@LetEpsilonBeLessThanZero ,为简单起见,我修剪了数据集。数据中实际上有一个 pipeline_id 值(这最初是我分组的变量,而不是 Team_ID)。我遇到的问题是,团队正在创建仅用于 Dev 或仅用于 Prod 等的管道。因此,对于某些团队,如果我要按 pipeline_id 分组,则只有 Dev 的日期和时间pipeline_id 或只有该 pipeline_id 的产品的日期和时间等。
-
我们可以轻松过滤掉至少没有一个 DEV 和至少一个 PROD 行的 pipeline_id。然后,我们可以按它们的 pipeline_id 对行进行分组,将它们的开发时间相加以获得每个 pipeline_id 的总开发时间,然后找到这些总开发时间量的平均值。这就是你想要达到的目标,是吗?如果您将 pipeline_id 字段添加到问题中的数据集,那么我可以快速让您编写代码来执行我刚才所说的操作。