对于从外部数据源导入到es的日期数据,往往呈现出下列的状态
2015-01-01T12:10:30Z
elasticsearch 数据是以 JSON 格式存储的,而 JSON中是并没有 date 数据类型,因此 Elasticsearch 中虽然有 date 类型,但在展示时却要转化成另外的格式。date 类型在 Elasticsearch 展示的格式有下面几种:
1)将日期时间格式化后的字符串,如 "2015-01-01" 或者 "2015/01/01 12:10:30"
2)long 型的整数,意义是 milliseconds-since-the-epoch,翻译一下就是自 1970-01-01 00:00:00 UTC 以来经过的毫秒数。
3)int 型的整数,意义是 seconds-since-the-epoch, 是指自 1970-01-01 00:00:00 UTC 以来经过的秒数。
【注】UTC(Universal Time Coordinated) 叫做世界统一时间,中国大陆和 UTC 的时差是 + 8 ,也就是 UTC+8。不论 date 是什么展示格式,在 Elasticsearch 内部存储时都是转换成 UTC,并且把时区也会计算进去,从而得到 milliseconds-since-the-epoch 并作为存储的格式。
在ES中,Date类型的默认格式如下:
"strict_date_optional_time||epoch_millis"
这里的"strict_date_optional_time" 的解释如下:
表示只要是 ISO datetime parser 可以正常解析的都是 strict_date_optional_time。
解释:
dateOptionalTimeParser
public static DateTimeFormatter dateOptionalTimeParser()
Returns a generic ISO datetime parser where the date is mandatory and the time is optional.
The returned formatter can only be used for parsing, printing is unsupported.
This parser can parse zoned datetimes. The parser is strict by default, thus time string 24:00 cannot be parsed.
It accepts formats described by the following syntax:
date-opt-time = date-element ['T' [time-element] [offset]] date-element = std-date-element | ord-date-element | week-date-element std-date-element = yyyy ['-' MM ['-' dd]] ord-date-element = yyyy ['-' DDD] week-date-element = xxxx '-W' ww ['-' e] time-element = HH [minute-element] | [fraction] minute-element = ':' mm [second-element] | [fraction] second-element = ':' ss [fraction] fraction = ('.' | ',') digit+
offset = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]]) 这里解释一下,日期部分必须指定,其格式可以是:
而时间部分,如果按照这种格式,必须以字母T来开始:['T' [time-element] [offset]]
而这个时候,如果给ES的Date字段出入如下的值:
"2019-01-01 12:00:01"
的时候,就会报错,这个原因就是,按照确认格式,以上字符串是不能被识别为日期类型
而如下的写法,应该都是合法的写法:
PUT my_index { "mappings": { "properties": { "date": { "type": "date" } } } } PUT my_index/_doc/1 { "date": "2015-01-01" } PUT my_index/_doc/2 { "date": "2015-01-01T12:10:30Z" } PUT my_index/_doc/3 { "date": 1420070400001 } GET my_index/_search { "sort": { "date": "asc"} }
那么如何让一个日期型字段支持多种格式呢,答案是:给这个字段指定所有可能的格式(format)
譬如,如下定义:
...
"update_date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||strict_date_optional_time||epoch_millis"
},
....
这样定义后,这个update_date字段就可以接受"2019-01-01 12:00:01"这样的字符串作为输入或者查询条件了。
而如果对于通过logstash导入ES的日期格式数据,如果输入的日期字符串和上述定义的格式不相匹配是,也可以通过ruby插件尽心编辑,并修改成ES可以接受的格式。示例如下:
congfig文件如下:
input {
stdin { }
jdbc {
type => "country_info"
jdbc_connection_string => "jdbc:mysql://127.0.0.1:3306/world"
jdbc_user => "root"
jdbc_password => "root1234"
jdbc_driver_library => "D:/logstash-7.0.1/lib/mysql/mysql-connector-java-5.1.39-bin.jar"
jdbc_driver_class => "com.mysql.jdbc.Driver"
jdbc_default_timezone => "UTC"
jdbc_paging_enabled => "true"
jdbc_page_size => "50000"
statement => "SELECT CODE AS country_code,
NAME,
continent,
region,
SurfaceArea AS surface_area,
indepYear,
population,
LifeExpectancy AS life_expetancy,
gnp,
gnpold,
localname,
governmentform,
headofstate,capital,code2
FROM country"
}
}
filter {
ruby{
path => "D:\logstash-7.0.1\config\handle_country_info.rb"
}
}
output {
stdout { }
elasticsearch {
action => "index"
hosts => "127.0.0.1:9200"
index => "country_info"
document_id => "%{country_code}"
}
}
ruby文件如下:
# the filter method receives an event and must return a list of events.
# Dropping an event means not including it in the return array,
# while creating new ones only requires you to add a new instance of
# LogStash::Event to the returned array
def filter(event)
timestamp = event.get("@timestamp")
update_date = timestamp.time.localtime + 8*60*60
event.set('update_date',update_date.strftime('%Y-%m-%d %H:%M:%S'))
event.remove('@timestamp')
event.remove('@version')
return [event]
end
如上所示,通过ruby程序,可以对日期型字段的值以及格式做灵活调整,这里就是设置成年月日时分秒的格式,加工成了ES可以接受的形式之一。
对于ruby可以做哪些时间类型的运算和处理,请参照ruby的语言说明。