此版本仍在开发中,尚未视为稳定版。如需最新稳定版本,请使用 Spring Data Elasticsearch 6.0.4spring-doc.cadn.net.cn

Elasticsearch 对象映射

Spring Data Elasticsearch 对象映射是将 Java 对象(即领域实体)映射为存储在 Elasticsearch 中的 JSON 表示形式,以及反向映射的过程。 内部用于此映射的类是 MappingElasticsearchConverterspring-doc.cadn.net.cn

元模型对象映射

基于元模型的方法使用领域类型信息从 Elasticsearch 读取/写入数据。 这允许为特定的领域类型映射注册 Converter 个实例。spring-doc.cadn.net.cn

映射注解概述

MappingElasticsearchConverter 使用元数据来驱动对象到文档的映射。 元数据取自实体的属性,这些属性可以被注解。spring-doc.cadn.net.cn

以下注解可用:spring-doc.cadn.net.cn

  • @Document: 应用于类级别,表示该类是映射到数据库的候选类。 最重要的属性包括(完整属性列表请查阅 API 文档):spring-doc.cadn.net.cn

  • @Id:应用于字段级别,用于标记用作标识目的的字段。spring-doc.cadn.net.cn

  • @Transient, @ReadOnlyProperty, @WriteOnlyProperty:请参阅以下章节 控制哪些属性被写入和读取自 Elasticsearch 以获取详细信息。spring-doc.cadn.net.cn

  • @PersistenceConstructor:标记一个给定的构造函数(即使是包级私有的构造函数),用于从数据库实例化对象时使用。 构造函数的参数将根据名称映射到所检索文档中的键值。spring-doc.cadn.net.cn

  • @Field:应用于字段级别,用于定义字段的属性,其中大多数属性映射到相应的 Elasticsearch 映射 定义(以下列表并不完整,请参阅注解的 Javadoc 以获取完整参考):spring-doc.cadn.net.cn

    • name: 该字段在 Elasticsearch 文档中的表示名称;如果未设置,则使用 Java 字段名。spring-doc.cadn.net.cn

    • type:字段类型,可以是以下之一:Text、Keyword、Long、Integer、Short、Byte、Double、Float、Half_Float、Scaled_Float、Date、Date_Nanos、Boolean、Binary、Integer_Range、Float_Range、Long_Range、Double_Range、Date_Range、Ip_Range、Object、Nested、Ip、TokenCount、Percolator、Flattened、Search_As_You_Type。 请参阅 Elasticsearch 映射类型。 如果未指定字段类型,则默认为 FieldType.Auto。 这意味着不会为该属性写入任何映射条目,而 Elasticsearch 会在首次存储该属性的数据时动态添加映射条目(请查阅 Elasticsearch 文档以了解动态映射规则)。spring-doc.cadn.net.cn

    • format:一个或多个内置日期格式,请参阅下一节 日期格式映射spring-doc.cadn.net.cn

    • pattern:一个或多个自定义日期格式,请参阅下一节 日期格式映射spring-doc.cadn.net.cn

    • store:标志是否应将原始字段值存储在 Elasticsearch 中,默认值为 falsespring-doc.cadn.net.cn

    • analyzersearchAnalyzernormalizer 用于指定自定义分析器和标准化器。spring-doc.cadn.net.cn

  • @GeoPoint:将字段标记为 geo_point 数据类型。 如果该字段是 GeoPoint 类的实例,则可以省略此标记。spring-doc.cadn.net.cn

  • @ValueConverter 定义一个类,用于转换指定的属性。 与已注册的 Spring Converter 不同,它仅转换被注解的属性,而非给定类型的每个属性。spring-doc.cadn.net.cn

映射元数据基础设施定义在一个独立且与技术无关的 spring-data-commons 项目中。spring-doc.cadn.net.cn

控制哪些属性被写入和读取自 Elasticsearch

本节详细介绍了用于定义属性值是写入还是读取 Elasticsearch 的注解。spring-doc.cadn.net.cn

