Freigeben über


Bewährte Methoden für Microsoft Advertising-Skripts

Um die Leistung Ihrer Skripts und die leistung der Plattform zu verbessern, lesen Und befolgen Sie die unten beschriebenen bewährten Methoden.

Arbeiten mit Selektoren

Verwenden von Filtern

Verwenden Sie die Filter eines Selektors, anstatt die Entitäten selbst zu filtern. Mit Selektoren können Sie nach IDs und Bedingungen filtern. Sie können z. B. nach der Leistung einer Entität (zurückgeben kampagnen mit einem durchschnittlichen CPC größer als 10), deren status (kampagnen, die angehalten werden), dem Namen des übergeordneten Objekts der Entität und mehr filtern.

Vorteile der Verwendung von Filtern:

  • Beschränkt die Anzahl der Entitäten, die der Selektor zurückgibt, auf die Entitäten, die Sie benötigen.

  • Ermöglicht die schnellere Ausführung des Skripts (weniger Entitäten, die zurückgegeben und verarbeitet werden müssen)

  • Verringert die Wahrscheinlichheit, dass Sie die Lesebeschränkungen für Entitäten überschreiten (siehe Skriptausführungsgrenzwerte).

Richtiger Weg

    var adGroups = AdsApp.adGroups()
        .withCondition('Status = PAUSED')
        .get();

    while (adGroups.hasNext()) {
        var adGroup = adGroups.next();
        // Do something with paused ad group.
    }

Falscher Weg

    var adGroups = AdsApp.adGroups().get();

    while (adGroups.hasNext()) {
        var adGroup = adGroups.next();
        
        if (adGroup.isPaused() == true) {
            // Do something with paused ad group.
        }
    }

Durchlaufen Sie nicht die Entitätshierarchie.

Wenn Sie die untergeordneten Entitäten einer Entität oder die übergeordnete Entität der Entität abrufen möchten, durchlaufen Sie nicht die Entitätshierarchie, um sie abzurufen.

Um untergeordnete Entitäten abzurufen, verwenden Sie die Sammlung der untergeordneten Entität auf der gewünschten Ebene.

Richtiger Weg

    // Get all ads.
    var ads = AdsApp.ads().get();

    while (ads.hasNext()) {
        var ad = ads.next();
        // Do something with ad.
    }

Oder, wenn Sie Anzeigen aus einer bestimmten Kampagne wünschen:

    // Get all ads in the campaign, 'mycampaign'.
    var ads = AdsApp.ads()
        .withCondition("CampaignName = 'mycampaign'")
        .get();

    while (ads.hasNext()) {
        var ad = ads.next();
        // Do something with ad.
    }

Oder sie erhalten die Anzeigen einer Kampagne, wenn Sie über das Kampagnenobjekt verfügen:

    // Get all ads in the campaign.
    var ads = campaign.ads().get();

    while (ads.hasNext()) {
        var ad = ads.next();
        // Do something with ad.
    }

Falscher Weg

    var campaigns = AdsApp.campaigns().get();

    while (campaigns.hasNext()) {
        var adGroups = campaigns.next().adGroups().get();
        
        while (adGroups.hasNext()) {
            var ads = adGroups.next().ads().get();

            while (ads.hasNext()) {
                var ad = ads.next();
                // Do something with ad.
            }
        }
    }

Das gleiche gilt, wenn Sie das übergeordnete Element einer Entität abrufen möchten. Anstatt die Hierarchie zu durchlaufen, um das übergeordnete Element abzurufen, verwenden Sie die übergeordnete Accessormethode der untergeordneten Entität.

Richtiger Weg

    // Get all ads.
    var ads = AdsApp.ads()
        .withCondition('Clicks > 5')
        .forDateRange('LAST_7_DAYS')
        .get();

    while (ads.hasNext()) {
        var ad = ads.next();
        
        // Do something with campaign and adGroup.
        var adGroup = ad.adGroup();
        var campaign = ad.campaign();
    }

Falscher Weg

    var campaigns = AdsApp.campaigns().get();

    while (campaigns.hasNext()) {
        var campaign = campaigns.next();
        var adGroups = campaign.adGroups().get();
        
        while (adGroups.hasNext()) {
            var adGroup = adGroups.next();
            var ads = adGroup.ads().get();

            while (ads.hasNext()) {
                var ad = ads.next();
                
                if ('<some condition is met>') {
                    // Do something with campaign and adGroup.
                }
            }
        }
    }

