Добро пожаловать в очередной выпуск моего Безголовый ряд. Ранее мы рассмотрели:
До сих пор мы говорили об архитектурных решениях, редактировании на странице и сравнении Optimizely Graph с другими API.
Сегодня мы сделаем следующий шаг и посмотрим на как хранить и предоставлять свои пользовательские данные в Optimizely Graph — данные, которые не обязательно поступают непосредственно из свойств CMS.
Эта статья проходит через три разных подхода:
- Использование API соглашений
- Создание пользовательского IContentApiModelProperty выполнение
- Использование SDK Graph Source
Каждый метод предлагает разный уровень контроля, гибкости и усилий. Давайте погрузимся.
Первый и наиболее простой способ повлиять на индексацию ваших данных в Optimizely Graph — это API соглашений. Этот API позволяет разработчикам изменять или расширять способ представления содержимого CMS при его отправке в конвейер индексирования. Другими словами, прежде чем ваш контент будет опубликован в Graph, API соглашений дает вам возможность изменить или дополнить данные.
Когда его использовать
Если вам нужно всего лишь:
- Исключить определенные свойства или типы контента,
- Включите несколько настраиваемых полей,
- Добавьте некоторые облегченные метаданные, полученные из существующих свойств контента.
…тогда API Conventions — ваш лучший друг.
Пример:
Допустим, у вас есть Целевая страница и Страница внутренних настроек типы контента:
// InternalSettingsPage.cs
[ContentType(DisplayName = "Internal Settings Page")]
public class InternalSettingsPage : SitePageData
{
[Display(
Name = "Some Internal Setting",
Description = "A confidential value / setting that should not be published in Graph")]
public virtual string? SomeInternalSetting { get; set; }
}
// LandingPage.cs
using EPiServer.Core;
using EPiServer.DataAnnotations;
using System.ComponentModel.DataAnnotations;
[ContentType(DisplayName = "Landing Page")]
public class LandingPage : SitePageData
{
[Display(
Name = "Secret Property",
Description = "A confidential value not published in Graph")]
public virtual string? SecretProperty { get; set; }
[Display(
Name = "Title Prefix",
Description = "Prefix for the page title")]
public virtual string? TitlePrefix { get; set; }
[Display(
Name = "Title",
Description = "The main page title")]
public virtual string? Title { get; set; }
public virtual string PageTitle()
{
return TitlePrefix + " " + Title;
}
}
Для этих типов контента вы хотите:
- Исключать Страница внутренних настроек тип контента из индексации в Graph
- Исключить Секретное свойство чтобы предотвратить его утечку в Graph, и
- Включить пользовательский Название страницы свойство (представляющее собой смесь свойств TitlePrefix и Title) в индексе Graph
Вы можете сделать это с помощью простой регистрации соглашения:
// GraphConventions.cs
using EPiServer.Framework;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using Optimizely.ContentGraph.Cms.NetCore.ConventionsApi;
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class GraphConventions : IInitializableModule
{
public void Initialize(InitializationEngine context)
{
var conventionRepository = context.Locate.Advanced.GetInstance();
conventionRepository.ExcludeContentType();
conventionRepository.ForInstancesOf()
.ExcludeField(x => x.SecretProperty);
conventionRepository.ForInstancesOf()
.IncludeField(x => x.PageTitle());
}
public void Uninitialize(InitializationEngine context) { }
}
Как только это соглашение будет зарегистрировано, Optimizely будет пропускать исключенные типы контента и применять определенные корректировки всякий раз, когда LandingPage сериализуется для индексации в Graph.
Иногда одних соглашений недостаточно.
Может быть, вы хотите сделать инъекцию динамические данные этого вообще не существует в CMS — данные, поступающие от другого сервиса, или расчетное значение, зависящее от условий выполнения.
Вот когда IContentApiModelProperty вступает в игру.
Что он делает
IContentApiModelProperty позволяет вам определить новая недвижимость который будет доступен для всех элементов контента (или выбранных) при индексации в Optimizely Graph.
Вы можете думать об этом как о подключаемом модуле для добавления пользовательских, вычисляемых или внешних данных в модель Graph.
Пример: добавление пользовательского свойства
Вот простая реализация:
using Optimizely.ContentGraph.Cms.Core.ContentApiModelProperties;
public sealed class CustomApiModelProperty : IContentApiModelProperty
{
private readonly IContentLoader _contentLoader;
public CustomApiModelProperty(IContentLoader contentLoader)
{
_contentLoader = contentLoader;
}
public string Name => "CustomPropertyName";
public object GetValue(ContentApiModel contentApiModel)
{
// Example: Load the content and derive a value dynamically
if (_contentLoader.TryGet(
new ContentReference(contentApiModel.ContentLink.Id ?? 0),
out SitePageData page))
{
return $"calculated-value-for-{page.Name}";
}
return null;
}
}
Когда это имущество будет зарегистрировано, каждый элемент контента отправленное в Optimizely Graph, будет включать дополнительное поле под названием CustomPropertyName, с любым значением, из которого вы возвращаетесь ПолучитьЗначение().
Например, выходные данные графика могут выглядеть так:
{
"name": "About Us",
"customPropertyName": "calculated-value-for-About Us"
}
Практическое использование
- Внедрение контента из внешних API (например, получение данных о наличии на страницах продуктов)
- Вычисление производных значений (например, времени чтения, средних оценок)
- Добавление метаданных среды или контекста
Последний подход является наиболее гибким и наиболее отделенным от CMS.
Если у вас есть данные полностью внешний в CMS (например, из CRM, ERP или пользовательской базы данных), вы можете использовать SDK Optimize Graph Source чтобы отправить его прямо в Graph.
SDK дает вам полный контроль над тем, что и как вы публикуете в Optimizely Graph, позволяя создавать пользовательские схемы и заполнить данные вручную.
Когда его использовать
Используйте SDK, когда:
- Вам необходимо индексировать данные, не относящиеся к CMS (например, каталоги продуктов, события, профили пользователей).
- Вы хотите синхронизировать сторонние источники данных с Graph.
- Вы создаете автономную архитектуру, в которой CMS является лишь одним из множества источников контента.
Пример: передача внешних данных
Вот упрощенный пример, основанный на SDK Graph Source на GitHub:
using Optimizely.Graph.Source.Sdk;
using Optimizely.Graph.Source.Sdk.SourceConfiguration;
public class ExternalProduct
{
public string? Id { get; set; }
public string? Name { get; set; }
public double Price { get; set; }
}
// Initialize the GraphSourceClient by calling the Create method
var source = "custom-source";
var appKey = "your-app-key";
var secret = "your-secret";
// Initialize the GraphSourceClient by calling the Create method
var client = GraphSourceClient.Create(new Uri("https://cg.optimizely.com"), source, appKey, secret);
// Add a language preference
client.AddLanguage("en");
// Configure content type for ExternalProduct
client.ConfigureContentType()
.Field(x => x.Id, IndexingType.Searchable)
.Field(x => x.Name, IndexingType.Searchable)
.Field(x => x.Price, IndexingType.Queryable);
// Save content types to Optimizely Graph
client.SaveTypesAsync();
// Instantiate and assign values for ExternalProduct
var product = new ExternalProduct
{
Id = "SKU-001",
Name = "Custom Running Shoes",
Price = 129.99,
};
// Use the client to sync the product
client.SaveContentAsync(generateId: (x) => x.Id, "en", product);
Этот код определяет пользовательскую схему (Внешний продукт) и публикует его в Optimizely Graph.
После индексации вы можете запрашивать свои данные напрямую через GraphQL — точно так же, как контент CMS.
Важное примечание об источниках Optimizely Graph:
В приведенном выше коде мы указали источник как пользовательский источник, но вы можете выбрать любое имя, чтобы логически разделить источники данных. Каждый источник действует как отдельный контейнер в Optimizely Graph.
По умолчанию содержимое CMS хранится в папке по умолчанию источник. Если бы вы использовали по умолчанию в качестве источника при отправке пользовательских типов вы рискуете перезаписать всю схему Graph для этого источника. Это потому, что вызов клиент.SaveTypesAsync() заменяет все типы контента в целевом источнике только теми, которые указаны КонфигуреКонтентТип.
Чтобы избежать нарушения данных и схемы CMS, всегда регистрируйте внешние данные под отдельным именем источника (например, пользовательский источник). Это обеспечивает изоляцию внешних типов и защиту от непреднамеренных изменений.
Пример запроса
query CustomQuery {
ExternalProduct {
items {
Id
Name
Price
}
}
}
И вы получите:
{
"data": {
"ExternalProduct": {
"items": [
{
"Id": "SKU-001",
"Name": "Custom Running Shoes",
"Price": 129.99
}
]
}
},
"extensions": {
"correlationId": "998b0a360df95906",
"cost": 23,
"costSummary": [
"ExternalProduct(23) = limit(20) + 3*fields(1)"
]
}
}
Ключевой вывод
Используйте Graph Source SDK, когда:
- Ваши данные находятся за пределами CMS,
- Вы хотите полный контроль над схемами,
- Вы интегрируете Graph как часть более крупной безголовой экосистемы.
Это самый продвинутый вариант, но он также открывает больше возможностей.
В безголовой установке Оптимизировать график становится нечто большим, чем просто уровень доставки контента.
Он может действовать как централизованный центр данных — объединение контента CMS, вычисляемых свойств и внешних наборов данных в одном унифицированном API GraphQL.
Подведем итоги:
| Подход | Лучшее для | Уровень усилий | Примечания |
|---|---|---|---|
| API соглашений | Формирование существующих данных CMS | 🟢 Низкий | Идеально подходит для переименования, исключения или небольшого дополнения данных. |
| IContentApiModelProperty | Внедрение динамических или вычисляемых данных | 🟠 Средний | Отлично подходит для добавления вычисляемых или внешних полей. |
| SDK исходного кода графа | Индексирование источников данных, отличных от CMS | 🔴Высокая | Полный контроль над схемой и индексацией |
Выбор правильного подхода зависит от ваших архитектурных целей и от того, насколько «безголовым» вы действительно хотите добиться.
В большинстве проектов лучше всего работает комбинация:
- Использовать Конвенции для быстрой настройки,
- Добавлять пользовательские свойства для динамической логики и
- Расширьте с помощью SDK когда вам нужен полный контроль.
Вот и все в этом выпуске Безголовый!
В следующей части мы рассмотрим, как эффективно запрашивать объединенные наборы данных и как разработать схему для обеспечения реальной производительности.
Дальнейшее чтение
3 ноября 2025 г.
По теме