在DateTime-range上使用ContentSearch-API查询Sitecore Lucene-index

时间:2014-02-14 17:53:19

标签: c# .net linq sitecore

目前我正在开发一个实施Sitecore 7.0 Update 2的项目

在我的数据模板中,我有一个名为Begin Date的字段和另一个End Date。这两个字段是使用“日期”类型(而不是日期时间)创建的。因此,当我编辑和创建项目时,它会显示一个日期选择器,并且我已经提交了一些带有虚拟内容的项目,以及上个月和当月的开始和结束日期。

我想要实现的是获取所选月份内的所有项目。我的方法包含一个月和一年的整数作为参数。这应该控制具有应该从Lucene sitecore_master_index获得的开始日期和结束日期的项目。 Date-field的Sitecore原始值是ISO datetime-strings。

所以这是我试图获取所选月份中所有项目的查询。

private void GetItems(int month, int year)
{
    using (
        IProviderSearchContext context =
                ContentSearchManager.
GetIndex("sitecore_master_index").CreateSearchContext())
    {
         List<EventSearchResultItem> allEvents =     context.GetQueryable<EventSearchResultItem>(new     CultureExecutionContext(Sitecore.Context.Language.CultureInfo))
         .Where(s =>
                s.TemplateId == this.EventTemplateID &&
                ((s.BeginDate.Month == month && s.BeginDate.Year == year) || (s.EndDate.Month == month && s.EndDate.Year == year))
                    )
        .ToList();
    }
}

使用这个Where语句,我希望将某些事件模板的项目返回到应该包含该月份日期的地方。但它返回一个空的结果集。缺点是我无法调试Lamba表达式,所以不幸的是我不知道该范围的值。但不是第1年和第9999年之间的事情:)在IQueryable执行查询并返回一些内容之后,列表中的对象包含属性的正确DateTime。因此它将索引中的字段正确映射到属性。此外,如果我删除日期检查,只有TemplateID检查是Where子句,它返回结果。但即使将BeginDate与DateTime.MinValue和DateTime.MaxValue进行比较也不会返回任何内容。

它使用我为此创建的POCO类EvenSearchResultItem。在这个类中,我已将字段映射到属性,并添加了TypeConverter以将其转换为DateTime。至少,它应该......

public class EventSearchResultItem : SearchResultItem
{
    [TypeConverter(typeof(IndexFieldDateTimeValueConverter))]
    [IndexField("__begin_date")]
    public DateTime BeginDate { get; set; }

    [TypeConverter(typeof(IndexFieldDateTimeValueConverter))]
    [IndexField("__end_date")]
    public DateTime EndDate { get; set; }
}

在Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config中我添加了-tag中的字段(也尝试了-tag,但结果没有那么不同)。 参见:

<field luceneName="__begin_date" storageType="yes" indexType="tokenized" format="yyyyMMdd">Begin Date</field>
<field luceneName="__end_date" storageType="yes" indexType="tokenized" format="yyyyMMdd">End Date</field>

因此,在重新索引后,Luke(用于查看Lucene索引内容的Java应用程序)字段出现并包含该项目的给定日期(在yyyyMMdd&gt; 20140214中)。就像其他日期字段一样,例如__smallCreatedDate。

我可以通过将查询修改为:

来解决此问题
List<EventSearchResultItem> allEvents = context.GetQueryable<EventSearchResultItem>()
    .Where(s =>
        (s["Begin Date"].StartsWith(string.Concat(year, month.ToString("00"))) || s["End Date"].StartsWith(string.Concat(year, month.ToString("00"))))
    )
    .ToList();

这是Stack Overflow上另一个问题的解决方案。但我不认为这是最佳实践和可靠。不幸的是,谷歌没有任何其他选择。我猜想有什么东西可能是对的吗?

有没有人有经验从IQueryable过滤DateTime上的Lucene结果?并且可以指出我正确的方向?

2 个答案:

答案 0 :(得分:6)

尝试以下方法:

private void GetItems(int month, int year)
        {
            DateTime startDate = new DateTime(year,month,1);
            DateTime endDate = new DateTime(year,month, DateTime.DaysInMonth(year, month));
            using ( IProviderSearchContext context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
            {
                List<EventSearchResultItem> allEvents = context.GetQueryable<EventSearchResultItem>(new CultureExecutionContext(Sitecore.Context.Language.CultureInfo))
                .Where(s =>
                       s.TemplateId == this.EventTemplateID &&
                       ((s.BeginDate >= startDate) || (s.EndDate <= endDate))
                           )
               .ToList();
            }
        }

编辑:只是解释为什么你的方法不起作用,当lucene索引任何日期字段时,它被索引为数字,格式将为'yyyyMMdd',例如2014年2月18日索引为20140218,所以当你可以看到它存储为一个整数,年,月和日都在同一个字段中,所以你不能只与年份或月份比较等。

现在在Sitecore linq中,如果要查询日期字段,必须与'DateTime'类型进行比较,Sitecore知道必须将DateTime对象转换为'yyyyMMdd'格式才能将其传递给Lucene。

答案 1 :(得分:0)

您可以尝试从索引配置和EventSearchResult项中的字段定义中删除下划线。我以前见过这个问题。

<field luceneName="begindate" storageType="yes" indexType="tokenized" format="yyyyMMdd">Begin Date</field>
<field luceneName="enddate" storageType="yes" indexType="tokenized" format="yyyyMMdd">End Date</field>

[TypeConverter(typeof(IndexFieldDateTimeValueConverter))]
    [IndexField("begindate")]
    public DateTime BeginDate { get; set; }

    [TypeConverter(typeof(IndexFieldDateTimeValueConverter))]
    [IndexField("enddate")]
    public DateTime EndDate { get; set; }