總覽

結構化資料檔案 (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_UNSPECIFIEDsdfdownloadtask 就會完成錯誤。

您可以使用 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 方法,檢查作業是否已完成並可供下載,或是發生錯誤。

完成後,傳回的作業會具有非空值的 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']
);