Verwenden von Entitäts-IDs nach Möglichkeit

Die Verwendung von IDs zum Filtern von Entitäten bietet die beste Leistung.

Das

    var adGroups = AdsApp.adGroups()
        .withIds(["123456"])
        .get();

    while (adGroups.hasNext()) {
        var adGroup = adGroups.next();
        
        // Do something with adGroup.
    }

Bietet eine bessere Leistung als diese

    var adGroups = AdsApp.adGroups()
        .withCondition("Name = 'myadgroup'")
        .get();

    while (adGroups.hasNext()) {
        var adGroup = adGroups.next();
        
        // Do something with adGroup.
    }

Vermeiden Sie enge Schleifen mit Selektoren und einer unnötigen Anzahl von Get-Befehlen.

Vermeiden Sie Schleifen mit Get-Anforderungen, die eine einzelne Entität abrufen. Angenommen, Sie führen einen Schlüsselwort (keyword) Leistungsbericht aus und möchten Schlüsselwörter im Bericht aktualisieren. Anstatt eine Zeile aus dem Bericht zu erhalten, die Schlüsselwort (keyword) zu erhalten und sie dann zu aktualisieren, sollten Sie eine Liste der Schlüsselwort (keyword) IDs erstellen, während Sie jede Zeile im Bericht durchlaufen. Übergeben Sie dann die Liste der IDs an den Selektor, um alle Schlüsselwörter in einer einzelnen Get-Anforderung abzurufen. Anschließend können Sie die Liste der Schlüsselwörter durchlaufen und diese aktualisieren.

Richtiger Weg

    var report = AdsApp.report('<report query goes here>');

    var rows = report.rows();
    var idLists = []; // an array where each element contains an array of IDs.
    var idList = [];  // array of IDs that's limited to maxCount.
    var maxCount = 10000;

    while (rows.hasNext()) {
        var row = rows.next();

        if (idList.length < maxCount) {
            idList.push(row['id']);
        }
        else {
            idLists.push(idList);
            idList = [];
        }
    }

    for (idList of idLists) {
        var keywords = AdsApp.keywords()
            .withIds(idList)
            .get();

        while (keywords.hasNext()) {
            var keyword = keywords.next();
            // update the keyword        
        }
    }

Falscher Weg

    var report = AdsApp.report('<report query goes here>');

    var rows = report.rows();

    while (rows.hasNext()) {
        var row = rows.next();

        var keyword = AdsApp.keywords()
            .withIds([row['id']])
            .get()
            .next();

        // update the keyword        
    }

Schließen Sie die forDateRange-Methode nur ein, wenn Sie planen, die getStats-Methode der Entität aufzurufen.

Das Aufrufen der -Methode eines Selektors forDateRange bewirkt, dass der Selektor die Leistungsdaten der Entität erhält. Das Abrufen der Leistungsdaten einer Entität ist teuer. Rufen Sie sie daher nur ab, wenn Sie planen, die -Methode der Entität getStats aufzurufen und die Daten zu verwenden.

Der Datumsbereich, den Sie für eine Entität angeben, gilt nicht für die übergeordneten oder untergeordneten Entitäten, auf die Sie von dieser Entität aus zugreifen. Wenn Sie beispielsweise eine Anzeigengruppe und dann die übergeordnete Kampagne abrufen und versuchen, auf die Leistungsmetriken der Kampagne zuzugreifen, schlägt der Aufruf fehl.

Der campaignStats.getReturnOnAdSpend() Aufruf im folgenden Beispiel schlägt fehl, da der Datumsbereich für die Anzeigengruppe und nicht für die Kampagne gilt.

    var myAdGroups = AdsApp.adGroups().
        .withCondition("CampaignName CONTAINS 'gen'")
        .forDateRange("LAST_7_DAYS")
        .get();

    while (myAdGroups.hasNext()) {
        var adGroup = myAdGroups.next();
        var campaign = adGroup.getCampaign();
        var campaignStats = campaign.getStats();
        var campaignROAS = campaignStats.getReturnOnAdSpend();
    }