@Transient:使用此注解标注的属性不会被写入映射,其值也不会发送到 Elasticsearch;当从 Elasticsearch 返回文档时,该属性也不会在生成的实体中设置。spring-doc.cadn.net.cn

@ReadOnlyProperty:带有此注解的属性不会将其值写入 Elasticsearch,但在返回数据时,该属性将被填充为从 Elasticsearch 文档中返回的值。 此功能的一个用例是索引映射中定义的运行时字段。spring-doc.cadn.net.cn

@WriteOnlyProperty: 带有此注解的属性,其值将被存储到 Elasticsearch 中,但在读取文档时不会被赋予任何值。 例如,这可用于合成字段,这些字段需要写入 Elasticsearch 索引,但不会在其他地方使用。spring-doc.cadn.net.cn

日期格式映射

派生自 TemporalAccessor 或类型为 java.util.Date 的属性,必须具有类型为 FieldType.Date@Field 注解,或者必须为该类型注册自定义转换器。 本段描述了 FieldType.Date 的用法。spring-doc.cadn.net.cn

@Field 注解有两个属性,用于定义写入映射的日期格式信息(另请参阅 Elasticsearch 内置格式Elasticsearch 自定义日期格式spring-doc.cadn.net.cn

format 属性用于定义至少一种预定义格式。 如果未定义,则使用默认值 _date_optional_timeepoch_millisspring-doc.cadn.net.cn

pattern 属性可用于添加额外的自定义格式字符串。 如果只想使用自定义日期格式,必须将 format 属性设置为空 {}spring-doc.cadn.net.cn

下表展示了不同的属性及其值所创建的映射:spring-doc.cadn.net.cn

注解 在 Elasticsearch 映射中格式化字符串

@Field(type=FieldType.Date)spring-doc.cadn.net.cn

"date_optional_time||epoch_millis",spring-doc.cadn.net.cn

@Field(type=FieldType.日期,format=DateFormat.基本日期)spring-doc.cadn.net.cn

"basic_date"spring-doc.cadn.net.cn

@Field(type=FieldType.日期,format={DateFormat.基本日期,DateFormat.基本时间})spring-doc.cadn.net.cn

"basic_date||basic_time"spring-doc.cadn.net.cn

@Field(type=FieldType.日期,pattern="dd.MM.uuuu")spring-doc.cadn.net.cn

"date_optional_time||epoch_millis||dd.MM.uuuu",spring-doc.cadn.net.cn

@Field(type=FieldType.日期,format={}, pattern="dd.MM.uuuu")spring-doc.cadn.net.cn

"dd.MM.uuuu"spring-doc.cadn.net.cn

如果您使用的是自定义日期格式,则需要使用 uuuu 来表示年份,而不是 yyyy。 这是由于 Elasticsearch 7 中的变更 所致。

查看 org.springframework.data.elasticsearch.annotations.DateFormat 枚举的代码,以获取预定义值及其模式的完整列表。spring-doc.cadn.net.cn

范围类型

当一个字段被注解为 Integer_Range、Float_Range、Long_Range、Double_Range、Date_RangeIp_Range 类型之一时,该字段必须是可映射到 Elasticsearch 范围类型的类的实例,例如:spring-doc.cadn.net.cn

class SomePersonData {

    @Field(type = FieldType.Integer_Range)
    private ValidAge validAge;

    // getter and setter
}

class ValidAge {
    @Field(name="gte")
    private Integer from;

    @Field(name="lte")
    private Integer to;

    // getter and setter
}

作为替代方案,Spring Data Elasticsearch 提供了一个 Range<T> 类,因此前面的示例可以编写为:spring-doc.cadn.net.cn

class SomePersonData {

    @Field(type = FieldType.Integer_Range)
    private Range<Integer> validAge;

    // getter and setter
}

支持类型 <T> 的类包括 IntegerLongFloatDoubleDate,以及实现了 TemporalAccessor 接口的类。spring-doc.cadn.net.cn

映射的字段名称

在不进行额外配置的情况下,Spring Data Elasticsearch 会将对象的属性名用作 Elasticsearch 中的字段名。 可以通过在该属性上使用 @Field 注解来为单个字段更改此行为。spring-doc.cadn.net.cn

也可以在客户端的配置中定义一个 FieldNamingStrategyElasticsearch 客户端)。 例如,如果配置了 SnakeCaseFieldNamingStrategy,则对象的 sampleProperty 属性将在 Elasticsearch 中映射为 sample_propertyFieldNamingStrategy 适用于所有实体;可以通过在属性上使用 @Field 设置特定名称来覆盖它。spring-doc.cadn.net.cn

