概览

结构化数据文件 (SDF) 是采用特殊格式的逗号分隔值 (CSV) 文件,用于批量检索和更新 Display & Video 360 资源的相关数据。通过 Display & Video 360 API,您可以生成和下载自定义 SDF,从而检索经过整理的 Display & Video 360 资源上经过过滤的数据。

本指南介绍了如何创建 SDF 下载操作、跟踪该操作,以及如何下载生成的 SDF。

如需关于 SDF 格式和版本控制的信息,请参阅 SDF 参考文档

创建任务

SDF 由称为 sdfdownloadtask 的异步操作生成。创建此任务时,您可以定义与所需 SDF 相关的参数。这是通过 sdfdownloadtasks.create 方法完成的。以下小节介绍了您可以设置的参数。

指定版本

结构化数据文件格式会独立于 Display & Video 360 API 定期更新,并会定期弃用新版本和旧版本。因此,始终建议用户使用最新版本的 SDF

您可以使用请求正文中的 version 字段设置所需 SDF 的 SDF 版本。如果此政策未设置或设为 SDF_VERSION_UNSPECIFIED,任务将使用广告主或合作伙伴资源的默认 SDF 版本(用作 SDF 内容上下文)。

设定背景

您可以生成包含任何可用资源相关数据的 SDF,但任何单个 SDF 都只能在单个合作伙伴或广告主环境中返回内容。此上下文由 partnerIdadvertiserId 字段在请求正文中定义。这两个字段中必须设置且只能设置一个。

生成的 SDF 中只会包含给定上下文中的资源。如果您尝试按不归指定合作伙伴或广告主所有的资源进行过滤,结果将不包含该资源及其下的内容。如果仅按这些未包含的资源进行过滤,则生成的文件将为空。如果尝试按给定上下文之外的资源进行过滤,系统不会返回错误,因此请务必检查您的上下文是否正确。

选择合适的过滤条件

除了上面设置的上下文之外,您还可以指定要生成的文件类型以及要包含的特定资源或资源系列,从而进一步过滤所生成结构化数据文件的范围。

sdfdownloadtask 有三个可用的过滤器,每个过滤器可满足特定的规范类型。您只能为一个 sdfdownloadtask 分配一个。

ParentEntityFilter

ParentEntityFilter 是可用过滤器中范围最广的。

使用 fileType 字段,您可以列出希望在任务中生成的所有需要的文件类型。这是必填字段,如果留空或设置为 FILE_TYPE_UNSPECIFIED,您的 sdfdownloadtask 将错误地完成。

使用 filterTypefilterIds 字段,您可以进一步优化结果。filterType 指定要过滤的资源类型filterIds 按资源的唯一 ID 识别这些资源。生成的 SDF 将包含由 fileType 标识的资源,这些资源可以是通过 filterTypefilterIds 标识的资源的资源或子项。

IdFilter

IdFilter 过滤您的请求,以便仅包含识别出的资源。

IdFilter 中,每种 SDF 类型(不包括广告资源来源)都有一个对应的字段。其中每个字段都是一个唯一 ID 列表,用于标识您希望包含在生成的 SDF 中的特定资源。提供的 ID 必须在上下文集中,但它们不必直接相关。您无需请求特定的广告系列即可请求其中包含的订单项,反之亦然。仅生成与 IdFilter 中标识的资源对应的文件类型。

InventorySourceFilter

InventorySourceFilter 仅允许过滤和下载包含广告资源来源资源的 SDF。您只能使用该过滤条件来获取广告资源来源资源的相关信息。

InventorySourceFilter 具有单个 inventorySourceIds 字段,您可在其中标识要添加到 SDF 中的广告资源来源资源的唯一 ID。如果提供给 inventorySourceIds 的列表为空,则设置的上下文下的所有商品目录来源都将包含在生成的 SDF 中。

发出请求

知道所需 SDF 的参数后,您可以构建请求并创建 sdfdownloadtask

