使用Sitecore 8内容搜索API的复杂查询

本文关键字:API 复杂 查询 搜索 Sitecore 使用 | 更新日期: 2023-09-27 18:10:25

我正在尝试编写一个Linq来迭代使用sitecore内容搜索API的ID列表,但它抛出此异常

无效方法调用参数类型:Field - FieldNode - Field: supplier_categorories_sm - DCP.Common.Models.Shared.CategoryItem[]。只支持常量参数。

   //The search item class
 public class EventSupplierItem : BaseSearchItem
 {
    [IndexField("supplier_categories_sm")]
    public CategoryItem[] SupplierCategories { get; set; } //maped to multilist
 }
 //I have wrote custom converter to map the multilist to that item
 public class CategoryItem
{
    [SitecoreId]
    [IndexField("_group")]
    [TypeConverter(typeof(IndexFieldIDValueConverter))]
    public virtual ID Id { set; get; }
    [IndexField("name")]
    public string Name { get; set; }
}

创建过滤器谓词以获得结果的代码:

  var EventCategoryID = new ID(EventSupplierFilters.SupplierCategory);
                    FilterOR = FilterOR.Or(x => x.SupplierCategories.Select(a => a.Id).Contains(EventCategoryID));
                    filter = filter.And(FilterOR.Predicate);
 results = queryable.Filter(filter.Predicate);
 executedResults = results.ToList();

我也尝试使用.Any而不是.Select,但仍然抛出与Sitecore内容搜索linq在表达式中不支持AnySelect相同的异常。有谁知道处理这个问题的最好方法是什么吗?

使用Sitecore 8内容搜索API的复杂查询

在Fortis源代码中有一个如何做到这一点的示例。有2种扩展方法,.ContainsAnd.ContainsOr,采用Id列表与另一个字段进行比较。

来源:https://github.com/Fortis-Collection/fortis/blob/master/Fortis/Search/SearchExtensions.cs

你可以根据自己的需要定制。

在使用中我们叫:

var query = searchContext.GetQueryable<IItemWrapper>().ContainsOr(x => x.FieldName, arrayValues);

Sitecore LINQ可能无法解决您的复杂查询,请尝试以下操作,它将返回预期的结果:

var normalizedID = Sitecore.ContentSearch.Utilities.IdHelper.NormalizeGuid(EventSupplierFilters.SupplierCategory,true);
FilterOR = FilterOR.Or(x => x["supplier_categories_sm"].Contains(normalizedID));
filter = filter.And(FilterOR.Predicate);
results = queryable.Filter(filter.Predicate);
executedResults = results.ToList();

我认为问题的根本原因是这些表达式需要被解析为Lucene查询,这与你期望的工作相比是相当有限的。我的想法是,所有要转化为查询的东西都需要被解析成格式化的字符串查询——这里解释了更多关于这方面的信息。

最简单的方法可能是使用单个'Where'查询来一次比较一个对象,然后当你需要复杂的逻辑时,在尝试对其运行复杂的IEnumerable查询之前将其转换为List。

或者你可以深入研究并尝试理解常量表达式是如何在LINQ中工作的——尽管这不是我真正熟悉的东西。

是的,您需要获得id,然后用它们构建您的查询,而不是在过滤器或。在为搜索构建一些复杂的谓词表达式时,我遇到了很多麻烦:)

我遇到过一个类似的问题,于是使用了我自己的表达式树。

下面是一个对从搜索索引中检索到的id列表进行Contains匹配的示例。

   public static Expression<Func<CustomSearchResultItem, bool>> MatchOnMultipleValues(IEnumerable<string> arrayOfIds, string parameter)
    {
        var predicate = PredicateBuilder.True<CustomSearchResultItem>();
        foreach (var id in arrayOfIds)
        {
            // create dynamic expression tree for filter for Enumerable properties (multivalued)
            Expression constant = Expression.Constant(id);
            ParameterExpression parameterExpression = Expression.Parameter(typeof(CustomSearchResultItem), "s");
            Expression property = Expression.Property(parameterExpression, parameter);
            // Call contains method on IEnumerable
            var callExpression = Expression.Call(typeof(Enumerable), "Contains", new[] { typeof(string) }, property, constant);
            predicate = predicate.Or(Expression.Lambda<Func<CustomSearchResultItem, Boolean>>(callExpression, parameterExpression));
        }
        return predicate;
    }
  query = query.Where(ExpressionMatches.MatchOnMultipleValues(arrayIds, Id));

CustomSearchResultItem是我自己的POCO类,用于处理搜索结果,其功能与EventSupplierItem类相同。matchonmultiplevalues方法是在字符串数组上做一个contains,但你可以将其调整为使用CategoryItem数组。