非字段支持的属性

通常,实体中使用的属性是实体类的字段。 但在某些情况下,属性值是在实体中计算得出的,并且需要存储到 Elasticsearch 中。 在这种情况下,除了使用 @AccessType(AccessType.Type .PROPERTY) 注解该方法外,还可以使用 @Field 注解其 getter 方法(getProperty())。 此种情形下所需的第三个注解是 @WriteOnlyProperty,因为此类值仅写入 Elasticsearch。 完整示例:spring-doc.cadn.net.cn

@Field(type = Keyword)
@WriteOnlyProperty
@AccessType(AccessType.Type.PROPERTY)
public String getProperty() {
	return "some value that is calculated here";
}

其他属性注解

@索引名称

此注解可设置在实体的 String 属性上。 该属性不会被写入映射,不会存储到 Elasticsearch 中,其值也不会从 Elasticsearch 文档中读取。 在实体持久化之后(例如通过调用 ElasticsearchOperations.save(T entity)),该调用返回的实体将在该属性中包含实体所保存到的索引名称。 当索引名称由 Bean 动态设置,或写入写别名时,此功能非常有用。spring-doc.cadn.net.cn

将某个值设置到此类属性中,并不会设定实体存储的索引位置!spring-doc.cadn.net.cn

映射规则

类型提示

映射利用嵌入在发送到服务器的文档中的类型提示,以支持泛型类型映射。 这些类型提示在文档中表示为_class属性,并为每个聚合根编写。spring-doc.cadn.net.cn

示例 1. 类型提示
public class Person {              (1)
  @Id String id;
  String firstname;
  String lastname;
}
{
  "_class" : "com.example.Person", (1)
  "id" : "cb7bef",
  "firstname" : "Sarah",
  "lastname" : "Connor"
}
1 默认情况下,领域类型的类名将用作类型提示。

类型提示可以配置为保存自定义信息。 使用 @TypeAlias 注解来实现这一点。spring-doc.cadn.net.cn