以下示例展示了如何使用 ParentEntityFilter 创建 sdfdownloadtask

Java

// Create the filter structure
ParentEntityFilter parentEntityFilter = new ParentEntityFilter();
parentEntityFilter.setFileType(sdf-file-type-list);
parentEntityFilter.setFilterType(sdfFilterType);
parentEntityFilter.setFilterIds(filter-id-list);

// Configure the sdfdownloadtasks.create request
Sdfdownloadtasks.Create request =
   service
       .sdfdownloadtasks()
       .create(
           new CreateSdfDownloadTaskRequest()
               .setVersion(sdfVersion)
               .setAdvertiserId(advertiserId)
               .setParentEntityFilter(parentEntityFilter)
       );

// Create the sdfdownloadtask
Operation operationResponse = request.execute();

System.out.printf("Operation %s was created.\n",
   operationResponse.getName());

Python

# Configure the sdfdownloadtasks.create request
createSdfDownloadTaskRequest = {
    'version': sdf-version,
    'advertiserId': advertiser-id,
    'parentEntityFilter': {
        'fileType': sdf-file-type-list,
        'filterType': sdf-filter-type,
        'filterIds': filter-id-list
    }
}

# Create the sdfdownloadtask
operation = service.sdfdownloadtasks().create(
    body=createSdfDownloadTaskRequest).execute();

print("Operation %s was created." % operation["name"])

PHP

// Create the sdfdownloadtasks.create request structure
$createSdfDownloadTaskRequest =
    new Google_Service_DisplayVideo_CreateSdfDownloadTaskRequest();
$createSdfDownloadTaskRequest->setAdvertiserId(advertiser-id);
$createSdfDownloadTaskRequest->setVersion(sdf-version);

// Create and set the parent entity filter
$parentEntityFilter = new Google_Service_DisplayVideo_ParentEntityFilter();
$parentEntityFilter->setFileType(sdf-file-type-list);
$parentEntityFilter->setFilterType(sdf-filter-type);
if (!empty(filter-id-list)) {
    $parentEntityFilter->setFilterIds(filter-id-list);
}
$createSdfDownloadTaskRequest->setParentEntityFilter($parentEntityFilter);

// Call the API, creating the SDF Download Task.
$operation = $this->service->sdfdownloadtasks->create(
    $createSdfDownloadTaskRequest
);

printf('Operation %s was created.\n', $operation->getName());

检查您的请求并获取下载路径

当您创建 sdfdownloadtask 时,会返回一个 operation 对象。此操作表示异步 SDF 生成操作在创建时的状态。您可以使用 sdfdownloadtasks.operations.get 方法检查操作,确认其是否已完成并可供下载,或是否已抛出错误。

完成后,返回的操作将具有非 null done 字段。完成的操作将包含 responseerror 字段。如果存在,则 error 字段将包含一个 Status 对象,该对象包含错误代码和提供所发生错误的详细信息消息。如果存在 response 字段,则该字段将包含一个具有 resourceName 值的对象,用于标识生成的可供下载的文件。

以下示例展示了如何使用指数退避算法检查您的请求:

Java

String operationName = operationResponse.getName();

// Configure the Operations.get request
Sdfdownloadtasks.Operations.Get operationRequest =
   service
       .sdfdownloadtasks()
       .operations()
       .get(operationName);

// Configure exponential backoff for checking the status of our operation
ExponentialBackOff backOff = new ExponentialBackOff.Builder()
   .setInitialIntervalMillis(5000) // setting initial interval to five seconds
   .setMaxIntervalMillis(300000)  // setting max interval to five minutes
   .setMaxElapsedTimeMillis(18000000) // setting max elapsed time to five hours
   .build();

