/// <summary> /// Outputs the list of BulkAdGroupProductPartition which each contain an AdGroupCriterion, formatted as a tree. /// Each AdGroupCriterion must be either a BiddableAdGroupCriterion or NegativeAdGroupCriterion. /// </summary> /// <param name="adGroupCriterions">The list of BulkAdGroupProductPartition to output formatted as a tree.</param> private void OutputProductPartitions(IList <BulkAdGroupProductPartition> bulkAdGroupProductPartitions) { // Set up the tree for output Dictionary <long, List <BulkAdGroupProductPartition> > childBranches = new Dictionary <long, List <BulkAdGroupProductPartition> >(); BulkAdGroupProductPartition treeRoot = null; foreach (var bulkAdGroupProductPartition in bulkAdGroupProductPartitions) { AdGroupCriterion adGroupCriterion = bulkAdGroupProductPartition.AdGroupCriterion; if (adGroupCriterion != null) { ProductPartition partition = (ProductPartition)adGroupCriterion.Criterion; childBranches[(long)(adGroupCriterion.Id)] = new List <BulkAdGroupProductPartition>(); // The product partition with ParentCriterionId set to null is the root node. if (partition.ParentCriterionId != null) { childBranches[(long)(partition.ParentCriterionId)].Add(bulkAdGroupProductPartition); } else { treeRoot = bulkAdGroupProductPartition; } } } // Outputs the tree root node and any children recursively OutputProductPartitionTree(treeRoot, childBranches, 0); }
/// <summary> /// Displays the product partition tree. /// </summary> /// <param name="node">The root node.</param> /// <param name="children">The child node.</param> /// <param name="level">The tree level.</param> /// <param name="writer">The stream to write output to.</param> private void DisplayTree(ProductPartition node, Dictionary <long, List <ProductPartition> > children, int level, StringWriter writer) { // Recursively display a node and each of its children. object value = null; string type = ""; if (node.caseValue != null) { type = node.caseValue.ProductDimensionType; switch (type) { case "ProductCanonicalCondition": value = (node.caseValue as ProductCanonicalCondition).condition.ToString(); break; case "ProductBiddingCategory": value = (node.caseValue as ProductBiddingCategory).type.ToString() + "(" + (node.caseValue as ProductBiddingCategory).value + ")"; break; default: value = node.caseValue.GetType().GetProperty("value").GetValue(node.caseValue, null); break; } } writer.WriteLine("{0}id: {1}, type: {2}, value: {3}", "".PadLeft(level, ' '), node.id, type, value); foreach (ProductPartition childNode in children[node.id]) { DisplayTree(childNode, children, level + 1, writer); } }
/// <summary> /// Constructs a <see cref="ProductPartition" /> criterion corresponding to /// the node. /// </summary> /// <returns>The <see cref="ProductPartition" /> node.</returns> internal ProductPartition GetCriterion() { ProductPartition partition = new ProductPartition(); partition.id = this.ProductPartitionId; if (this.Parent != null) { partition.parentCriterionId = this.Parent.ProductPartitionId; } partition.caseValue = this.Dimension; partition.partitionType = this.IsUnit ? ProductPartitionType.UNIT : ProductPartitionType.SUBDIVISION; return(partition); }
/// <summary> /// Creates the criterion for product partition. /// </summary> /// <param name="partitionId">The product partition ID.</param> /// <param name="parentPartitionId">The proudct partition ID for parent node.</param> /// <param name="caseValue">The case value.</param> /// <param name="isUnit">True, if the node is UNIT node, false otherwise.</param> /// <param name="isExcluded">True, if the node is EXCLUDE node, false otherwise.</param> /// <param name="bid">The bid to be set on a node, if it is UNIT.</param> /// <returns>An ad group criterion node for the product partition.</returns> internal static AdGroupCriterion CreateCriterionForProductPartition(long partitionId, long parentPartitionId, ProductDimension caseValue, bool isUnit, bool isExcluded, long bid) { AdGroupCriterion adGroupCriterion; ProductPartition partition = new ProductPartition() { id = partitionId, parentCriterionId = parentPartitionId, caseValue = caseValue, partitionType = isUnit ? ProductPartitionType.UNIT : ProductPartitionType.SUBDIVISION }; if (isExcluded) { NegativeAdGroupCriterion negative = new NegativeAdGroupCriterion(); adGroupCriterion = negative; } else { BiddableAdGroupCriterion biddable = new BiddableAdGroupCriterion(); biddable.userStatus = UserStatus.ENABLED; BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration(); if (isUnit && bid != 0) { CpcBid cpcBid = new CpcBid() { bid = new Money() { microAmount = bid }, cpcBidSource = BidSource.CRITERION }; biddingConfig.bids = new Bids[] { cpcBid }; } biddable.biddingStrategyConfiguration = biddingConfig; adGroupCriterion = biddable; } adGroupCriterion.criterion = partition; return(adGroupCriterion); }
public void TestCreateMultiNodeTreeFromScratch() { ProductPartitionTree tree = ProductPartitionTree.CreateAdGroupTree(new List <AdGroupCriterion>()); ProductPartitionNode rootNode = tree.Root.AsSubdivision(); ProductPartitionNode brand1 = rootNode.AddChild(ProductDimensions.CreateBrand("google")) .AsSubdivision(); ProductPartitionNode brand1Offer1 = brand1.AddChild(ProductDimensions.CreateOfferId("A")); brand1Offer1.AsBiddableUnit().CpcBid = 1000000L; ProductPartitionNode brand1Offer2 = brand1.AddChild(ProductDimensions.CreateOfferId()).AsExcludedUnit(); ProductPartitionNode brand2 = rootNode.AddChild(ProductDimensions.CreateBrand()).AsExcludedUnit(); ProductPartitionNode[] nodes = new ProductPartitionNode[] { rootNode, brand1, brand1Offer1, brand1Offer2, brand2 }; AdGroupCriterionOperation[] mutateOperations = tree.GetMutateOperations(); for (int i = 0; i < nodes.Length; i++) { List <AdGroupCriterionOperation> nodeOperations = shoppingTestUtils.GetOperationsForNode(nodes[i], mutateOperations); Assert.That(nodeOperations.Count == 1); Assert.That(nodeOperations[0].@operator == Operator.ADD); ProductPartition partition = (ProductPartition)nodeOperations[0].operand.criterion; Assert.That(partition.id == nodes[i].ProductPartitionId); if (nodes[i].Parent == null) { Assert.That(partition.parentCriterionIdSpecified == false); } else { Assert.That(partition.parentCriterionId == nodes[i].Parent.ProductPartitionId); } Assert.That(partition.caseValue == nodes[i].Dimension); } }
/// <summary> /// Creates a subdivision node. /// </summary> /// <param name="parent">The node that should be this node's parent. /// </param> /// <param name="value">The value being paritioned on.</param> /// <returns>A new subdivision node.</returns> public ProductPartition CreateSubdivision(ProductPartition parent, ProductDimension value) { ProductPartition division = new ProductPartition(); division.partitionType = ProductPartitionType.SUBDIVISION; division.id = this.nextId--; // The root node has neither a parent nor a value. if (parent != null) { division.parentCriterionId = parent.id; division.caseValue = value; } BiddableAdGroupCriterion criterion = new BiddableAdGroupCriterion(); criterion.adGroupId = this.adGroupId; criterion.criterion = division; this.CreateAddOperation(criterion); return division; }
/// <summary> /// Creates a map with key as the parent criterion ID and value as the list of child nodes. /// </summary> /// <param name="adGroupCriteria">The list of ad group criteria.</param> /// <returns>A criteria map.</returns> private static Dictionary <long, List <AdGroupCriterion> > CreateParentIdMap( List <AdGroupCriterion> adGroupCriteria) { PreconditionUtilities.CheckNotNull(adGroupCriteria, ShoppingMessages.CriteriaListNull); Dictionary <long, List <AdGroupCriterion> > parentIdMap = new Dictionary <long, List <AdGroupCriterion> >(); foreach (AdGroupCriterion adGroupCriterion in adGroupCriteria) { PreconditionUtilities.CheckNotNull(adGroupCriterion.criterion, ShoppingMessages.AdGroupCriterionNull); if (adGroupCriterion is BiddableAdGroupCriterion) { BiddableAdGroupCriterion biddableCriterion = (BiddableAdGroupCriterion)adGroupCriterion; PreconditionUtilities.CheckState(biddableCriterion.userStatusSpecified, string.Format(ShoppingMessages.UserStatusNotSpecified, biddableCriterion.criterion.id)); if (biddableCriterion.userStatus == UserStatus.REMOVED) { continue; } } if (adGroupCriterion.criterion is ProductPartition) { ProductPartition partition = (ProductPartition)adGroupCriterion.criterion; List <AdGroupCriterion> children = null; if (!parentIdMap.TryGetValue(partition.parentCriterionId, out children)) { children = new List <AdGroupCriterion>(); parentIdMap[partition.parentCriterionId] = children; } children.Add(adGroupCriterion); } } return(parentIdMap); }
/// <summary> /// Using the criteria in <paramref name="parentIdMap"/>, recursively adds /// all children under the partition ID of <paramref name="parentNode"/> to /// <paramref name="parentNode"/>. /// </summary> /// <param name="parentNode">The parent node.</param> /// <param name="parentIdMap">The multimap from parent partition ID to list /// of child criteria</param> private static void AddChildNodes(ProductPartitionNode parentNode, Dictionary <long, List <AdGroupCriterion> > parentIdMap) { List <AdGroupCriterion> childCriteria = null; if (parentIdMap.ContainsKey(parentNode.ProductPartitionId)) { childCriteria = parentIdMap[parentNode.ProductPartitionId]; } // no children, return. if (childCriteria == null || childCriteria.Count == 0) { return; } // Ensure that the parent is a subdivision. parentNode.AsSubdivision(); foreach (AdGroupCriterion childCriterion in childCriteria) { ProductPartition partition = (ProductPartition)childCriterion.criterion; ProductPartitionNode childNode = parentNode.AddChild(partition.caseValue); childNode.ProductPartitionId = partition.id; if (childCriterion is BiddableAdGroupCriterion) { childNode = childNode.AsBiddableUnit(); Money cpcBidAmount = GetBid((BiddableAdGroupCriterion)childCriterion); if (cpcBidAmount != null) { childNode.CpcBid = cpcBidAmount.microAmount; } } else { childNode = childNode.AsExcludedUnit(); } AddChildNodes(childNode, parentIdMap); } }
/// <summary> /// Creates the unit. /// </summary> /// <param name="parent">The node that should be this node's parent. /// </param> /// <param name="value">The value being paritioned on.</param> /// <param name="bidAmount">The amount to bid for matching products, /// in micros.</param> /// <param name="isNegative">True, if this is negative criterion, false /// otherwise.</param> /// <returns>A new unit node.</returns> public ProductPartition CreateUnit(ProductPartition parent, ProductDimension value, long bidAmount, bool isNegative) { ProductPartition unit = new ProductPartition(); unit.partitionType = ProductPartitionType.UNIT; // The root node has neither a parent nor a value. if (parent != null) { unit.parentCriterionId = parent.id; unit.caseValue = value; } AdGroupCriterion criterion; if (isNegative) { criterion = new NegativeAdGroupCriterion(); } else { BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration(); CpcBid cpcBid = new CpcBid(); cpcBid.bid = new Money(); cpcBid.bid.microAmount = bidAmount; biddingStrategyConfiguration.bids = new Bids[] { cpcBid }; criterion = new BiddableAdGroupCriterion(); (criterion as BiddableAdGroupCriterion).biddingStrategyConfiguration = biddingStrategyConfiguration; } criterion.adGroupId = this.adGroupId; criterion.criterion = unit; this.CreateAddOperation(criterion); return(unit); }
/// <summary> /// Runs the code example. /// </summary> /// <param name="user">The AdWords user.</param> /// <param name="adGroupId">The ad group to which product partition is /// added.</param> public void Run(AdWordsUser user, long adGroupId) { // Get the AdGroupCriterionService. AdGroupCriterionService adGroupCriterionService = (AdGroupCriterionService)user.GetService( AdWordsService.v201506.AdGroupCriterionService); ProductPartitionHelper helper = new ProductPartitionHelper(adGroupId); // The most trivial partition tree has only a unit node as the root: // helper.createUnit(null, null, 100000); ProductPartition root = helper.CreateSubdivision(null, null); ProductCanonicalCondition newCondition = new ProductCanonicalCondition(); newCondition.condition = ProductCanonicalConditionCondition.NEW; ProductPartition newPartition = helper.CreateUnit(root, newCondition, 200000, false); ProductCanonicalCondition usedCondition = new ProductCanonicalCondition(); usedCondition.condition = ProductCanonicalConditionCondition.USED; ProductPartition usedPartition = helper.CreateUnit(root, usedCondition, 100000, false); ProductPartition otherCondition = helper.CreateSubdivision(root, new ProductCanonicalCondition()); ProductBrand coolBrand = new ProductBrand(); coolBrand.value = "CoolBrand"; helper.CreateUnit(otherCondition, coolBrand, 900000, false); ProductBrand cheapBrand = new ProductBrand(); cheapBrand.value = "CheapBrand"; helper.CreateUnit(otherCondition, cheapBrand, 10000, false); ProductPartition otherBrand = helper.CreateSubdivision(otherCondition, new ProductBrand()); // The value for the bidding category is a fixed ID for the 'Luggage & Bags' // category. You can retrieve IDs for categories from the ConstantDataService. // See the 'GetProductCategoryTaxonomy' example for more details. ProductBiddingCategory luggageAndBags = new ProductBiddingCategory(); luggageAndBags.type = ProductDimensionType.BIDDING_CATEGORY_L1; luggageAndBags.value = -5914235892932915235; helper.CreateUnit(otherBrand, luggageAndBags, 750000, false); ProductBiddingCategory everythingElse = new ProductBiddingCategory(); everythingElse.type = ProductDimensionType.BIDDING_CATEGORY_L1; helper.CreateUnit(otherBrand, everythingElse, 110000, false); try { // Make the mutate request. AdGroupCriterionReturnValue retval = adGroupCriterionService.mutate(helper.Operations); Dictionary <long, List <ProductPartition> > children = new Dictionary <long, List <ProductPartition> >(); ProductPartition rootNode = null; // For each criterion, make an array containing each of its children // We always create the parent before the child, so we can rely on that here. foreach (AdGroupCriterion adGroupCriterion in retval.value) { ProductPartition newCriterion = (ProductPartition)adGroupCriterion.criterion; children[newCriterion.id] = new List <ProductPartition>(); if (newCriterion.parentCriterionIdSpecified) { children[newCriterion.parentCriterionId].Add(newCriterion); } else { rootNode = (ProductPartition)adGroupCriterion.criterion; } } // Show the tree StringWriter writer = new StringWriter(); DisplayTree(rootNode, children, 0, writer); Console.WriteLine(writer.ToString()); } catch (Exception ex) { throw new System.ApplicationException("Failed to set shopping product partition.", ex); } }
/// <summary> /// Outputs the ProductPartition. /// </summary> protected void OutputProductPartition(ProductPartition productPartition) { if (productPartition != null) { OutputStatusMessage(string.Format("ParentCriterionId: {0}", productPartition.ParentCriterionId)); OutputStatusMessage(string.Format("PartitionType: {0}", productPartition.PartitionType)); if (productPartition.Condition != null) { OutputStatusMessage(string.Format("Condition: ")); OutputStatusMessage(string.Format("\tOperand: {0}", productPartition.Condition.Operand)); OutputStatusMessage(string.Format("\tAttribute: {0}", productPartition.Condition.Attribute)); } } }
/// <summary> /// Creates the unit. /// </summary> /// <param name="parent">The node that should be this node's parent. /// </param> /// <param name="value">The value being paritioned on.</param> /// <param name="bidAmount">The amount to bid for matching products, /// in micros.</param> /// <param name="isNegative">True, if this is negative criterion, false /// otherwise.</param> /// <returns>A new unit node.</returns> public ProductPartition CreateUnit(ProductPartition parent, ProductDimension value, long bidAmount, bool isNegative) { ProductPartition unit = new ProductPartition(); unit.partitionType = ProductPartitionType.UNIT; // The root node has neither a parent nor a value. if (parent != null) { unit.parentCriterionId = parent.id; unit.caseValue = value; } AdGroupCriterion criterion; if (isNegative) { criterion = new NegativeAdGroupCriterion(); } else { BiddingStrategyConfiguration biddingStrategyConfiguration = new BiddingStrategyConfiguration(); CpcBid cpcBid = new CpcBid(); cpcBid.bid = new Money(); cpcBid.bid.microAmount = bidAmount; biddingStrategyConfiguration.bids = new Bids[] { cpcBid }; criterion = new BiddableAdGroupCriterion(); (criterion as BiddableAdGroupCriterion).biddingStrategyConfiguration = biddingStrategyConfiguration; } criterion.adGroupId = this.adGroupId; criterion.criterion = unit; this.CreateAddOperation(criterion); return unit; }
/// <summary> /// Creates a subdivision node. /// </summary> /// <param name="parent">The node that should be this node's parent. /// </param> /// <param name="value">The value being paritioned on.</param> /// <returns>A new subdivision node.</returns> public ProductPartition CreateSubdivision(ProductPartition parent, ProductDimension value) { ProductPartition division = new ProductPartition(); division.partitionType = ProductPartitionType.SUBDIVISION; division.id = this.nextId--; // The root node has neither a parent nor a value. if (parent != null) { division.parentCriterionId = parent.id; division.caseValue = value; } BiddableAdGroupCriterion criterion = new BiddableAdGroupCriterion(); criterion.adGroupId = this.adGroupId; criterion.criterion = division; this.CreateAddOperation(criterion); return division; }
/// <summary> /// Displays the product partition tree. /// </summary> /// <param name="node">The root node.</param> /// <param name="children">The child node.</param> /// <param name="level">The tree level.</param> /// <param name="writer">The stream to write output to.</param> private void DisplayTree(ProductPartition node, Dictionary<long, List<ProductPartition>> children, int level, StringWriter writer) { // Recursively display a node and each of its children. object value = null; string type = ""; if (node.caseValue != null) { type = node.caseValue.ProductDimensionType; switch (type) { case "ProductCanonicalCondition": value = (node.caseValue as ProductCanonicalCondition).condition.ToString(); break; case "ProductBiddingCategory": value = (node.caseValue as ProductBiddingCategory).type.ToString() + "(" + (node.caseValue as ProductBiddingCategory).value + ")"; break; default: value = node.caseValue.GetType().GetProperty("value").GetValue(node.caseValue, null); break; } } writer.WriteLine("{0}id: {1}, type: {2}, value: {3}", "".PadLeft(level, ' '), node.id, type, value); foreach (ProductPartition childNode in children[node.id]) { DisplayTree(childNode, children, level + 1, writer); } }
/// <summary> /// Constructs a <see cref="ProductPartition" /> criterion corresponding to /// the node. /// </summary> /// <returns>The <see cref="ProductPartition" /> node.</returns> internal ProductPartition GetCriterion() { ProductPartition partition = new ProductPartition(); partition.id = this.ProductPartitionId; if (this.Parent != null) { partition.parentCriterionId = this.Parent.ProductPartitionId; } partition.caseValue = this.Dimension; partition.partitionType = this.IsUnit ? ProductPartitionType.UNIT : ProductPartitionType.SUBDIVISION; return partition; }
/// <summary> /// Creates the criterion for product partition. /// </summary> /// <param name="partitionId">The product partition ID.</param> /// <param name="parentPartitionId">The proudct partition ID for parent node.</param> /// <param name="caseValue">The case value.</param> /// <param name="isUnit">True, if the node is UNIT node, false otherwise.</param> /// <param name="isExcluded">True, if the node is EXCLUDE node, false otherwise.</param> /// <param name="bid">The bid to be set on a node, if it is UNIT.</param> /// <returns>An ad group criterion node for the product partition.</returns> internal static AdGroupCriterion CreateCriterionForProductPartition(long partitionId, long parentPartitionId, ProductDimension caseValue, bool isUnit, bool isExcluded, long bid) { AdGroupCriterion adGroupCriterion; ProductPartition partition = new ProductPartition() { id = partitionId, parentCriterionId = parentPartitionId, caseValue = caseValue, partitionType = isUnit ? ProductPartitionType.UNIT : ProductPartitionType.SUBDIVISION }; if (isExcluded) { NegativeAdGroupCriterion negative = new NegativeAdGroupCriterion(); adGroupCriterion = negative; } else { BiddableAdGroupCriterion biddable = new BiddableAdGroupCriterion(); biddable.userStatus = UserStatus.ENABLED; BiddingStrategyConfiguration biddingConfig = new BiddingStrategyConfiguration(); if (isUnit && bid != 0) { CpcBid cpcBid = new CpcBid() { bid = new Money() { microAmount = bid }, cpcBidSource = BidSource.CRITERION }; biddingConfig.bids = new Bids[] { cpcBid }; } biddable.biddingStrategyConfiguration = biddingConfig; adGroupCriterion = biddable; } adGroupCriterion.criterion = partition; return adGroupCriterion; }