确保在初始实体集 (AbstractElasticsearchConfiguration#getInitialEntitySet) 中添加类型为 @TypeAlias 的实体,以便在首次从存储中读取数据时已具备实体信息。
示例 2. 使用别名的类型提示
@TypeAlias("human")                (1)
public class Person {

  @Id String id;
  // ...
}
{
  "_class" : "human",              (1)
  "id" : ...
}
1 配置别名在写入实体时使用。
除非属性的类型为 Object、接口,或者实际值类型与属性声明不匹配,否则不会为嵌套对象写入类型提示。
禁用类型提示

当应使用的索引已存在,但其映射中未定义类型提示,且映射模式设置为严格时,可能需要禁用类型提示的写入。 在这种情况下,写入类型提示将产生错误,因为无法自动添加该字段。spring-doc.cadn.net.cn

可以通过在派生自 AbstractElasticsearchConfiguration 的配置类中重写方法 writeTypeHints() 来为整个应用程序禁用类型提示(请参阅 Elasticsearch 客户端)。spring-doc.cadn.net.cn

作为替代方案,可以使用 @Document 注解为单个索引禁用它们:spring-doc.cadn.net.cn

@Document(indexName = "index", writeTypeHint = WriteTypeHint.FALSE)
我们强烈建议不要禁用类型提示。 仅在被迫的情况下才执行此操作。 禁用类型提示可能导致在存在多态数据时无法从 Elasticsearch 正确检索文档,或导致文档检索完全失败。

地理空间类型

PointGeoPoint 这样的地理空间类型会被转换为 纬度/经度 对。spring-doc.cadn.net.cn

示例 3. 地理空间类型
public class Address {
  String city, street;
  Point location;
}
{
  "city" : "Los Angeles",
  "street" : "2800 East Observatory Road",
  "location" : { "lat" : 34.118347, "lon" : -118.3026284 }
}

GeoJson 类型

Spring Data Elasticsearch 通过提供接口 GeoJson 以及针对不同几何类型的实现,支持 GeoJson 类型。 它们会根据 GeoJson 规范映射到 Elasticsearch 文档。 当写入索引映射时,实体的相应属性在索引映射中被指定为 geo_shape。(也可查阅 Elasticsearch 文档spring-doc.cadn.net.cn

示例 4. GeoJson 类型
public class Address {

  String city, street;
  GeoJsonPoint location;
}
{
  "city": "Los Angeles",
  "street": "2800 East Observatory Road",
  "location": {
    "type": "Point",
    "coordinates": [-118.3026284, 34.118347]
  }
}

已实现以下 GeoJson 类型:spring-doc.cadn.net.cn

集合

对于集合内部的值,在涉及类型提示自定义转换时,应用与聚合根相同的映射规则。spring-doc.cadn.net.cn

示例 5. 集合
public class Person {

  // ...

  List<Person> friends;

}
{
  // ...

  "friends" : [ { "firstname" : "Kyle", "lastname" : "Reese" } ]
}

映射

对于 Map 内部的值,在涉及类型提示自定义转换时,应用与聚合根相同的映射规则。 然而,Map 的键必须是 String 类型才能被 Elasticsearch 处理。spring-doc.cadn.net.cn

示例 6. 集合
public class Person {

  // ...

  Map<String, Address> knownLocations;

}
{
  // ...

  "knownLocations" : {
    "arrivedAt" : {
       "city" : "Los Angeles",
       "street" : "2800 East Observatory Road",
       "location" : { "lat" : 34.118347, "lon" : -118.3026284 }
     }
  }
}

自定义转换

查看前一节中的ConfigurationElasticsearchCustomConversions允许注册特定规则以映射领域类型和简单类型。spring-doc.cadn.net.cn

示例 7.元模型对象映射配置
@Configuration
public class Config extends ElasticsearchConfiguration  {

	@Override
	public ClientConfiguration clientConfiguration() {
		return ClientConfiguration.builder() //
				.connectedTo("localhost:9200") //
				.build();
	}

  @Bean
  @Override
  public ElasticsearchCustomConversions elasticsearchCustomConversions() {
    return new ElasticsearchCustomConversions(
      Arrays.asList(new AddressToMap(), new MapToAddress()));       (1)
  }

  @WritingConverter                                                 (2)
  static class AddressToMap implements Converter<Address, Map<String, Object>> {

    @Override
    public Map<String, Object> convert(Address source) {

      LinkedHashMap<String, Object> target = new LinkedHashMap<>();
      target.put("ciudad", source.getCity());
      // ...

      return target;
    }
  }

  @ReadingConverter                                                 (3)
  static class MapToAddress implements Converter<Map<String, Object>, Address> {

    @Override
    public Address convert(Map<String, Object> source) {

      // ...
      return address;
    }
  }
}
{
  "ciudad" : "Los Angeles",
  "calle" : "2800 East Observatory Road",
  "localidad" : { "lat" : 34.118347, "lon" : -118.3026284 }
}
1 添加 Converter 个实现。
2 设置用于将 DomainType 写入 Elasticsearch 的 Converter
3 设置用于从搜索结果中读取DomainTypeConverter