Solr日期类型处理

Solr 如何处理日期类型

日期格式与实际时间晚8小时

solr控制台查询出的日期格式与实际时间少8个小时,因为我们是东八区,推测是时区的原因。

造成这个问题的根源是东八区的人不习惯零时区的时间。其实,solr索引存储的时间并没有少8小时,只是在时间格式化的时候,用的是UTC时间,因为我们是东八区,UTC是零时区时间,所以日期展示的时候,看起来是慢了8小时。

误区一:修改写入时间

为了解决这个问题,在solrJ写入时间时,修改时间,增加8小时。这种方案相当于篡改了数据,是不可取的。

误区二:修改服务器时区

为了解决这个问题,修改服务器的时区(或solr的时区)。集群服务器时间配置应该保持一致,不应该为了解决局部问题而破坏整体,所以不建议修改服务器时区。

Solr日期格式的传输与存储

  • Solr日期类型在索引文件中存储的是long类型

通过Date的getTime获取long值,通过new Date(longValue)转换为时间。

  • Solr文本格式传输:日期为UTC标准格式(如:1972-05-20T17:33:18.772Z)

json、XML格式都属于文本格式。

SolrJ和Solr服务器都是根据本地时区来转换UTC,同时也是根据本地时区来将UTC字符串转换为Date类型。

Solr的Web控制台就是采用的文本传输格式,所以看见的时间是UTC格式字符串(滞后8小时)。

  • Solr二进制传输:日期为long类型

采用二进制传输时,与时区无关。

long值是通过date.getTime直接获取,

long值转换Date时,直接new Date(longValue);

文本传输&二进制传输

  • 文本传输

优点:保证UTC时间一致性,即便时区不一致的服务器依然能保证UTC时间的一致性

缺点:是数据报文比较大,性能不好。

适合场景:人机交互。

  • 二进制传输

优点:数据紧凑,性能好。

缺点:不考虑时区,无法保证UTC时间一致。

场景:服务器间交互。一般企业集群的服务器时钟是统一配置的。

源码分析

  org.apache.solr.util.DateFormatUtil源码:
  文本格式日期处理相关

  public static final TimeZone CANONICAL_TZ = UTC;
  public static final Locale CANONICAL_LOCALE = Locale.ROOT;
  public static final String NOW = "NOW";
  ...
  static class ISO8601CanonicalDateFormat extends SimpleDateFormat {

    protected NumberFormat millisParser
        = NumberFormat.getIntegerInstance(CANONICAL_LOCALE);

    protected NumberFormat millisFormat = new DecimalFormat
        (".###", new DecimalFormatSymbols(CANONICAL_LOCALE));

    public ISO8601CanonicalDateFormat() {
      super("yyyy-MM-dd'T'HH:mm:ss", CANONICAL_LOCALE);
      this.setTimeZone(CANONICAL_TZ);
    }
    ....
  }
  ...   

 org.apache.solr.common.util.JavaBinCodec源码:
 二进制格式日期处理相关

 if (val instanceof Date) {
    daos.writeByte(DATE);
    daos.writeLong(((Date) val).getTime());
    return true;
 }