1

在我的项目中,我正在尝试使用 Linq 实现 Faceted 搜索。我不想使用 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    | 
+----+---------------+---------+---------+

产品价值

+---------------+---------+
|  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 实现分面搜索的分步指南。

4

1 回答 1

0

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

这是一个迭代值列表并建立 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());
        }

这是一个单独的过滤器,其中在一组值之间创建 OR 关系,就像您对 10g 和 20g 所做的那样。

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

祝你好运。

于 2013-09-12T22:35:49.097 回答