Home » Оптимизация поиска и навигации. Часть 2

Оптимизация поиска и навигации. Часть 2

Введение

Продолжение от Часть 1 – Советы по поискусегодня я поделюсь следующей частью — советами по фильтрам.

В этой статье используются следующие версии платформ: Optimizely CMS 12.27.x, Optimizely Customized Commerce 14.21.x и EpiServer.Find 16.1.x.

Как добавить новый пользовательский фильтр

Во встроенном поиске и навигации Optimizely по умолчанию используются следующие фильтры:

  • И Фильтр
  • Булевский фильтр
  • Фильтр существует
  • Фильтр георасстояния
  • Фильтр диапазона георасстояний
  • Фильтр геополигонов
  • Имеет Детский Фильтр
  • Фильтр идентификаторов
  • Фильтр километров
  • Вложенный фильтр
  • Не фильтровать
  • Или Фильтр
  • Фильтр префиксов
  • Фильтр запроса
  • Фильтр диапазона
  • Фильтр скриптов
  • Фильтр терминов

Эти фильтры генерируют соответствующий основной текст при отправке запросов в Elasticsearch через фреймворк поиска и навигации с использованием JSON-конвертеров.

Что делать, если фильтр существует в Elasticsearch, но не в Search & Navigation, или существующий фильтр не имеет требуемых параметров? Можно ли создать новый фильтр?

Да, вы можете добавлять новые пользовательские фильтры в Поиск и навигацию. Вот как создать новый фильтр регулярного выражения.

Шаг 1: Создание нового DTO на основе класса фильтра

[JsonConverter(typeof(RegularExpressionFilterConverter))]
public class RegularExpressionFilter : Filter
{
    [JsonIgnore]
    public string Field { get; set; }

    [JsonProperty("value")]
    public string Value { get; set; }

    public RegularExpressionFilter(string field, string value)
    { 
        Field = field;
        Value = value;
    }
}

Шаг 2: Создайте новый JSON-конвертер для нового фильтра

internal class RegularExpressionFilterConverter : CustomWriteConverterBase
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value is not RegularExpressionFilter)
        {
            writer.WriteNull();
            return;
        }
        var regularExpressionFilter = (RegularExpressionFilter)value;
        writer.WriteStartObject();
        writer.WritePropertyName("regexp");
        writer.WriteStartObject();
        writer.WritePropertyName(regularExpressionFilter.Field);
        serializer.Serialize(writer, regularExpressionFilter.Value);
        writer.WriteEndObject();
        writer.WriteEndObject();
    }
}

Шаг 3: Создайте новый метод фильтрации для вашего поиска

public static DelegateFilterBuilder MatchRegularExpression(this string value, string input)
{ 
   return new DelegateFilterBuilder((string field) => new RegularExpressionFilter(field, input));
}

Шаг 4: Примените новый фильтр к вашему поиску

if (!string.IsNullOrEmpty(filterOptions.Q)){
    query = query.Filter(x => x.Name.MatchRegularExpression(filterOptions.Q));
}

Ключевое слово для поиска в этом примере может быть текстом в синтаксисе регулярного выражения. Синтаксис для ElasticSearch можно найти здесь.

Read more:  Дроновый дождь над Украиной ночью. Шесть самолетов сбиты

Как применить И/ИЛИ для группы подфильтров

Рассмотрим следующий пример:

У вас есть тип контента продукта со следующими свойствами:

[Display(Name = "On sale", GroupName = SystemTabNames.Content, Order = 50)]
public virtual bool OnSale { get; set; }

[Display(Name = "New arrival", GroupName = SystemTabNames.Content, Order = 55)]
public virtual bool NewArrival { get; set; }

[Display(Name = "Best seller", GroupName = SystemTabNames.Content, Order = 58)]
public virtual bool BestSeller { get; set; }

Чтобы найти товары, продающиеся по сниженным ценам, и/или новые поступления, вы можете:

Используйте оператор И/ИЛИ в FilterExpression:

query = query.Filter(x => x.OnSale.Match(true) & x.NewArrival.Match(true));
query = query.Filter(x => x.OnSale.Match(true) | x.NewArrival.Match(true));

Используйте фильтр И/ИЛИ:

var andFilter = new AndFilter();
andFilter.Filters.Add(new TermFilter(searchClient.GetFullFieldName("OnSale", typeof(bool)), true));
andFilter.Filters.Add(new TermFilter(searchClient.GetFullFieldName("NewArrival", typeof(bool)), true));
query = query.Filter(andFilter);
var orFilter = new OrFilter();
orFilter.Filters.Add(new TermFilter(searchClient.GetFullFieldName("OnSale", typeof(bool)), true));
orFilter.Filters.Add(new TermFilter(searchClient.GetFullFieldName("NewArrival", typeof(bool)), true));
query = query.Filter(orFilter);

Обратите внимание, что имя поля, понимаемое Elasticsearch, не совпадает с именем поля в модели типа контента Optimizely. Используйте следующий метод для получения имени индексированного поля:

public static string GetFullFieldName(this IClient searchClient, string fieldName, Type type)
{
    if (type != null)
        return fieldName + searchClient.Conventions.FieldNameConvention.GetFieldName(Expression.Variable(type, fieldName));
    return fieldName;
}

За и против:

  • Использование оператора И/ИЛИ: Короткий и простой в использовании, но не подходит для динамического построения фильтров.
  • Использование фильтра И/ИЛИ: Более длинный код, но позволяющий гибко строить фильтры на основе имен полей и входных значений.

Как сортировать результаты поиска на основе набора условий

Поиск и навигация позволяют сортировать по одному или нескольким полям:

query = query.OrderBy(x => x.Name).ThenByDescending(x => x.StartPublish);

Пример требования: Размещайте в верхней части страницы товары-бестселлеры, за ними следуют новинки, а затем товары со скидками.

Добиться этого можно с помощью усиления соответствия:

query = query.BoostMatching(x => (x as GenericProduct).NewArrival.Match(true), 2);
query = query.BoostMatching(x => (x as GenericProduct).OnSale.Match(true), 3);
query = query.BoostMatching(x => (x as GenericProduct).BestSeller.Match(true), 4);

Проблема: Если продукт продается и является новым, он отображается наверху, даже если он не является бестселлером. Оценка этого продукта (5) выше, чем у бестселлера (4).

Read more:  Подозреваемый в нападении в Страсбурге приговорен к 30 годам тюрьмы – DW – 04.04.2024

Решение: Убедитесь, что бестселлеры всегда находятся наверху, установив значение Boost по следующему правилу: Следующее значение Boost = сумма всех предыдущих значений Boost + 1:

query = query.BoostMatching(x => (x as GenericProduct).NewArrival.Match(true), 2);
query = query.BoostMatching(x => (x as GenericProduct).OnSale.Match(true), 3);
query = query.BoostMatching(x => (x as GenericProduct).BestSeller.Match(true), 6);

Заключение

Эти советы основаны на моем опыте работы с поиском и навигацией. Надеюсь, они помогут вам реализовать аналогичные функции.

Приятного вам программирования!

01 июля 2024 г.

Leave a Comment

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