R 3.4.1 - RSiteCatalyst 排队报告智能使用 while 循环

Posted

技术标签:

【中文标题】R 3.4.1 - RSiteCatalyst 排队报告智能使用 while 循环【英文标题】:R 3.4.1 - Intelligent use of while loop for RSiteCatalyst enqueued reports 【发布时间】:2018-02-26 20:11:54 【问题描述】:

实际

我现在使用RSiteCatalyst 包已经有一段时间了。对于那些不了解它的人,它使通过 API 从 Adob​​e Analytics 获取数据的过程变得更加容易。

到目前为止,工作流程如下:

    发出请求,例如:
    key_metrics <- QueueOvertime(clientId, dateFrom4, dateTo,
                   metrics = c("pageviews"), date.granularity = "month",
                   max.attempts = 500, interval.seconds = 20) 

    等待将保存为data.frame(示例结构)的响应:

    > View(head(key_metrics,1)) 
        datetime      name         year   month   day    pageviews 
      1 2015-07-01    July 2015    2015   7       1      45825
    

    做一些数据转换(例如:

    key_metrics$datetime &lt;- as.Date(key_metrics$datetime)

这个工作流程的问题是有时(由于请求的复杂性),我们可以等待很长时间直到响应最终到来。如果 R 脚本包含 40-50 个同样复杂的 API 请求,这意味着我们将等待 40-50 次,直到数据最终到来,我们才能发出新的请求。这显然在我的 ETL 过程中产生了引导。

目标

然而,在包的大部分函数中都有一个参数enqueueOnly,它告诉 Adob​​e 在传递报告 ID 作为响应的同时处理请求:

key_metrics <- QueueOvertime(clientId, dateFrom4, dateTo,
               metrics = c("pageviews"), date.granularity = "month",
               max.attempts = 500, interval.seconds = 20,
               enqueueOnly = TRUE)

> key_metrics
[1] 1154642436 

我可以随时使用以下函数获得“真实”响应(带有数据):

key_metrics <- GetReport(key_metrics)

在每个请求中,我添加参数enqueueOnly = TRUE,同时生成报告 ID 和报告名称列表:

queueFromIds <- c(queueFromIds, key_metrics)
queueFromNames <- c(queueFromNames, "key_metrics")

这种方法最重要的区别是我的所有请求都由 Adob​​e 同时处理,因此等待时间大大减少。

问题

但是,我在有效获取数据方面遇到了问题。我正在尝试使用while 循环,一旦获得数据,该循环就会从先前的向量中删除键 ID 和键名称:

while (length(queueFromNames)>0)

  assign(queueFromNames[1], GetReport(queueFromIds[1],
                                      max.attempts = 3,
                                      interval.seconds = 5))
  queueFromNames <- queueFromNames[-1]
  queueFromIds <- queueFromIds[-1]

但是,这仅适用于请求简单到可以在几秒钟内处理的情况。当请求复杂到无法在 3 次尝试中以 5 秒的间隔处理时,循环停止并出现以下错误:

ApiRequest 中的错误(body = toJSON(request.body), func.name = “Report.Get”,:错误:超过最大尝试次数 https://api3.omniture.com/admin/1.4/rest/?method=Report.Get

哪些函数可以帮助我控制所有 API 请求都得到正确处理,并且在最佳情况下,需要额外时间(它们会生成错误)的 API 请求会被跳过,直到循环结束,当他们再次被要求?

【问题讨论】:

我不知道r,但Adobe Reports API 本身有一个Report.GetQueue 方法,听起来它可能对您有用。它返回当前在 Adob​​e 队列中待处理的所有报告的列表(来自 API 调用)。因此,您可以对照您的报告 ID 列表检查该列表以查看它们何时完成(不在列表中 == 完成) 【参考方案1】:

我使用几个函数来独立生成/检索报告 ID。这样,处理报告所需的时间并不重要。我通常会在生成报告 ID 12 小时后回来接他们。我认为它们会在 48 小时左右后过期。这些功能当然依赖于 RSiteCatalyst。以下是函数:

#' Generate report IDs to be retrieved later
#'
#' @description This function works in tandem with other functions to programatically extract big datasets from Adobe Analytics.
#' @param suite Report suite ID.
#' @param dateBegin Start date in the following format: YYYY-MM-DD.
#' @param dateFinish End date in the following format: YYYY-MM-DD.
#' @param metrics Vector containing up to 30 required metrics IDs.
#' @param elements Vector containing element IDs.
#' @param classification Vector containing classification IDs.
#'@param valueStart Integer value pointing to row to start report with.
#' @return A data frame containing all the report IDs per day. They are required to obtain all trended reports during the specified time frame.
#' @examples
#' \dontrun
#' ReportsIDs <- reportsGenerator(suite,dateBegin,dateFinish,metrics, elements,classification)
#'
#' @export
    reportsGenerator <- function(suite,
                                 dateBegin,
                                 dateFinish,
                                 metrics,
                                 elements,
                                 classification,
                                 valueStart) 

      #Convert dates to date format.
      #Deduct one from dateBegin to
      #neutralize the initial +1 in the loop.

      dateBegin <-  as.Date(dateBegin, "%Y-%m-%d") - 1
      dateFinish <-  as.Date(dateFinish, "%Y-%m-%d")
      timeRange <- dateFinish - dateBegin

      #Create data frame to store dates and report IDs
      VisitorActivityReports <-
        data.frame(matrix(NA, nrow = timeRange, ncol = 2))
      names(VisitorActivityReports) <- c("Date", "ReportID")

      #Run a loop to retrieve one ReportID for each day in the time period.
      for (i in 1:timeRange) 
        dailyDate <- as.character(dateBegin + i)
        print(i) #Visibility to end user
        print(dailyDate) #Visibility to end user
        VisitorActivityReports[i, 1] <- dailyDate


        VisitorActivityReports[i, 2] <-
          RSiteCatalyst::QueueTrended(
            reportsuite.id = suite,
            date.from = dailyDate,
            date.to = dailyDate,
            metrics = metrics,
            elements = elements,
            classification = classification,
            top = 50000,
            max.attempts = 500,
            start = valueStart,
            enqueueOnly = T
          )
      
      return(VisitorActivityReports)
    

您应该将前一个函数的输出分配给一个变量。然后将该变量用作以下函数的输入。还将 reportsRetriever 的结果分配给一个变量。输出将是一个数据框。只要它们共享相同的结构,该函数就会将所有报告rbind在一起。不要尝试连接具有不同结构的报表。

#' Retrieve all reports stored as output of reportsGenerator function and consolidate them.
#'
#' @param dataFrameReports This is the output from reportsGenerator function. It MUST contain a column titled: ReportID
#' @details It is recommended to break the input data frame in chunks of 50 rows in order to prevent memory issues if the reports are too large. Otherwise the server or local computer might run out of memory.
#' @return A data frame containing all the consolidated reports defined by the reportsGenerator function.
#' @examples
#' \dontrun
#' visitorActivity <- reportsRetriever(dataFrameReports)
#'
#'
#' @export    

reportsRetriever <- function(dataFrameReports) 

      visitor.activity.list <- lapply(dataFrameReports$ReportID, tryCatch(GetReport))
      visitor.activity.df <- as.data.frame(do.call(rbind, visitor.activity.list))

      #Validate report integrity

      if (identical(as.character(unique(visitor.activity.df$datetime)), dataFrameReports$Date)) 
        print("Ok. All reports available")
        return(visitor.activity.df)
       else 
        print("Some reports may have been missed.")
        missingReportsIndex <- !(as.character(unique(visitor.activity.df$datetime)) %in% dataFrameReports$Date)

        return(visitor.activity.df)
      

    

【讨论】:

以上是关于R 3.4.1 - RSiteCatalyst 排队报告智能使用 while 循环的主要内容,如果未能解决你的问题,请参考以下文章

通过 R 运行 .vbs 脚本,在任务计划程序中安排

快排模板

2022下半年 Acwing 第一篇:快排模板

4002.基于快排思想的查找

快排模板

证明:有理数是可数的,而实数是不可数的。