Spring Data Elasticsearch 对象映射是将 Java 对象(域实体)映射到存储在 Elasticsearch 中并返回的 JSON 表示的过程。 内部用于此映射的类是 .MappingElasticsearchConverterSpring中文文档

元模型对象映射

基于元模型的方法使用域类型信息从 Elasticsearch 读取/写入 Elasticsearch。 这允许为特定域类型映射注册实例。ConverterSpring中文文档

映射注释概述

使用元数据来驱动对象到文档的映射。 元数据取自实体的属性,这些属性可以进行注释。MappingElasticsearchConverterSpring中文文档

可以使用以下注释:Spring中文文档

  • @Document:在类级别应用,以指示此类是映射到数据库的候选项。 最重要的属性是(查看 API 文档以获取完整的属性列表):Spring中文文档

  • @Id:应用于字段级别,以标记用于标识目的的字段。Spring中文文档

  • @Transient, , : 有关详细信息,请参阅以下部分控制向 Elasticsearch 写入和读取哪些属性@ReadOnlyProperty@WriteOnlyPropertySpring中文文档

  • @PersistenceConstructor:标记给定的构造函数 - 甚至是受包保护的构造函数 - 在从数据库实例化对象时使用。 构造函数参数按名称映射到检索到的 Document 中的键值。Spring中文文档

  • @Field:应用于字段级别并定义字段的属性,大多数属性映射到相应的 Elasticsearch 映射定义(以下列表不完整,请查看 Javadoc 注释以获取完整参考):Spring中文文档

    • name:将在 Elasticsearch 文档中表示的字段名称,如果未设置,则使用 Java 字段名称。Spring中文文档

    • 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 映射类型。 如果未指定字段类型,则默认为 。 这意味着,不会为该属性编写映射条目,并且 Elasticsearch 将在存储此属性的第一个数据时动态添加映射条目(查看 Elasticsearch 文档,了解动态映射规则)。FieldType.AutoSpring中文文档

    • format:一种或多种内置日期格式,请参阅下一节日期格式映射Spring中文文档

    • pattern:一种或多种自定义日期格式,请参阅下一节日期格式映射Spring中文文档

    • store:标记原始字段值是否应存储在 Elasticsearch 中,默认值为 falseSpring中文文档

    • analyzer、 、 用于指定自定义分析器和归一化器。searchAnalyzernormalizerSpring中文文档

  • @GeoPoint:将字段标记为geo_point数据类型。 如果字段是类的实例,则可以省略。GeoPointSpring中文文档

  • @ValueConverter定义用于转换给定属性的类。 与已注册的 Spring 不同,它只转换带注释的属性,而不是给定类型的每个属性。ConverterSpring中文文档

映射元数据基础结构在一个单独的 spring-data-commons 项目中定义,该项目与技术无关。Spring中文文档

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

本节详细介绍了定义属性值是写入 Elasticsearch 还是从 Elasticsearch 读取属性值的注释。Spring中文文档

@Transient:使用此注释注释的属性不会写入映射,其值不会发送到 Elasticsearch,并且当从 Elasticsearch 返回文档时,不会在生成的实体中设置此属性。Spring中文文档

@ReadOnlyProperty:具有此注释的属性不会将其值写入 Elasticsearch,但在返回数据时,该属性将填充 Elasticsearch 在文档中返回的值。 其中一个用例是在索引映射中定义的运行时字段。Spring中文文档

@WriteOnlyProperty:具有此注释的属性的值将存储在 Elasticsearch 中,但在读取文档时不会设置任何值。 例如,这可以用于合成字段,这些字段应该进入 Elasticsearch 索引,但不在其他地方使用。Spring中文文档

日期格式映射

派生自或属于类型的属性必须具有类型的批注,或者必须为此类型注册自定义转换器。 本段介绍 的用法。TemporalAccessorjava.util.Date@FieldFieldType.DateFieldType.DateSpring中文文档

注释有两个属性用于定义将哪些日期格式信息写入映射(另请参阅 Elasticsearch 内置格式Elasticsearch 自定义日期格式@Field)Spring中文文档

该属性用于定义至少一种预定义格式。 如果未定义,则使用默认值 _date_optional_timeepoch_millisformatSpring中文文档

该属性可用于添加其他自定义格式字符串。 如果只想使用自定义日期格式,则必须将该属性设置为空。patternformat{}Spring中文文档

下表显示了不同的属性以及根据其值创建的映射:Spring中文文档

注解 Elasticsearch 映射中的格式字符串

@Field(type=FieldType.Date)Spring中文文档

“date_optional_time||epoch_millis“,Spring中文文档

@Field(type=FieldType.Date, format=DateFormat.basic_date)Spring中文文档

“basic_date”Spring中文文档

@Field(type=FieldType.Date, format={DateFormat.basic_date, DateFormat.basic_time})Spring中文文档

“basic_date||basic_time”Spring中文文档

@Field(type=FieldType.Date, pattern=“dd.MM.uuuu”)Spring中文文档

“date_optional_time||epoch_millis||dd.MM.uuuu“,Spring中文文档

@Field(type=FieldType.Date, format={}, pattern=“dd.MM.uuuu”)Spring中文文档

“dd.MM.uuuu”Spring中文文档

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

检查枚举的代码,获取预定义值及其模式的完整列表。org.springframework.data.elasticsearch.annotations.DateFormatSpring中文文档

范围类型