while (operationResponse.getDone() == null) {
 long backoffMillis = backOff.nextBackOffMillis();
 if (backoffMillis == ExponentialBackOff.STOP) {
   System.out.printf("The operation has taken more than five hours to
       complete.\n");
   return;
 }
 Thread.sleep(backoffMillis);

 // Get current status of operation
 operationResponse = operationRequest.execute();
}

// Check if the operation finished with an error and return
if (operationResponse.getError() != null) {
 System.out.printf("The operation finished in error with code %s: %s\n",
     operationResponse.getError().getCode(), operationResponse.getError()
         .getMessage());
 return;
}

System.out.printf(
    "The operation completed successfully. Resource %s was created.\n",
    operationResponse.getResponse().get("resourceName").toString());

Python

# The following values control retry behavior while
# the report is processing.
# Minimum amount of time between polling requests. Defaults to 5 seconds.
min_retry_interval = 5
# Maximum amount of time between polling requests. Defaults to 5 minutes.
max_retry_interval = 5 * 60
# Maximum amount of time to spend polling. Defaults to 5 hours.
max_retry_elapsed_time = 5 * 60 * 60

# Configure the Operations.get request
get_request = service.sdfdownloadtasks().operations().get(
  name=operation["name"]
)

sleep = 0
start_time = time.time()
while True:
  # Get current status of operation
  operation = get_request.execute()

  if "done" in operation:
    if "error" in operation:
      print("The operation finished in error with code %s: %s" % (
            operation["error"]["code"],
            operation["error"]["message"]))
    else:
      print("The operation completed successfully. Resource %s was created."
            % operation["response"]["resourceName"])
    break
  elif time.time() - start_time > max_retry_elapsed_time:
    print("Generation deadline exceeded.")

  sleep = next_sleep_interval(sleep)
  print("Operation still running, sleeping for %d seconds." % sleep)
  time.sleep(sleep)

def next_sleep_interval(previous_sleep_interval):
  """Calculates the next sleep interval based on the previous."""
  min_interval = previous_sleep_interval or min_retry_interval
  max_interval = previous_sleep_interval * 3 or min_retry_interval
  return min(max_retry_interval, random.randint(min_interval, max_interval))

PHP

// The following values control retry behavior
// while the task is processing.
// Minimum amount of time between polling requests. Defaults to 5 seconds.
$minRetryInterval = 5;
// Maximum amount of time between polling requests. Defaults to 5 minutes.
$maxRetryInterval = 300;
// Maximum amount of time to spend polling. Defaults to 5 hours.
$maxRetryElapsedTime = 18000;

$operationName = $operation->getName();

$sleepInterval = 0;
$startTime = time();

while (!$operation->getDone()) {
    if ($sleepInterval != 0) {
        printf(
            'The operation is still running, sleeping for %d seconds\n',
            $sleepInterval
        );
    }

    // Sleep before retrieving the SDF Download Task again.
    sleep($sleepInterval);

    // Call the API, retrieving the SDF Download Task.
    $operation = $this->service->sdfdownloadtasks_operations->get(
        $operation->getName()
    );

    // If the operation has exceeded the set deadline, throw an exception.
    if (time() - $startTime > $maxRetryElapsedTime) {
        printf('SDF download task processing deadline exceeded\n');
        throw new Exception(
            'Long-running operation processing deadline exceeded'
        );
    }

    // Generate the next sleep interval using exponential backoff logic.
    $sleepInterval = min(
        $maxRetryInterval,
        rand(
            max($minRetryInterval, $previousSleepInterval),
            max($minRetryInterval, $previousSleepInterval * 3)
        )
    );
}

// If the operation finished with an error, throw an exception.
if($operation->getError() !== null) {
    $error = $operation->getError();
    printf(
        'The operation finished in error with code %s: %s\n',
        $error->getCode(),
        $error->getMessage()
    );
    throw new Exception($error->getMessage());
}

// Print successfully generated resource.
$response = $operation->getResponse();
printf(
    'The operation completed successfully. Resource %s was '
        . 'created. Ready to download.\n',
    $response['resourceName']
);