Damit dies funktioniert, müssen Sie einen Selektor für die Kampagne erstellen.

    var myAdGroups = AdsApp.adGroups().
        .withCondition("CampaignName CONTAINS 'gen'")
        .forDateRange("LAST_7_DAYS")
        .get();

    while (myAdGroups.hasNext()) {
        var adGroup = myAdGroups.next();
        var campaign = AdsApp.campaigns()
            .withIds([adGroup.getCampaign().getId()])
            .forDateRange("LAST_7_DAYS")
            .get()
            .next();
        var campaignStats = campaign.getStats();
        var campaignROAS = campaignStats.getReturnOnAdSpend();
    }

Ändern Sie nicht die Eigenschaft einer Entität, die als Bedingung in der Auswahl verwendet wird.

Iteratoren verringern die Arbeitsspeicherauslastung, indem nur ein einzelnes Element geladen wird und nicht der gesamte Satz von Elementen. Aus diesem Grund kann das Ändern einer Eigenschaft, die Sie als Bedingung in der Auswahl verwendet haben, zu unerwartetem Verhalten führen.

Richtiger Weg

    var adGroups = []; 

    var iterator = AdsApp.adGroups()
        .withCondition('Status = ENABLED')
        .get();

    while (iterator.hasNext()) {
        adGroups.push(iterator.next());
    }

    for (var adGroup of adGroups) {
        adGroup.pause();
    }

Falscher Weg

    var adGroups = AdsApp.adGroups()
        .withCondition('Status = ENABLED')
        .get();

    while (adGroups.hasNext()) {
        var adGroup = adGroups.next();
        adGroup.pause();
    }

Batchverarbeitung von Updates

Um die Leistung zu verbessern, verarbeitet Skripts Buildanforderungen in Batches. Wenn Sie die Vorgangsmethode einer Buildanforderung aufrufen, erzwingt dies Skripts, die in der Warteschlange eingereihten Buildanforderungen sofort zu verarbeiten, wobei Leistungssteigerungen negiert werden. Wenn Sie mehrere Entitäten erstellen, führen Sie die Vorgangsmethoden nicht in derselben Schleife aus, die Sie zum Erstellen der Entität verwenden. Dies führt zu einer schlechten Leistung, da jeweils nur eine Entität verarbeitet wird. Erstellen Sie stattdessen ein Array der Vorgänge, und verarbeiten Sie sie nach der Buildschleife.

Richtiger Weg

    // An array to hold the operations, so you 
    // can process them after all the entities are queued.
    var operations = []; 

    // Create all the new entities.
    for (var i = 0; i < keywords.length; i++) {
        var keywordOperation = AdsApp.adGroups().get().next()
          .newKeywordBuilder()
          .withText(keywords[i])
          .build();
        operations.push(keywordOperation);
    }

    // Now call the operation method so the build requests
    // get processed in batches.
    for (var i = 0; i < operations.length; i++) {
        var newKeyword = operations[i].getResult();
    }

Falscher Weg

    for (var i = 0; i < keywords.length; i++) {
        var keywordOperation = AdsApp.adGroups().get().next()  // Get the first ad group
          .newKeywordBuilder()  // Add the keyword to the ad group
          .withText(keywords[i])
          .build();

        // Don't get results in the same loop that creates
        // the entity because Scripts then only processes one
        // entity at a time.
        var newKeyword = keywordOperation.getResult();
    }

Das gleiche gilt, wenn Sie eine Entität aktualisieren und dann dieselbe Eigenschaft erhalten, die Sie aktualisiert haben. Führen Sie dies nicht aus:

    var bidAmount = 1.2;

    while (keywords.hasNext()) {
        var keyword = keywords.next();

        keyword.bidding().setCpc(bidAmount);

        if (keyword.bidding().getCpc() != bidAmount) {
            Logger.log(`Failed to update bid amount for keyword, ${keyword.getText()} (${keyword.getId()})`);
        }
    }

Verwenden sie die Schlüsselwort (keyword), wenn Sie große Gruppen von Entitäten abrufen.

