在弹性搜索和嵌套中传递和比较具有不同时区的日期时间值

时间:2019-02-15 20:39:59

标签: c# datetime elasticsearch timezone nest

我试图在将参数与日期时间值(时区为-05:00的时区识别值)进行比较的查询中传递日期时间值作为参数(时区“ UTC”中的时区识别值) ')放入弹性搜索文档中并返回文档。

问题:
1.我在下面的代码中正确执行了吗?
    2. ES在将它与文档的datetime值进行比较之前,是否要处理datetime参数的不同时区的复杂性?
    3. ES是否要返回具有原始datetime时区值的文档?
    4.是否有任何文档揭示了弹性搜索实例时区处理的内部?

下面的代码返回值,但是我不确定它是否达到期望的目标。
遵循了link,但仅限于一些基本知识
    预先感谢。

ES源文档:

{
  "took" : 12,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },

  "hits" : {
    "total" : 2700881,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "doc",
        "_id" : "R22224!!5333e7e4-9ee3-45f4-9dc3-2a8b8d8cdcf8",
        "_score" : 1.0,
        "_source" : {
          "duration" : 14986283,
          "group_id" : "com",
          "var_time" : "2018-04-24T17:05:13.082-05:00",
          "var_name" : "2",
        }
      }
    ]
  }
}


public class RawDocument
{

    [PropertyName("duration")]
    public long Duration { get; set; }

    [PropertyName("group_id")]
    public string GroupId { get; set; }

    [PropertyName("var_time")]
    public DateTime Vartime { get; set; }

    [PropertyName("var_name")]
    public string Varname { get; set; }

}


static void Main(string[] args)
{

    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool)
        .DefaultMappingFor<RawDocument>(m => m
              .IndexName(test_index)
              .TypeName("doc"));

    var client = new ElasticClient(settings);

    //argument being passed into the query is maxExtractionTime datetime values. maxExtractionTime is in UTC
    //maxExtractionTime is being compared to var_time datetime with timezone values
    DateTime maxExtractionTime;
    maxExtractionTime = DateTime oDate = DateTime.ParseExact("2019-02-08 16:10:40.000", "yyyy-MM-dd HH:mm.fff", System.Globalization.CultureInfo.InvariantCulture);

    var searchResponse = client.Search<RawDocument>(s => s
                .Size(5000)
                .Scroll("2m")
                .Query(q => q.DateRange(m => m.Field("var_time").GreaterThanOrEquals(maxExtractionTime.ToString("yyyy-MM-dd HH:mm:ss.fff")).TimeZone("+00:00")))                
                );


    while (searchResponse.Documents.Any())
        {

            foreach (var document in searchResponse.Hits)
            {
            //do some business logic on the values
            MessageBox.Show("document.Source.Duration", document.Source.Duration);
            MessageBox.Show("document.Source.Vartime", document.Source.Vartime);

            }
            searchResponse = client.Scroll<RawDocument>("2m", searchResponse.ScrollId);
        }   

    var clearScrollResponse = client.ClearScroll(c => c.ScrollId(searchResponse.ScrollId));         
}

2 个答案:

答案 0 :(得分:2)

您从文档中获得了指向以下内容的链接:

  

现在不受time_zone参数的影响(日期必须存储为UTC)

由此,以及该页面上的其他示例,您可以看到time_zone参数(或C#中的.TimeZone(...))会影响查询的输入值。通过传递+00:00,您的意思是输入值不需要调整。

日期本身必须作为UTC存储在文档中,才能正确执行范围查询。您不应该将var_time存储为2018-04-24T17:05:13.082-05:00,而应该存储为2018-04-24T17:10:13.082Z。然后您可以查询它。

如有必要,请存储两个字段,因此您需要查询一个字段,并显示一个原始本地时间。

要回答您的特定问题:

  
      
  1. 我在下面的代码中正确执行了吗?
  2.   

您的查询很好,但是.TimeZone("+00:00")不是必需的,因为它不会调整参数。但是,您确实需要确保文档中的时间戳记存储在UTC中。

  
      
  1. ES在将其与文档的datetime值进行比较之前,是否要处理datetime参数不同时区的复杂性?
  2.   

调整参数只是一种方便。它不会调整文档中的值。

  
      
  1. ES是否要返回具有原始datetime时区值的文档?
  2.   

文档应正常返回。更改查询中的时区不会对此造成影响。

  
      
  1. 是否有任何文档揭示了弹性搜索实例时区处理的内部?
  2.   

除了您链接到的文档外,我找不到其他内容。您应该尝试验证所有假设。

答案 1 :(得分:1)

要添加到Matt Johnson's answer中,当您输入的日期字符串输入有一个时区偏移量(或格式未指定一个例如2019-02-21)但希望希望Elasticsearch转换时,发送时区会很有帮助在与目标字段中存储的日期进行比较之前,将其设置为另一个时区偏移量。

让我们看一些示例。

DateTimeKind.Utc

var client = new ElasticClient();

var maxExtractionTime = new DateTime(2019, 2, 8, 16, 10, 40, DateTimeKind.Utc);

var searchResponse = client.Search<RawDocument>(s => s
    .Query(q => q
        .DateRange(m => m
            .Field(f => f.Vartime)
            .GreaterThanOrEquals(maxExtractionTime)
        )
    )
);

序列化为

{
  "query": {
    "range": {
      "var_time": {
        "gte": "2019-02-08T16:10:40Z"
      }
    }
  }
}

DateTimeKind.Local(我在澳大利亚)

var maxExtractionTime = new DateTime(2019, 2, 8, 16, 10, 40, DateTimeKind.Local);

序列化为

{
  "query": {
    "range": {
      "var_time": {
        "gte": "2019-02-08T16:10:40+10:00"
      }
    }
  }
}

DateTimeKind.Unspecified

var maxExtractionTime = new DateTime(2019, 2, 8, 16, 10, 40, DateTimeKind.Unspecified);

序列化为

{
  "query": {
    "range": {
      "var_time": {
        "gte": "2019-02-08T16:10:40"
      }
    }
  }
}   

在前两种情况下,每个都包含一个时区偏移值,Elasticsearch在比较日期时可以使用该值。最后,不存在时区偏移,因此将其解释为UTC。在后一种情况下,您可能希望发送一个时区值以用于将输入转换为UTC。

有一些history to DateTime and DateTimeOffset serialization within the client。 6.x中的序列化无法更改,除了您自己的POCO上带有custom serializer hooked upDateTimeDateTimeOffset属性类型外。但是,限制并不经常成为问题,但是由于客户端中的大多数API都接受DateMath type,因此可以使用支持日期数学表达式的格式化日期字符串。使用DateMath,可以从DateTimestring进行隐式转换,还可以构建更复杂的表达式。