3

Elasticsearch.Nest 教程系列 10-3 常用类型:Date math expressions | 日期数字表达...

 2 years ago
source link: https://blog.zhuliang.ltd/2020/01/backend/Elasticsearch-Nest-Date-math-expression.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Elasticsearch.Nest 教程系列 10-3 常用类型:Date math expressions | 日期数字表达式

create: 2020-01-23 12:45:01 | update: 2020-01-23 12:15:44 本文总阅读量:  次  |  文章总字数: 1.1k 字  |  阅读约需: 5 分钟


在“查询/过滤”的时候支持使用日期类型的数学表达式。表达式以“锚定”日期开始,该日期可以是现在,也可以是以“||”结尾的日期字符串。它后面可以是一个数学表达式,支持 +,- 和 /(四舍五入)。支持的单位有:

  • y (year)
  • M (month)
  • w (week)
  • d (day)
  • h (hour)
  • m (minute)
  • s (second)

ES 中的 Date Math

使用 DateMath 提供的静态方法:

Expect("2020-01-23T00:00:00").WhenSerializing(Nest.DateMath.Anchored(new DateTime(2020,01, 23)));

字符串则会隐式转换为 DateMath

Expect("now").WhenSerializing<Nest.DateMath>("now");

DateMath 对于入参会进行一定程度的容错:

var nonsense = "now||*asdaqwe";  //“*asdaqwe”不是一个有效的时间表达式
Expect(nonsense)
    .WhenSerializing<Nest.DateMath>(nonsense)
    .AssertSubject(dateMath => ((IDateMath)dateMath)
        .Anchor.Match(
            d => d.Should().NotBe(default(DateTime)),
            s => s.Should().Be(nonsense)
        )
    );

DateTime 还会隐式转换为简单的日期数学表达式

  • 哪怕经过序列化/反序列化后,所得的Anchor 仍将是实际的 DateTime。
var date = new DateTime(2020,1, 23); //将会倍序列化为 "2020-01-23T00:00:00"

//UTC 示例
var utcDate = new DateTime(2020, 1, 23, 0, 0, 0, DateTimeKind.Utc); //将会倍序列化为 "2020-01-23T00:00:00Z"

范围可以链接到简单表达式

Expect("now+1d").WhenSerializing(Nest.DateMath.Now.Add("1d"));

Expect("now+1d-1m").WhenSerializing(
    Nest.DateMath.Now.Add("1d").Subtract(TimeSpan.FromMinutes(1)));

经过四舍五入的表达式,之后不能再使用范围进行链接,如下:

Expect("now+1d-1m/d").WhenSerializing(
    Nest.DateMath.Now.Add("1d")
        .Subtract(TimeSpan.FromMinutes(1))
        .RoundTo(DateMathTimeUnit.Day));

锚定日期时,需要在锚点和范围之间使用分隔符 “||”。同样,可以链接多个范围

Expect("2020-01-23T00:00:00||+1d-1m").WhenSerializing(
    Nest.DateMath.Anchored(new DateTime(2020,1,23))
        .Add("1d")
        .Subtract(TimeSpan.FromMinutes(1)));

含有小数时间

Elasticsearch中的日期数学表达式不支持小数。

为了在 NEST 中更轻松地使用日期数学,从字符串,TimeSpan 和 double 转换而来的值会将小数部分转换为最大的整数值和单位,四舍五入到最接近的秒数。

Expect("now+1w").WhenSerializing(Nest.DateMath.Now.Add(TimeSpan.FromDays(7)));

Expect("now+1w").WhenSerializing(Nest.DateMath.Now.Add("1w"));

Expect("now+1w").WhenSerializing(Nest.DateMath.Now.Add(604800000));

Expect("now+7d").WhenSerializing(Nest.DateMath.Now.Add("7d"));

Expect("now+30h").WhenSerializing(Nest.DateMath.Now.Add(TimeSpan.FromHours(30)));

Expect("now+30h").WhenSerializing(Nest.DateMath.Now.Add("1.25d"));

Expect("now+90001s").WhenSerializing(
    Nest.DateMath.Now.Add(TimeSpan.FromHours(25).Add(TimeSpan.FromSeconds(1))));

Expect("now+90000s").WhenSerializing(
    Nest.DateMath.Now.Add(TimeSpan.FromHours(25).Add(TimeSpan.FromMilliseconds(1))));

Expect("now+1y").WhenSerializing(Nest.DateMath.Now.Add("1y"));

Expect("now+12M").WhenSerializing(Nest.DateMath.Now.Add("12M"));

Expect("now+18M").WhenSerializing(Nest.DateMath.Now.Add("1.5y"));

Expect("now+52w").WhenSerializing(Nest.DateMath.Now.Add(TimeSpan.FromDays(7 * 52)));

可以使用构造函数控制舍入,并传递一个值进行舍入:

Expect("now+2s").WhenSerializing(
    Nest.DateMath.Now.Add(new DateMathTime("2.5s", MidpointRounding.ToEven)));

Expect("now+3s").WhenSerializing(
    Nest.DateMath.Now.Add(new DateMathTime("2.5s", MidpointRounding.AwayFromZero)));

Expect("now+0s").WhenSerializing(
    Nest.DateMath.Now.Add(new DateMathTime(500, MidpointRounding.ToEven)));

Expect("now+1s").WhenSerializing(
    Nest.DateMath.Now.Add(new DateMathTime(500, MidpointRounding.AwayFromZero)));

相等性比较

DateMathTime 实现了 equality 和 comparison:

DateMathTime twoSeconds = new DateMathTime(2, DateMathTimeUnit.Second);
DateMathTime twoSecondsFromString = "2s";
DateMathTime twoSecondsFromTimeSpan = TimeSpan.FromSeconds(2);
DateMathTime twoSecondsFromDouble = 2000;

twoSeconds.Should().Be(twoSecondsFromString);
twoSeconds.Should().Be(twoSecondsFromTimeSpan);
twoSeconds.Should().Be(twoSecondsFromDouble);

DateMathTime threeSecondsFromString = "3s";
DateMathTime oneMinuteFromTimeSpan = TimeSpan.FromMinutes(1);

(threeSecondsFromString > twoSecondsFromString).Should().BeTrue();
(oneMinuteFromTimeSpan > threeSecondsFromString).Should().BeTrue();

年份和月份不包含确切值:

  • 一年大约365天
  • 一个月大约(365/12)天
DateMathTime oneYear = new DateMathTime(1, DateMathTimeUnit.Year);
DateMathTime oneYearFromString = "1y";
DateMathTime twelveMonths = new DateMathTime(12, DateMathTimeUnit.Month);
DateMathTime twelveMonthsFromString = "12M";

oneYear.Should().Be(oneYearFromString);
oneYear.Should().Be(twelveMonths);
twelveMonths.Should().Be(twelveMonthsFromString);

DateMathTime thirteenMonths = new DateMathTime(13, DateMathTimeUnit.Month);
DateMathTime thirteenMonthsFromString = "13M";
DateMathTime fiftyTwoWeeks = "52w";

(oneYear < thirteenMonths).Should().BeTrue();
(oneYear < thirteenMonthsFromString).Should().BeTrue();
(twelveMonths > fiftyTwoWeeks).Should().BeTrue();
(oneYear > fiftyTwoWeeks).Should().BeTrue();

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK