Skip to content

Commit 6391da8

Browse files
authored
Add AddHotelListingGroupTree example (#361)
* Add AddHotelListingGroupTree example Change-Id: I77ce66b75b37aeb86a4353232ac803dd463ed3cd * Address comments Change-Id: Ic305f35846b66e45d9478a5557138ebcedbeadc9 * Remove assert Change-Id: I5fa79789c6c1a0d596595b536133748443a9c3e7 * Use stream iterator Change-Id: Ia11a673d80b672d769849bbfb078f3d69fc407db * Remove unused imports Change-Id: I144d9c1635bc14cfc580c11d92a67d89ca13b278
1 parent 3ca606b commit 6391da8

2 files changed

Lines changed: 388 additions & 0 deletions

File tree

Lines changed: 387 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,387 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.ads.googleads.examples.hotelads;
16+
17+
import com.beust.jcommander.Parameter;
18+
import com.google.ads.googleads.examples.utils.ArgumentNames;
19+
import com.google.ads.googleads.examples.utils.CodeSampleParams;
20+
import com.google.ads.googleads.lib.GoogleAdsClient;
21+
import com.google.ads.googleads.v5.common.HotelClassInfo;
22+
import com.google.ads.googleads.v5.common.HotelCountryRegionInfo;
23+
import com.google.ads.googleads.v5.common.ListingDimensionInfo;
24+
import com.google.ads.googleads.v5.common.ListingGroupInfo;
25+
import com.google.ads.googleads.v5.enums.AdGroupCriterionStatusEnum.AdGroupCriterionStatus;
26+
import com.google.ads.googleads.v5.enums.ListingGroupTypeEnum.ListingGroupType;
27+
import com.google.ads.googleads.v5.errors.GoogleAdsError;
28+
import com.google.ads.googleads.v5.errors.GoogleAdsException;
29+
import com.google.ads.googleads.v5.resources.AdGroupCriterion;
30+
import com.google.ads.googleads.v5.services.AdGroupCriterionOperation;
31+
import com.google.ads.googleads.v5.services.AdGroupCriterionServiceClient;
32+
import com.google.ads.googleads.v5.services.MutateAdGroupCriteriaResponse;
33+
import com.google.ads.googleads.v5.services.MutateAdGroupCriterionResult;
34+
import com.google.ads.googleads.v5.utils.ResourceNames;
35+
import java.io.FileNotFoundException;
36+
import java.io.IOException;
37+
import java.util.ArrayList;
38+
import java.util.Iterator;
39+
import java.util.List;
40+
import java.util.stream.LongStream;
41+
42+
/**
43+
* This example shows how to add a hotel listing group tree, which has two levels. The first level
44+
* is partitioned by the hotel class. The second level is partitioned by the country region.
45+
*
46+
* <p>Each level is composed of two types of nodes: `UNIT` and `SUBDIVISION`. `UNIT` nodes serve as
47+
* leaf nodes in a tree and can have bid amount set. `SUBDIVISION` nodes serve as internal nodes
48+
* where a subtree will be built. The `SUBDIVISION` node cannot have bid amount set. See
49+
* https://developers.google.com/google-ads/api/docs/hotel-ads/overview for more information.
50+
*
51+
* <p>Note: Only one listing group tree can be added per ad group. Attempting to add another listing
52+
* group tree to an ad group that already has one will fail.
53+
*/
54+
public class AddHotelListingGroupTree {
55+
56+
private static Iterator<Long> idGenerator;
57+
58+
private static class AddHotelListingGroupTreeParams extends CodeSampleParams {
59+
60+
@Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
61+
private Long customerId;
62+
63+
@Parameter(names = ArgumentNames.AD_GROUP_ID, required = true)
64+
private Long adGroupId;
65+
66+
// Specify the CPC bid micro amount to be set on a created ad group criterion.
67+
// For simplicity, each ad group criterion will use the below amount equally. In practice, you
68+
// probably want to use different values for each ad group criterion.
69+
@Parameter(names = ArgumentNames.PERCENT_CPC_BID_MICRO_AMOUNT)
70+
private Long percentCpcBidMicroAmount = 1_000_000L;
71+
}
72+
73+
public static void main(String[] args) {
74+
AddHotelListingGroupTreeParams params = new AddHotelListingGroupTreeParams();
75+
if (!params.parseArguments(args)) {
76+
77+
// Either pass the required parameters for this example on the command line, or insert them
78+
// into the code here. See the parameter class definition above for descriptions.
79+
params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
80+
params.adGroupId = Long.parseLong("INSERT_AD_GROUP_ID_HERE");
81+
// Optional: To use a different CPC bid micro value from the default (1_000_000), uncomment
82+
// the line below and insert the desired CPC bid micro value.
83+
// params.percentCpcBidMicroAmount = Long.parseInt("INSERT_PERCENT_CPC_BID_MICRO_AMOUNT");
84+
}
85+
86+
GoogleAdsClient googleAdsClient = null;
87+
try {
88+
googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
89+
} catch (FileNotFoundException fnfe) {
90+
System.err.printf(
91+
"Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
92+
System.exit(1);
93+
} catch (IOException ioe) {
94+
System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
95+
System.exit(1);
96+
}
97+
98+
try {
99+
new AddHotelListingGroupTree()
100+
.runExample(
101+
googleAdsClient,
102+
params.customerId,
103+
params.adGroupId,
104+
params.percentCpcBidMicroAmount);
105+
} catch (GoogleAdsException gae) {
106+
// GoogleAdsException is the base class for most exceptions thrown by an API request.
107+
// Instances of this exception have a message and a GoogleAdsFailure that contains a
108+
// collection of GoogleAdsErrors that indicate the underlying causes of the
109+
// GoogleAdsException.
110+
System.err.printf(
111+
"Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
112+
gae.getRequestId());
113+
int i = 0;
114+
for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
115+
System.err.printf(" Error %d: %s%n", i++, googleAdsError);
116+
}
117+
System.exit(1);
118+
}
119+
}
120+
121+
/**
122+
* Constructor used to create iterator for generating temporary criterion IDs, which are negative
123+
* integers.
124+
*
125+
* <p>When creating a tree, we need to specify the parent-child relationships between nodes.
126+
* However, until a criterion has been created on the server we do not have a criterion ID with
127+
* which to refer to it.
128+
*
129+
* <p>Instead we can specify temporary IDs that are specific to a single mutate request. Once a
130+
* criterion is created, it is assigned an ID as normal and the temporary ID will no longer refer
131+
* to it.
132+
*/
133+
AddHotelListingGroupTree() {
134+
idGenerator = LongStream.iterate(-1L, prev -> prev - 1).iterator();
135+
}
136+
137+
/**
138+
* Runs the example.
139+
*
140+
* @param googleAdsClient the Google Ads API client.
141+
* @param customerId the client customer ID.
142+
* @param adGroupId the ID of the ad group.
143+
* @param percentCpcBidMicroAmount the percent CPC bid micro amount to set on created ad group
144+
* criteria.
145+
* @throws GoogleAdsException if an API request failed with one or more service errors.
146+
*/
147+
private void runExample(
148+
GoogleAdsClient googleAdsClient,
149+
long customerId,
150+
long adGroupId,
151+
long percentCpcBidMicroAmount) {
152+
List<AdGroupCriterionOperation> operations = new ArrayList<>();
153+
154+
// Creates the root of the tree as a SUBDIVISION node.
155+
String rootResourceName =
156+
addRootNode(customerId, adGroupId, operations, percentCpcBidMicroAmount);
157+
158+
// Creates child nodes of level 1, partitioned by the hotel class info.
159+
String otherHotelResourceName =
160+
addLevel1Nodes(
161+
customerId, adGroupId, rootResourceName, operations, percentCpcBidMicroAmount);
162+
163+
// Creates child nodes of level 2, partitioned by the hotel country region info.
164+
addLevel2Nodes(
165+
customerId, adGroupId, otherHotelResourceName, operations, percentCpcBidMicroAmount);
166+
167+
try (AdGroupCriterionServiceClient adGroupCriterionServiceClient =
168+
googleAdsClient.getLatestVersion().createAdGroupCriterionServiceClient()) {
169+
MutateAdGroupCriteriaResponse response =
170+
adGroupCriterionServiceClient.mutateAdGroupCriteria(
171+
String.valueOf(customerId), operations);
172+
173+
System.out.printf("Added %d listing group info entities.%n", response.getResultsCount());
174+
for (MutateAdGroupCriterionResult result : response.getResultsList()) {
175+
System.out.println(result.getAdGroupCriterion().getResourceName());
176+
}
177+
}
178+
}
179+
180+
/**
181+
* Creates the root node of the listing group tree and adds its create operation to the operations
182+
* list.
183+
*
184+
* @param customerId the customer ID.
185+
* @param adGroupId the ad group ID.
186+
* @param operations the operations.
187+
* @param percentCpcBidMicroAmount the CPC bid micro amount to set on created ad group criteria.
188+
* @return the root node's resource name
189+
*/
190+
private static String addRootNode(
191+
long customerId,
192+
long adGroupId,
193+
List<AdGroupCriterionOperation> operations,
194+
long percentCpcBidMicroAmount) {
195+
// Creates the root of the tree as a SUBDIVISION node.
196+
ListingGroupInfo root =
197+
ListingGroupInfo.newBuilder().setType(ListingGroupType.SUBDIVISION).build();
198+
AdGroupCriterion rootAdGroupCriterion =
199+
createAdGroupCriterion(customerId, adGroupId, root, percentCpcBidMicroAmount);
200+
AdGroupCriterionOperation operation = generateCreateOperation(rootAdGroupCriterion);
201+
operations.add(operation);
202+
return rootAdGroupCriterion.getResourceName();
203+
}
204+
205+
/**
206+
* Creates child nodes of level 1, partitioned by the hotel class info.
207+
*
208+
* @param customerId the customer ID.
209+
* @param adGroupId the ad group ID.
210+
* @param rootResourceName the resource name of the root node.
211+
* @param operations the operations list.
212+
* @param percentCpcBidMicroAmount the CPC bid micro amount to set on created ad group criteria.
213+
* @return the "other hotel classes" node's resource name, which serves as a parent node for the
214+
* next level.
215+
*/
216+
// [START addLevel1Nodes]
217+
private static String addLevel1Nodes(
218+
long customerId,
219+
long adGroupId,
220+
String rootResourceName,
221+
List<AdGroupCriterionOperation> operations,
222+
long percentCpcBidMicroAmount) {
223+
// Creates hotel class info and dimension info for 5-star hotels.
224+
ListingDimensionInfo fiveStarredDimensionInfo =
225+
ListingDimensionInfo.newBuilder()
226+
.setHotelClass(HotelClassInfo.newBuilder().setValue(5).build())
227+
.build();
228+
// Creates listing group info for 5-star hotels as a UNIT node.
229+
ListingGroupInfo fiveStarredUnit =
230+
ListingGroupInfo.newBuilder()
231+
.setType(ListingGroupType.UNIT)
232+
.setParentAdGroupCriterion(rootResourceName)
233+
.setCaseValue(fiveStarredDimensionInfo)
234+
.build();
235+
// Creates an ad group criterion for 5-star hotels.
236+
AdGroupCriterion fiveStarredAdGroupCriterion =
237+
createAdGroupCriterion(customerId, adGroupId, fiveStarredUnit, percentCpcBidMicroAmount);
238+
// Decrements the temp ID for the next ad group criterion.
239+
AdGroupCriterionOperation operation = generateCreateOperation(fiveStarredAdGroupCriterion);
240+
operations.add(operation);
241+
242+
// You can also create more UNIT nodes for other hotel classes by copying the above code in
243+
// this method and modifying the value passed to HotelClassInfo() to the value you want.
244+
// For instance, passing 4 instead of 5 in the above code will create a UNIT node of 4-star
245+
// hotels instead.
246+
247+
// Creates hotel class info and dimension info for other hotel classes by not specifying
248+
// any attributes on those object.
249+
ListingDimensionInfo otherHotelsDimensionInfo =
250+
ListingDimensionInfo.newBuilder()
251+
.setHotelClass(HotelClassInfo.newBuilder().build())
252+
.build();
253+
// Creates listing group info for other hotel classes as a SUBDIVISION node, which will be
254+
// used as a parent node for children nodes of the next level.
255+
ListingGroupInfo otherHotelsSubdivision =
256+
createListingGroupInfo(
257+
ListingGroupType.SUBDIVISION, rootResourceName, otherHotelsDimensionInfo);
258+
// Creates an ad group criterion for other hotel classes.
259+
AdGroupCriterion otherHotelsAdGroupCriterion =
260+
createAdGroupCriterion(
261+
customerId, adGroupId, otherHotelsSubdivision, percentCpcBidMicroAmount);
262+
operation = generateCreateOperation(otherHotelsAdGroupCriterion);
263+
operations.add(operation);
264+
265+
return otherHotelsAdGroupCriterion.getResourceName();
266+
}
267+
// [END addLevel1Nodes]
268+
269+
/**
270+
* Creates child nodes of level 2, partitioned by the country region.
271+
*
272+
* @param customerId the customer ID.
273+
* @param adGroupId the ad group ID.
274+
* @param parentResourceName the resource name of the parent node.
275+
* @param operations the operations list.
276+
* @param percentCpcBidMicroAmount the CPC bid micro amount to set on created ad group criteria.
277+
* criteria
278+
*/
279+
private static void addLevel2Nodes(
280+
long customerId,
281+
long adGroupId,
282+
String parentResourceName,
283+
List<AdGroupCriterionOperation> operations,
284+
long percentCpcBidMicroAmount) {
285+
// The criterion ID for Japan is 2392.
286+
// See https://developers.google.com/adwords/api/docs/appendix/geotargeting for criteria ID
287+
// of other countries.
288+
long japanGeoTargetConstantId = 2392;
289+
ListingDimensionInfo japanDimensionInfo =
290+
ListingDimensionInfo.newBuilder()
291+
// Creates hotel country region info and dimension info for hotels in Japan.
292+
.setHotelCountryRegion(
293+
HotelCountryRegionInfo.newBuilder()
294+
.setCountryRegionCriterion(
295+
ResourceNames.geoTargetConstant(japanGeoTargetConstantId))
296+
.build())
297+
.build();
298+
// Creates hotel country region info and dimension info for hotels in Japan.
299+
ListingGroupInfo japanHotelsUnit =
300+
createListingGroupInfo(ListingGroupType.UNIT, parentResourceName, japanDimensionInfo);
301+
// Creates an ad group criterion for hotels in Japan.
302+
AdGroupCriterion japanHotelsAdGroupCriterion =
303+
createAdGroupCriterion(customerId, adGroupId, japanHotelsUnit, percentCpcBidMicroAmount);
304+
// Decrements the temp ID for the next ad group criterion.
305+
AdGroupCriterionOperation operation = generateCreateOperation(japanHotelsAdGroupCriterion);
306+
operations.add(operation);
307+
308+
// Creates hotel class info and dimension info for hotels in other regions.
309+
ListingDimensionInfo otherHotelRegionsDimensionInfo =
310+
ListingDimensionInfo.newBuilder()
311+
.setHotelCountryRegion(HotelCountryRegionInfo.newBuilder().build())
312+
.build();
313+
// Creates listing group info for hotels in other regions as a UNIT node.
314+
// The "others" node is always required for every level of the tree.
315+
ListingGroupInfo otherHotelRegionsUnit =
316+
createListingGroupInfo(
317+
ListingGroupType.UNIT, parentResourceName, otherHotelRegionsDimensionInfo);
318+
// Creates an ad group criterion for other hotel country regions.
319+
AdGroupCriterion otherHotelRegionsAdGroupCriterion =
320+
createAdGroupCriterion(
321+
customerId, adGroupId, otherHotelRegionsUnit, percentCpcBidMicroAmount);
322+
operation = generateCreateOperation(otherHotelRegionsAdGroupCriterion);
323+
operations.add(operation);
324+
}
325+
326+
/**
327+
* Creates the listing group info with the provided parameters.
328+
*
329+
* @param listingGroupType the listing group type.
330+
* @param parentCriterionResourceName the resource name of parent criterion ID of the listing
331+
* group info.
332+
* @param caseValue the dimension info for the listing group.
333+
* @return the created listing group info
334+
*/
335+
private static ListingGroupInfo createListingGroupInfo(
336+
ListingGroupType listingGroupType,
337+
String parentCriterionResourceName,
338+
ListingDimensionInfo caseValue) {
339+
return ListingGroupInfo.newBuilder()
340+
.setType(listingGroupType)
341+
.setParentAdGroupCriterion(parentCriterionResourceName)
342+
.setCaseValue(caseValue)
343+
.build();
344+
}
345+
346+
/**
347+
* Creates an ad group criterion from the provided listing group info. Bid amount will be set on
348+
* the created ad group criterion when listing group info type is `UNIT`. Setting bid amount for
349+
* `SUBDIVISION` types is not allowed.
350+
*
351+
* @param customerId the customer ID.
352+
* @param adGroupId the ad group ID.
353+
* @param listingGroupInfo the listing group info.
354+
* @param percentCpcBidMicroAmount the CPC bid micro amount to set for the ad group criterion.
355+
* @return the created ad group criterion
356+
*/
357+
private static AdGroupCriterion createAdGroupCriterion(
358+
long customerId,
359+
long adGroupId,
360+
ListingGroupInfo listingGroupInfo,
361+
long percentCpcBidMicroAmount) {
362+
AdGroupCriterion.Builder adGroupCriterionBuilder =
363+
AdGroupCriterion.newBuilder()
364+
.setStatus(AdGroupCriterionStatus.ENABLED)
365+
.setListingGroup(listingGroupInfo)
366+
.setResourceName(
367+
ResourceNames.adGroupCriterion(customerId, adGroupId, idGenerator.next()));
368+
369+
// Bids are valid only for UNIT nodes.
370+
if (listingGroupInfo.getType() == ListingGroupType.UNIT) {
371+
adGroupCriterionBuilder.setPercentCpcBidMicros(percentCpcBidMicroAmount);
372+
}
373+
374+
return adGroupCriterionBuilder.build();
375+
}
376+
377+
/**
378+
* Creates an operation for creating the specified ad group criterion.
379+
*
380+
* @param adGroupCriterion the ad group criterion to create an operation for.
381+
* @return the created ad group criterion operation
382+
*/
383+
private static AdGroupCriterionOperation generateCreateOperation(
384+
AdGroupCriterion adGroupCriterion) {
385+
return AdGroupCriterionOperation.newBuilder().setCreate(adGroupCriterion).build();
386+
}
387+
}

google-ads-examples/src/main/java/com/google/ads/googleads/examples/utils/ArgumentNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public final class ArgumentNames {
8282
public static final String PARTNER_ID = "--partnerId";
8383
public static final String PAYMENTS_ACCOUNT_ID_ID = "--paymentsAccountId";
8484
public static final String PAYMENTS_PROFILE_ID = "--paymentsProfileId";
85+
public static final String PERCENT_CPC_BID_MICRO_AMOUNT = "--percentCpcBidMicroAmount";
8586
public static final String RECOMMENDATION_ID = "--recommendationId";
8687
public static final String REPLACE_EXISTING_TREE = "--replaceExistingTree";
8788
public static final String RESTATEMENT_VALUE = "--restatementValue";

0 commit comments

Comments
 (0)