当字段使用 Integer_Range、Float_Range、Long_Range、Double_Range、Date_RangeIp_Range类型之一进行注释时,该字段必须是将映射到 Elasticsearch 范围的类的实例,例如:Spring中文文档

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中文文档

class SomePersonData {

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

    // getter and setter
}

该类型支持的类是 、 、 、 和实现接口的类。<T>IntegerLongFloatDoubleDateTemporalAccessorSpring中文文档

映射的字段名称

无需进一步配置,Spring Data Elasticsearch 将在 Elasticsearch 中使用对象的属性名称作为字段名称。 这可以通过使用该属性上的注释来更改单个字段。@FieldSpring中文文档

也可以在客户端(Elasticsearch 客户端)的配置中定义一个。 例如,如果配置了 a,则对象的属性 sampleProperty 将映射到 Elasticsearch 中的 sample_property。 A 适用于所有实体;可以通过在属性上设置特定名称来覆盖它。FieldNamingStrategySnakeCaseFieldNamingStrategyFieldNamingStrategy@FieldSpring中文文档

非字段支持的属性

通常,实体中使用的属性是实体类的字段。 在某些情况下,属性值是在实体中计算的,并且应存储在 Elasticsearch 中。 在这种情况下,getter 方法 () 可以用注释进行注释,此外,该方法必须用 . 在这种情况下,需要的第三个注解是 ,因为这样的值只写入 Elasticsearch。 一个完整的例子:getProperty()@Field@AccessType(AccessType.Type .PROPERTY)@WriteOnlyPropertySpring中文文档

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

其他属性注释

@IndexedIndexName

可以在实体的 String 属性上设置此批注。 此属性不会写入映射,不会存储在 Elasticsearch 中,也不会从 Elasticsearch 文档中读取其值。 保留实体后(例如,通过对 的调用),从该调用返回的实体将包含实体在该属性中保存到的索引的名称。 当索引名称由 Bean 动态设置时,或者写入写入别名时,这很有用。ElasticsearchOperations.save(T entity)Spring中文文档

在这样的属性中输入一些值不会设置存储实体的索引!Spring中文文档

映射规则

类型提示

映射使用发送到服务器的文档中嵌入的类型提示来允许泛型类型映射。 这些类型提示表示为文档中的属性,并针对每个聚合根编写。_classSpring中文文档

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

可以将类型提示配置为保存自定义信息。 使用批注来执行此操作。@TypeAliasSpring中文文档

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

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

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

可以通过覆盖派生自的配置类中的方法,为整个应用程序禁用类型提示(请参阅 Elasticsearch 客户端)。writeTypeHints()AbstractElasticsearchConfigurationSpring中文文档

作为替代方法,可以对带有注释的单个索引禁用它们:@DocumentSpring中文文档

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

地理空间类型

像 & 这样的地理空间类型被转换为纬度/经度对。PointGeoPointSpring中文文档

例 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 规范映射到 Elasticsearch 文档。 实体的相应属性在索引映射中指定,就像写入索引映射时一样。(另请查看 Elasticsearch 文档GeoJsongeo_shapeSpring中文文档

例 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中文文档

收集

对于集合中的值,在类型提示自定义转换方面应用与聚合根相同的映射规则。Spring中文文档

例 5.收集
public class Person {

  // ...

  List<Person> friends;

}
{
  // ...

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

地图

对于 Maps 中的值,在类型提示自定义转换方面应用与聚合根相同的映射规则。 但是,Map 键需要 String 才能由 Elasticsearch 处理。Spring中文文档

例 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 }
     }
  }
}

自定义转换

查看上一节的内容,可以注册用于映射域和简单类型的特定规则。ConfigurationElasticsearchCustomConversionsSpring中文文档

例 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 设置用于写入 Elasticsearch。ConverterDomainType
3 设置用于从搜索结果中读取。ConverterDomainType
注解 Elasticsearch 映射中的格式字符串

@Field(type=FieldType.Date)Spring中文文档

“date_optional_time||epoch_millis“,Spring中文文档

@Field(type=FieldType.Date, format=DateFormat.basic_date)Spring中文文档

“basic_date”Spring中文文档

@Field(type=FieldType.Date, format={DateFormat.basic_date, DateFormat.basic_time})Spring中文文档

“basic_date||basic_time”Spring中文文档

@Field(type=FieldType.Date, pattern=“dd.MM.uuuu”)Spring中文文档

“date_optional_time||epoch_millis||dd.MM.uuuu“,Spring中文文档

@Field(type=FieldType.Date, format={}, pattern=“dd.MM.uuuu”)Spring中文文档

“dd.MM.uuuu”Spring中文文档

如果您使用的是自定义日期格式,则需要使用 uuuu 而不是 yyyy 来表示年份。 这是由于 Elasticsearch 7 中的更改
1 默认情况下,域类型类名用于类型提示。
确保将类型 with 添加到初始实体集 () 中,以便在首次从存储中读取数据时已具有可用的实体信息。@TypeAliasAbstractElasticsearchConfiguration#getInitialEntitySet
1 写入实体时使用配置的别名。
除非属性类型为 ,接口或实际值类型与属性声明不匹配,否则不会为嵌套对象编写类型提示。Object
我们强烈建议不要禁用类型提示。 只有在被迫的情况下才这样做。 在多态数据或文档检索可能完全失败的情况下,禁用类型提示可能会导致无法从 Elasticsearch 正确检索文档。
1 添加实现。Converter
2 设置用于写入 Elasticsearch。ConverterDomainType
3 设置用于从搜索结果中读取。ConverterDomainType