![](https://world.optimizely.com/resources/images/SocialShareImage.jpg)
介绍
继续 第 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