1745878348
2025-04-28 10:57:00
今日のペースの速いデジタル景観では、 パーソナライズがすべてです。顧客は、ブランドとやり取りするときはいつでも、関連性のあるテーラードエクスペリエンスを期待しています。その期待に応えることで、成功をもたらすことができます。それがここです Optimizelyの製品推奨 機能は輝いています。
Optimizely製品の推奨とは何ですか?
Optimizelyの製品推奨機能はaです 強力なAI駆動型ツール ブランドが顧客に超個人化された製品の提案を提供できるように設計されています。 Optimizely Commerceプラットフォームに組み込まれており、両方にシームレスに統合されています コマースクラウド そして カスタマイズされたコマース(以前のエピソーバーコマース)。
静的製品リストに依存する代わりに、Optimizelyを使用します 機械学習アルゴリズム そして リアルタイムの顧客行動 適切な製品を適切なタイミングで適切な視聴者に動的に表現します。
なぜ製品の推奨が重要なのですか?
- コンバージョン率を高めます
関連する製品の提案により、顧客が関与し続け、そうでないことがわからないかもしれない製品を発見するのに役立ち、売り上げの増加につながります。 - カスタマーエクスペリエンスを強化します
ユーザーがサイトが「理解している」ように感じると、滞在し、閲覧し、購入する可能性が高くなります。 - 平均注文値を増やします
スマートなクロスセリングと推奨事項を介したアップセリングは、顧客がカートにさらに追加することを促すことができます。 - 直帰率を下げます
魅力的な代替品または関連アイテムを提示すると、サイトの訪問者が長くなります。
トラブルシューティング
実装中に、ここで概説したいくつかの課題に直面しました。
互換性のあるパッケージ
開始する前に、使用しているコマースバージョンを確認し、関連するパッケージの互換性のあるバージョンを特定してください。
たとえば、私の場合、私はepirerver.commerce 13.33.0を使用していたので、epirerver.personalization.commerceとepirerver.tracking.commerceバージョン3.2.37をインストールしました。
構成
単一のカタログを使用している場合は、に従ってください シングルサイト 構成;それ以外の場合は、を使用します マルチサイト 構成アプローチ。マルチサイトのチャネルベースのセットアップで作業していたので、構成中に間違いを犯しました。 ウェブ の代わりに ウェブ、そして同様に 携帯 の代わりに 携帯。これらの値はそうであることに注意してください 大文字と小文字を区別、そのため、正しい低ケースの用語を使用して、構成の問題を回避してください。
単一サイト
マルチサイト:
マルチサイト構成はです スコープベース。複数のカタログを使用している場合は、以下に示すように構成を繰り返しフォームに設定する必要があります。
特定の価格設定(グループ価格)を同期する
「製品の輸出ジョブ」は、「すべての顧客」価格設定グループのみを同期します。特定の価格設定グループの価格を同期するには、IENTRYPRICESERVICEを使用してそのグループの価格を取得します。
例えば
public class DefaultEntryPriceService : IEntryPriceService
{
private readonly IPromotionEngine _promotionEngine;
private readonly IMarketService _marketService;
private readonly IPriceService _priceService;
private readonly bool _calculateDiscountPrices;
private readonly IPricingService _pricingService;
public DefaultEntryPriceService(IPromotionEngine promotionEngine, IMarketService marketService, IPricingService pricingService)
{
_promotionEngine = promotionEngine;
_marketService = marketService;
_pricingService = pricingService;
_calculateDiscountPrices = !bool.TryParse(ConfigurationManager.AppSettings["episerver:personalization.CalculateDiscountPrices"], out _calculateDiscountPrices) || _calculateDiscountPrices;
}
public IEnumerable GetPrices(IEnumerable entries, DateTime validOn, string scope)
{
CustomEntryPriceService entryPriceService = this;
List catalogKeys = entries
.Where(x => x is IPricing)
.Select(new Func(entryPriceService.GetCatalogKey))
.ToList();
Dictionary codeContentLinkMap = entries.ToDictionary(c => c.Code, c => c.ContentLink);
IEnumerable source1 = entryPriceService._marketService.GetAllMarkets().Where(x => x.IsEnabled);
List source2 = new List();
foreach (IMarket market in source1)
{
foreach (CatalogKey key in catalogKeys)
{
//Read price for specific group from your service
var price = _pricingService.GetConsumerListPricing(key.CatalogEntryCode, market);
source2.Add(new PriceValue
{
CatalogKey = key,
MarketId = market.MarketId,
UnitPrice = new Money(price ?? decimal.Zero, market.DefaultCurrency)
});
}
}
foreach (var priceValue in source2.GroupBy(c => new
{
c.CatalogKey,
c.UnitPrice.Currency
}).Select(g => g.OrderBy(x => x.UnitPrice.Amount).First()).ToList())
{
ContentReference contentLink;
if (codeContentLinkMap.TryGetValue(priceValue.CatalogKey.CatalogEntryCode, out contentLink))
{
Money salePrice = priceValue.UnitPrice;
if (entryPriceService._calculateDiscountPrices)
{
var market = _marketService.GetMarket(priceValue.MarketId);
//Read Discounted Price
var discountPrice = _pricingService.GetConsumerDiscountPricing(
priceValue.CatalogKey.CatalogEntryCode,
market) ?? decimal.Zero;
salePrice = discountPrice == 0
? priceValue.UnitPrice
: new Money(discountPrice, market.DefaultCurrency);
}
yield return new EntryPrice(contentLink, priceValue.UnitPrice, salePrice);
}
}
}
private CatalogKey GetCatalogKey(EntryContentBase entryContent)
{
return new CatalogKey(entryContent.Code);
}
}
ターゲット特定の市場:
特定の市場向けの製品をターゲットにするときは、icatalogitemfilterを使用して、フィードを製品の推奨に同期する前に、カタログから製品をフィルタリングします。
私たちの場合、サイトの1つについて、16を超える市場をターゲットにしています。ただし、中国市場のフィードを同期する問題に遭遇しました。 Unicode製品URLは製品の推奨フィードと互換性がなかったため(Unicodeの問題を最適に修正する必要があります)。その結果、特定の市場向けにのみこの機能を開始することにしました。
例えば
public class DefaultCatalogItemFilter : ICatalogItemFilter
{
private readonly IPublishedStateAssessor _publishedStateAssessor;
private List languages = new List() { "en", "en-CA", "fr-CA" };
public DefaultCatalogItemFilter(IPublishedStateAssessor publishedStateAssessor)
{
_publishedStateAssessor = publishedStateAssessor;
}
public bool ShouldFilter(CatalogContentBase content, string scope)
{
if (_publishedStateAssessor.IsPublished(content, PublishedStateCondition.None) &&
languages.Any(x => string.Equals(x, content.Language.Name, StringComparison.InvariantCultureIgnoreCase)))
{
return false;
}
return !_publishedStateAssessor.IsPublished(content, PublishedStateCondition.None);
}
}
製品フィードの特定の属性を同期します
カタログエントリのフィードに同期するための特定の属性をターゲットにするには、ientryattributeserviceを使用します。このサービスは、特定のルールを適用して、推奨領域で製品の表示方法を制御するのに役立ちます。
この場合、14を超えるカタログに単一のコードベースを使用しています。ただし、製品とバリアントには、他のサイトのフィードに含めることができない珍しいプロパティがあります。
public class DefaultEntryAttributeService : IEntryAttributeService
{
private readonly CatalogFeedSettings _catalogFeedSettings;
private readonly IVariantAttributeService _variantAttributeService;
public DefaultEntryAttributeService(CatalogFeedSettings catalogFeedSettings, IVariantAttributeService variantAttributeService)
{
_catalogFeedSettings = catalogFeedSettings;
_variantAttributeService = variantAttributeService;
}
public bool CanBeRecommended(EntryContentBase content, decimal stock, string scope)
{
return stock > 0M;
}
public IDictionary GetAttributes(EntryContentBase content, string scope)
{
List userMetaFieldNames = GetUserMetaFields(content).ToList();
Dictionary attributes = new Dictionary();
if (!userMetaFieldNames.Any())
return attributes;
// Read attributes from your list that you would like to exclude from feed
_catalogFeedSettings.ExcludedAttributes = RecommendationHelper.ExcludeAttributes;
HashSet excludedAttributes = new HashSet(_catalogFeedSettings.ExcludedAttributes, StringComparer.OrdinalIgnoreCase);
foreach (PropertyData propertyData in content.Property.Where(x => IsValidContentProperty(x, userMetaFieldNames, excludedAttributes)))
{
attributes.Add(propertyData.Name, propertyData.Value.ToString());
}
if (content is MyVariant variant)
{
foreach (var attr in RecommendationHelper.IncludeAttributes) // Include specific attributes
{
if (attributes.Any(x => string.Equals(x.Key, attr, StringComparison.OrdinalIgnoreCase)))
continue;
// Read the value for attribute if exists in catalog entries
var value = _variantAttributeService.GetAttributeValueByName(attr, variant);
if (!string.IsNullOrWhiteSpace(value))
{
attributes.Add(attr, value);
}
}
}
return attributes;
}
public string GetDescription(EntryContentBase entryContent, string scope)
{
return entryContent[_catalogFeedSettings.DescriptionPropertyName]?.ToString();
}
public string GetTitle(EntryContentBase entryContent, string scope)
{
return !string.IsNullOrEmpty(entryContent.DisplayName) ? entryContent.DisplayName : entryContent.Name;
}
private bool IsValidContentProperty(
PropertyData property,
IEnumerable userMetaFieldNames,
HashSet excludedAttributes)
{
return userMetaFieldNames.Any(x => x.Equals(property.Name))
&& !property.Name.Equals("_ExcludedCatalogEntryMarkets")
&& !property.Name.Equals("DisplayName")
&& !property.Name.Equals("ContentAssetIdInternal")
&& !property.Name.StartsWith("Epi_")
&& property.Value != null
&& !excludedAttributes.Contains(property.Name);
}
public IEnumerable GetUserMetaFields(EntryContentBase content)
{
var metaClass = Mediachase.MetaDataPlus.Configurator.MetaClass.Load(new MetaDataContext()
{
UseCurrentThreadCulture = false,
Language = content.Language.Name
}, content.MetaClassId);
return
metaClass != null
? metaClass.GetUserMetaFields().Select(x => x.Name).ToList()
: null ?? Enumerable.Empty();
}
}
製品ページトラッキング
バリアントコードの代わりに製品コードを使用して、製品を追跡します。
ネイティブの実装で課題に遭遇した場合は、お気軽にご連絡ください。
乾杯!
2025年4月28日
#Optimizely製品の推奨トラブルシューティング #Optimizely