优化搜索和导航 – 第 2 部分

介绍

继续 第 1 部分 – 搜索技巧,今天我将分享下一部分——过滤技巧。

本文使用的平台版本是 Optimizely CMS 12.27.x、Optimizely Customized Commerce 14.21.x 和 EpiServer.Find 16.1.x。

如何添加新的自定义过滤器

在内置的 Optimizely Search & Navigation 中,默认过滤器如下:

  • 并过滤
  • 布尔过滤器
  • 存在过滤器
  • 地理距离过滤器
  • 地理距离范围过滤器
  • 地理多边形过滤器
  • 有子过滤器
  • ID 过滤器
  • 公里过滤器
  • 嵌套过滤器
  • 不过滤
  • 或筛选
  • 前缀过滤器
  • 查询过滤器
  • 范围过滤器
  • 脚本过滤器
  • 术语过滤器

这些过滤器在使用 JSON 转换器通过搜索和导航框架向 Elasticsearch 发送请求时会生成相应的正文。

如果过滤器存在于 Elasticsearch 中但不存在于搜索和导航中,或者现有过滤器缺少必需的参数,该怎么办?您可以创建新的过滤器吗?

是的,您可以在搜索和导航中添加新的自定义过滤器。以下是如何构建新的正则表达式过滤器。

步骤 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 的语法 这里

如何对一组子过滤器应用 AND/OR

请考虑以下示例:

您有一个具有以下属性的产品内容类型:

[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 中使用 AND/OR 运算符:

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

使用 AND/OR 筛选器:

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 Content Type Model 中的字段名不一样,使用如下方法获取索引的字段名:

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;
}

优点和缺点:

  • 使用 AND/OR 运算符: 简短且易于使用,但不适合动态构建过滤器。
  • 使用 AND/OR 过滤器: 代码较长,但允许根据字段名称和输入值灵活地构建过滤器。

如何根据一组条件对搜索结果进行排序

搜索和导航允许根据一个或多个字段进行排序:

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)。

解决方案: 通过设置提升值来确保畅销商品始终位于顶部,规则如下:下一个提升值 = 所有先前提升值的总和 + 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);

结论

这些技巧是根据我使用搜索和导航的经验得出的。希望它们能帮助您实现类似的功能。

享受编码吧!

2024 年 7 月 1 日

1719859010
#优化搜索和导航 #第 #部分
2024-07-01 08:44:17

Leave a Reply

Your email address will not be published. Required fields are marked *

近期新闻​

编辑精选​