3 способа хранения пользовательских данных в Optimizely Graph

Добро пожаловать в очередной выпуск моего Безголовый ряд. Ранее мы рассмотрели:

До сих пор мы говорили об архитектурных решениях, редактировании на странице и сравнении Optimizely Graph с другими API.
Сегодня мы сделаем следующий шаг и посмотрим на как хранить и предоставлять свои пользовательские данные в Optimizely Graph — данные, которые не обязательно поступают непосредственно из свойств CMS.

Эта статья проходит через три разных подхода:

  1. Использование API соглашений
  2. Создание пользовательского IContentApiModelProperty выполнение
  3. Использование 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
Read more:  Выбросы парниковых газов в центрах обработки данных искусственного интеллекта составят 10% мировых! Эксперты раскрывают 6 стратегий достижения нулевых выбросов

Вы можете сделать это с помощью простой регистрации соглашения:

// 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.

Read more:  Начинается подготовка к увеличению помощи в секторе Газа, поскольку прекращение огня дает надежду на окончание двухлетней войны: -

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() заменяет все типы контента в целевом источнике только теми, которые указаны КонфигуреКонтентТип.

Read more:  Система экологического перехода в центре спора по поводу цен на энергоносители

Чтобы избежать нарушения данных и схемы 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 г.

По теме

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.