Elasticsearch 对象映射
Spring Data Elasticsearch 对象映射是将 Java 对象(域实体)映射到存储在 Elasticsearch 中的 JSON 表示形式并返回的过程。
内部用于此映射的类是 .MappingElasticsearchConverter
元模型对象映射
基于 Metamodel 的方法使用域类型信息从 Elasticsearch 读取/写入 Elasticsearch。
这允许为特定的域类型映射注册实例。Converter
映射注释概述
它使用元数据来驱动对象到文档的映射。
元数据取自实体的属性,这些属性可以进行批注。MappingElasticsearchConverter
可以使用以下注释:
-
@Document
:在类级别应用,以指示此类是映射到数据库的候选项。 最重要的属性是(查看 API 文档以获取完整的属性列表):-
indexName
:用于存储此实体的索引的名称。 这可以包含一个 SPEL 模板表达式,例如"log-#{T(java.time.LocalDate).now().toString()}"
-
createIndex
:标记是否在存储库引导时创建索引。 默认值为 true。 请参阅使用相应的映射自动创建索引
-
-
@Id
:在字段级别应用,以标记用于身份目的的字段。 -
@Transient
、 、 :有关详细信息,请参阅以下部分 控制写入 Elasticsearch 和从 Elasticsearch 读取的属性。@ReadOnlyProperty
@WriteOnlyProperty
-
@PersistenceConstructor
:标记给定的构造函数 - 甚至是受包保护的构造函数 - 在实例化数据库中的对象时使用。 构造函数参数按名称映射到检索到 Document 中的键值。 -
@Field
:在字段级别应用并定义字段的属性,大多数属性映射到相应的 Elasticsearch 映射定义(以下列表不完整,请查看注释 Javadoc 以获取完整参考):-
name
:字段的名称,它将在 Elasticsearch 文档中表示,如果未设置,则使用 Java 字段名称。 -
type
:字段类型可以是文本、关键字、长整型、整型、短整型、字节、双精度、浮点型、Half_Float、Scaled_Float、日期、Date_Nanos、布尔值、二进制、Integer_Range、Float_Range、Long_Range、Double_Range、Date_Range、Ip_Range、对象、嵌套、Ip、TokenCount、Percolator、Flattened Search_As_You_Type 之一。 请参阅 Elasticsearch 映射类型。 如果未指定字段类型,则默认为 。 这意味着,不会为该属性写入映射条目,并且 Elasticsearch 将在存储此属性的第一个数据时动态添加映射条目(请查看 Elasticsearch 文档以了解动态映射规则)。FieldType.Auto
-
format
:一个或多个内置日期格式,请参阅下一部分 日期格式映射. -
pattern
:一个或多个自定义日期格式,请参阅下一部分 日期格式映射. -
store
:标记是否应将原始字段值存储在 Elasticsearch 中,默认值为 false。 -
analyzer
、 、 用于指定自定义分析器和规范化器。searchAnalyzer
normalizer
-
-
@GeoPoint
:将字段标记为geo_point数据类型。 如果字段是类的实例,则可以省略。GeoPoint
-
@ValueConverter
定义用于转换给定属性的类。 与注册的 Spring 不同,这只转换带注释的属性,而不是给定类型的每个属性。Converter
映射元数据基础结构在单独的spring-data-commons项目中定义,该项目与技术无关。
控制哪些属性写入 Elasticsearch 和从 Elasticsearch 读取哪些属性
本节详细介绍了定义属性值是写入 Elasticsearch 还是从 Elasticsearch 读取的注释。
@Transient
:使用此注释注释的属性不会写入映射,其值不会发送到 Elasticsearch,并且当从 Elasticsearch 返回文档时,不会在生成的实体中设置此属性。
@ReadOnlyProperty
:具有此注释的属性不会将其值写入 Elasticsearch,但在返回数据时,该属性将填充从 Elasticsearch 返回的文档中的值。
其中一个用例是在索引映射中定义的运行时字段。
@WriteOnlyProperty
:具有此注释的属性的值将存储在 Elasticsearch 中,但在读取文档时不会设置任何值。
例如,这可用于应进入 Elasticsearch 索引但不在其他地方使用的合成字段。
日期格式映射
派生自 type 或 type 的属性必须具有 type 的注释,或者必须为此类型注册自定义转换器。
本段介绍了 的用法。TemporalAccessor
java.util.Date
@Field
FieldType.Date
FieldType.Date
注释有两个属性,用于定义将哪些日期格式信息写入映射(另请参阅 Elasticsearch 内置格式和 Elasticsearch 自定义日期格式@Field
)
该属性用于定义至少一种预定义格式。
如果未定义,则使用默认值 _date_optional_time 和 epoch_millis。format
该属性可用于添加其他自定义格式字符串。
如果只想使用自定义日期格式,则必须将该属性设置为 empty 。pattern
format
{}
下表显示了不同的属性以及根据其值创建的映射:
注解 | format 字符串 |
---|---|
@Field(type=FieldType.Date) |
“date_optional_time||epoch_millis“, |
@Field(type=FieldType.Date, format=DateFormat.basic_date) |
“basic_date” |
@Field(type=FieldType.Date, format={DateFormat.basic_date, DateFormat.basic_time}) |
“basic_date||basic_time” |
@Field(type=FieldType.Date, pattern=“dd.MM.uuuu”) |
“date_optional_time||epoch_millis||dd.MM.uuuu“, |
@Field(type=FieldType.Date, format={}, pattern=“dd.MM.uuuu”) |
“dd.MM.uuuu” |
如果您使用的是自定义日期格式,则需要使用 uuuu 表示年份,而不是 yyyy。 这是由于 Elasticsearch 7 中的更改。 |
检查枚举的代码以获取预定义值及其模式的完整列表。org.springframework.data.elasticsearch.annotations.DateFormat
范围类型
当字段使用 Integer_Range、Float_Range、Long_Range、Double_Range、Date_Range 或 Ip_Range 之一进行注释时,该字段必须是将映射到 Elasticsearch 范围的类的实例,例如:
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>
class SomePersonData {
@Field(type = FieldType.Integer_Range)
private Range<Integer> validAge;
// getter and setter
}
该类型支持的类是 、 、 、 和实现接口的类。<T>
Integer
Long
Float
Double
Date
TemporalAccessor
映射的字段名称
无需进一步配置, Spring Data Elasticsearch 将使用对象的属性名称作为 Elasticsearch 中的字段名称。
这可以通过使用该属性上的注释来更改单个字段。@Field
也可以在客户端的配置中定义 (Elasticsearch Clients)。
例如,如果配置了 a,则对象的属性 sampleProperty 将映射到 Elasticsearch 中的 sample_property。
A 适用于所有实体;可以通过在 Property 上设置特定名称来覆盖它。FieldNamingStrategy
SnakeCaseFieldNamingStrategy
FieldNamingStrategy
@Field
非字段支持的属性
通常,实体中使用的属性是实体类的字段。
在某些情况下,属性值是在实体中计算的,并且应该存储在 Elasticsearch 中。
在这种情况下,可以使用 Comments 对 getter 方法 () 进行注释,此外,该方法必须使用 进行 Comments。
在这种情况下,需要的第三个注释是 ,因为此类值仅写入 Elasticsearch。
一个完整的例子:getProperty()
@Field
@AccessType(AccessType.Type
.PROPERTY)
@WriteOnlyProperty
@Field(type = Keyword)
@WriteOnlyProperty
@AccessType(AccessType.Type.PROPERTY)
public String getProperty() {
return "some value that is calculated here";
}
映射规则
类型提示
映射使用嵌入在发送到服务器的文档中的类型提示来允许泛型类型映射。
这些类型提示在文档中表示为属性,并为每个聚合根写入。_class
public class Person { (1)
@Id String id;
String firstname;
String lastname;
}
{
"_class" : "com.example.Person", (1)
"id" : "cb7bef",
"firstname" : "Sarah",
"lastname" : "Connor"
}
1 | 默认情况下,域类型类名用于类型提示。 |
类型提示可以配置为保存自定义信息。
使用注释来执行此操作。@TypeAlias
确保将 types with 添加到初始实体集 () 中,以便在首次从存储中读取数据时已经具有可用的实体信息。@TypeAlias AbstractElasticsearchConfiguration#getInitialEntitySet |
@TypeAlias("human") (1)
public class Person {
@Id String id;
// ...
}
{
"_class" : "human", (1)
"id" : ...
}
1 | 在写入实体时使用配置的别名。 |
除非 properties type 为 、接口或实际值类型与 properties 声明不匹配,否则不会为嵌套 Object 编写类型提示。Object |
禁用类型提示
当应该使用的索引已经存在,而没有在其 Map 中定义类型提示并且 mapping 模式设置为 strict 时,可能需要禁用类型提示的写入。 在这种情况下,编写 type hint 将产生错误,因为无法自动添加字段。
可以通过覆盖派生自的配置类中的方法来禁用整个应用程序的类型提示(请参阅 Elasticsearch 客户端)。writeTypeHints()
AbstractElasticsearchConfiguration
作为替代方案,可以使用注释为单个索引禁用它们:@Document
@Document(indexName = "index", writeTypeHint = WriteTypeHint.FALSE)
我们强烈建议不要禁用 Type Hints。 仅在被迫时执行此操作。 禁用类型提示可能会导致无法从 Elasticsearch 中正确检索文档,以防多态数据或文档检索可能完全失败。 |
地理空间类型
像&这样的地理空间类型被转换为纬度/经度对。Point
GeoPoint
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 文档)GeoJson
geo_shape
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 类型:
-
GeoJsonPoint
-
GeoJsonMultiPoint
-
GeoJsonLineString
-
GeoJsonMultiLineString
-
GeoJsonPolygon
-
GeoJsonMultiPolygon
-
GeoJsonGeometryCollection
收集
对于 Collections 中的值,在类型提示和自定义转换方面,应用与聚合根相同的映射规则。
public class Person {
// ...
List<Person> friends;
}
{
// ...
"friends" : [ { "firstname" : "Kyle", "lastname" : "Reese" } ]
}
地图
对于 Maps 中的值,在类型提示和自定义转换方面,应用与聚合根相同的映射规则。 但是,Map 键需要为 String 才能由 Elasticsearch 处理。
public class Person {
// ...
Map<String, Address> knownLocations;
}
{
// ...
"knownLocations" : {
"arrivedAt" : {
"city" : "Los Angeles",
"street" : "2800 East Observatory Road",
"location" : { "lat" : 34.118347, "lon" : -118.3026284 }
}
}
}
自定义转化
查看上一节中的 可以注册用于映射 domain 和 simple types 的特定规则。Configuration
ElasticsearchCustomConversions
@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 | 添加 implementations。Converter |
2 | 设置 用于写入 Elasticsearch 的 。Converter DomainType |
3 | 设置 used for read from search result.Converter DomainType |