總覽

結構化資料檔案 (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 會篩選要求,只納入識別的資源。

每個 SDF 類型都有一個 IdFilter 欄位,但不含廣告空間來源。每個欄位都是專屬 ID 清單,可指明要在產生的 SDF 中加入哪些特定資源。提供的 ID 必須位於結構定義集中,但不必直接相關。您不需要提出特定廣告活動請求,即可請求內含的委刊項,反之亦然。系統只會產生與 IdFilter 中識別資源的對應檔案類型。

InventorySourceFilter

InventorySourceFilter 僅允許篩選及下載含有廣告空間來源資源的 SDF。這是唯一可用於取得 Inventory Source 資源相關資訊的篩選器。

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 時,系統會傳回「運算」物件。這項作業代表建立期間非同步 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']
);