如何让SolrJ序列化的LocalDate/LocalDateTime可作为日期检索?
当然可以解决这个问题!你不用一直转成java.util.Date,有两种靠谱的方式让SolrJ正确处理Java 8的LocalDate和LocalDateTime,并让它们能被当作日期字段检索:
方案一:自定义SolrJ字段序列化器
SolrJ允许你为特定类型自定义FieldSerializer,这样就能完全控制Java对象如何转换成Solr的字段值,不用修改实体类结构。
步骤1:编写自定义序列化器
分别为LocalDate和LocalDateTime实现序列化逻辑:
import org.apache.solr.client.solrj.beans.FieldSerializer; import org.apache.solr.common.SolrInputField; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; // 处理LocalDate的序列化器 public class LocalDateFieldSerializer implements FieldSerializer { private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE; @Override public void write(Object obj, String fieldName, SolrInputField field) { if (obj instanceof LocalDate) { LocalDate date = (LocalDate) obj; field.setValue(date.format(DATE_FORMAT)); } } } // 处理LocalDateTime的序列化器 public class LocalDateTimeFieldSerializer implements FieldSerializer { private static final DateTimeFormatter DATETIME_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE_TIME; @Override public void write(Object obj, String fieldName, SolrInputField field) { if (obj instanceof LocalDateTime) { LocalDateTime dateTime = (LocalDateTime) obj; field.setValue(dateTime.format(DATETIME_FORMAT)); } } }
步骤2:注册序列化器到SolrClient
在创建CloudSolrClient后,把自定义序列化器绑定到对应类型上:
String zkHosts = "localhost:2181"; CloudSolrClient client = new CloudSolrClient.Builder().withZkHost(zkHosts).build(); client.setDefaultCollection("playground"); // 注册自定义序列化器,让SolrJ知道怎么处理Java8日期类型 client.getBinder().registerFieldSerializer(LocalDate.class, new LocalDateFieldSerializer()); client.getBinder().registerFieldSerializer(LocalDateTime.class, new LocalDateTimeFieldSerializer()); Person test = Person.builder() .id("UID-333") .createdTimestamp(LocalDateTime.now()) .dateOfBirth(LocalDate.now()) .gender("male") .build(); client.addBean("person", test, 1000); client.commit(); // 别忘了提交变更! client.close();
方案二:通过Solr Schema配置+实体类转换
如果不想写自定义序列化器,也可以直接在Solr的Schema里定义日期类型字段,然后在实体类里做简单的格式转换。
步骤1:修改Solr Schema
确保你的Solr集合的Schema里有对应的日期类型字段,比如:
<field name="dateOfBirth" type="date" indexed="true" stored="true"/> <field name="createdTimestamp" type="date" indexed="true" stored="true"/>
(如果用的是Schema API,也可以通过API动态添加这些字段)
步骤2:调整实体类的字段映射
在Person类里,把Java8日期类型转成Solr支持的ISO格式字符串,再映射到对应的日期字段:
import org.apache.solr.client.solrj.beans.Field; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; public class Person { @Field private String id; @Field("createdTimestamp") private String serializedTimestamp; // 映射到Solr的日期字段 @Field("dateOfBirth") private String serializedDob; // 映射到Solr的日期字段 @Field private String gender; // 原有的Java8日期字段,不直接映射到Solr private LocalDateTime createdTimestamp; private LocalDate dateOfBirth; // Builder里处理格式转换 public static class Builder { private Person person = new Person(); public Builder id(String id) { person.id = id; return this; } public Builder createdTimestamp(LocalDateTime timestamp) { person.createdTimestamp = timestamp; // 转成Solr能识别的ISO日期字符串 person.serializedTimestamp = timestamp.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); return this; } public Builder dateOfBirth(LocalDate date) { person.dateOfBirth = date; person.serializedDob = date.format(DateTimeFormatter.ISO_LOCAL_DATE); return this; } public Builder gender(String gender) { person.gender = gender; return this; } public Person build() { return person; } } public static Builder builder() { return new Builder(); } // 按需添加getter/setter方法 }
这样处理后,Solr里存储的内容会变成标准的日期字符串,比如:
{ "id":"UID-333", "dateOfBirth":["2018-05-15"], "createdTimestamp":["2018-05-15T15:00:12.433"], "gender":["male"] }
此时你就可以用日期范围查询,比如dateOfBirth:[2018-01-01 TO 2018-12-31]来检索数据了。
注意事项
- 不管用哪种方案,都要确保Solr字段的类型是
date(或pdate等Solr支持的日期类型),否则即使存储了正确的字符串,也无法按日期规则检索。 - 第一种方案更优雅,不需要修改实体类结构,适合大规模使用Java8日期类型的场景。
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

