在linq中进行分面搜索

时间:2013-02-21 19:48:17

标签: asp.net-mvc linq faceted-search

在我的项目中,我正在尝试使用Linq实现分面搜索。我不想使用Solr,Lucene等......

我的数据库:

产品

+----+------+
| id | name |
+----+------+
| 1  | prod1|
+----+------+
| 2  | prod2|
+----+------+

属性

+----+--------+---------+
| id |  name  | alias   | 
+----+--------+---------+
| 1  | Weight | weight  |
+----+--------+---------+
| 2  | Height | height  |
+----+--------+---------+

+----+---------------+---------+---------+
| id |  attribute_id | value   |  alias  | 
+----+---------------+---------+---------+
| 1  |      1        |  10 g   |  10m    |
+----+---------------+---------+---------+
| 2  |      1        |  20 g   |  20m    | 
+----+---------------+---------+---------+
| 3  |      2        |  10 m   |  10m    | 
+----+---------------+---------+---------+
| 4  |      2        |  20 m   |  20m    | 
+----+---------------+---------+---------+

products_values

+---------------+---------+
|  product_id   | value_id| 
+---------------+---------+
|      1        |  1      | 
+---------------+---------+
|      1        |  2      | 
+---------------+---------+
|      1        |  3      | 
+---------------+---------+
|      2        |  1      | 
+---------------+---------+

查询选择,例如:site.com/filter/weight=10g_20g;height=10h/

过滤器的POCO模型:

public class Filter
{
 public string Attribute { get; set; }
 public IEnumerable<Value> Values{ get; set; }
}

此模型用于自定义模型绑定。

但是从现在开始,填充过滤器模型,我不知道如何实现选择产品并在过滤器中选择“活动”值(使用计数启用产品)。填充过滤器和产品表必须分开?或者,可能是单一行动?我很高兴看到使用Linq实现分面搜索的分步指南。

1 个答案:

答案 0 :(得分:0)

关系数据库和LINQ是Faceting搜索的糟糕开始,但我分享了你的梦想......我在上面看到的技术障碍并不是因为你可以动态建立OR关系来检索你的结果使用PredicateBuilder从products表中。如果我理解你想要一个查询来检查每个Alias的一堆OR关系以及每个值的OR关系。与别名匹配的任何产品和任何一个值都匹配。如果别名不匹配,那么您不必担心这些值。生成基本查询后,执行group by以删除重复项。

以下是迭代值列表并构建AND关系查询的示例。在您的情况下,您将在别名之间构建OR关系。在这种情况下,我的queryBuilders包含要匹配的值的集合,我传入当前的Queryable,因为您需要将语句链接在一起。

  public static IQueryable<MeetingPayment> GetViewSpecificQuery(IQueryable<MeetingPayment> query, IInvoiceViewDetail viewToUse, IEnumerable<IInvoiceViewQueryBuilder> queryBuilders)
        {
            Expression<Func<MeetingPayment, bool>> predicate = PredicateBuilder.True<MeetingPayment>();

            foreach (IInvoiceViewQueryBuilder builder in queryBuilders)
            {
                Expression<Func<MeetingPayment, bool>> predicateItem = builder.GetQuery(predicate, viewToUse);

                if (predicateItem != null)
                {
                    predicate = predicate.And(predicateItem.Expand()).Expand();
                }
            }

            return query.Where(predicate.Expand());
        }

这是一个单独的过滤器,在您使用10g和20g时,在一组值之间创建OR关系。

public Expression<Func<MeetingPayment, bool>> GetQuery(Expression<Func<MeetingPayment, bool>> query, IInvoiceViewDetail viewToUse)
            {
                    var ids = viewToUse.InvoiceStatuses.Select(x => x.Id).ToList();

                    if (!ids.Any()) return null;

                    var predicate = PredicateBuilder.False<MeetingPayment>();

                    foreach (var id in ids)
                    {
                        int? closure = id;
                        predicate = predicate.Or(x => x.InvoiceStatus == (InvoiceStatusEnum) closure);
                    }

                    return predicate;
            }
祝你好运。