Das Abrufen einer großen Anzahl von Entitäten und das Laden in eine einzelne Liste, die Sie in einer Schleife verarbeiten, hat einige Nachteile:

  1. Abhängig von der Größe der Anforderung kann es n Anzahl von Back-End-Anforderungen dauern, um alle Entitäten abzurufen, bevor die Schleife gestartet wird. Wenn Sie sie nicht alle verarbeiten, wird die Zeit und Die Rechenleistung, die zum Abrufen der nicht verarbeiteten Entitäten verwendet wird, verschwendet. Wenn Sie z. B. 10.000 Schlüsselwörter abrufen und die Schleifenumbrüche nach der Verarbeitung nur 2.000 Schlüsselwörter ausführen, werden die Zeit und die Rechenleistung verschwendet, die zum Abrufen der verbleibenden 8.000 Schlüsselwörter verwendet werden.

  2. Zum Erstellen der Liste ist mehr Arbeitsspeicher erforderlich, damit alle Entitäten gleichzeitig gespeichert werden können.

Um diese Probleme zu beheben, verwenden Sie die Yield-Schlüsselwort (keyword), mit der Ihr Skript Entitäten bei Bedarf abrufen oder in gewisser Weise nur dann "verzögert" abrufen kann, wenn sie benötigt werden. Dies bedeutet, dass Ihr Skript nicht mehr Aufrufe durchführt, als es im Moment benötigt, und es werden keine großen Listen von Objekten übergeben.

Dieses Beispiel umfasst die Protokollierung, um den Ablauf der Steuerung bei Verwendung des Yield-Schlüsselwort (keyword) zu veranschaulichen.

function main() {
    const keywords = getKeywords();

    //@ts-ignore <-- suppresses iterator error
    for (const keyword of keywords) {
        Logger.log("in for loop\n\n");
    }
}

// Note that you must use the yield keyword in a generator function - see the
// '*' at the end of the function keyword.

function* getKeywords() {
    const keywords = AdsApp.keywords()
        .withCondition("Status = ENABLED")
        .withCondition("CombinedApprovalStatus = APPROVED")
        .withLimit(10)
        .get();

    Logger.log(`total keywords in account: ${keywords.totalNumEntities()} \n\n`);

    while (keywords.hasNext()) {
        Logger.log("before next()\n\n");
        yield keywords.next();
        Logger.log("after next\n\n");
    }
}

Aufrufmuster zur Vermeidung von Entitätsgrenzwerten

Es gibt eine Beschränkung für die Anzahl von Entitäten, die Skripts für ein Konto zurückgeben können. Wenn die Anforderung mehr als diesen Grenzwert zurückgibt, löst Scripts einen Fehler mit der Meldung Es gibt zu viele Entitäten aus. Das folgende Beispiel zeigt das Aufrufmuster, das Sie beim Abrufen einer großen Anzahl von Entitäten verwenden sollten. Im Beispiel wird versucht, zuerst alle Schlüsselwörter auf Kontoebene abzurufen. Wenn dies fehlschlägt, wird versucht, mehrere Aufrufe zum Abrufen von Schlüsselwörtern nach Kampagne auszuführen, da es in der Regel weniger Entitäten auf Kampagnenebene gibt. Sie können dieses Muster bei Bedarf bis zur Anzeigengruppenebene fortsetzen.

Informationen zur Verwendung der Schlüsselwort (keyword) "Yield" finden Sie unter Verwenden des Schlüsselwort (keyword) beim Abrufen großer Entitätssätze.

function* getEntities() {
    const applyConditions = _ => _
        .withCondition('CampaignStatus = ENABLED')
        .withCondition('AdGroupStatus = ENABLED')
        .withCondition('Status = ENABLED')
        .withCondition("CombinedApprovalStatus = DISAPPROVED");

    try {
        // Get the account's keywords. 
        const keywords = applyConditions(AdsApp.keywords()).get();

        while (keywords.hasNext()) {
            yield keywords.next();
        }
    } catch (e) {
        if (!e.message.startsWith('There are too many entities')) {
            throw e;
        }

        // If there are too many keywords at the account level,
        // get keywords by campaigns under the account.
        const campaigns = AdsApp.campaigns().get();

        while (campaigns.hasNext()) {
            const campaign = campaigns.next();

            const keywords = applyConditions(campaign.keywords()).get();

            while (keywords.hasNext()) {
                yield keywords.next();
            }
        }
    }
}