mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-11-26 11:41:32 +00:00
331 lines
11 KiB
Plaintext
331 lines
11 KiB
Plaintext
[[elasticsearch.mapping]]
|
|
= Elasticsearch Object Mapping
|
|
|
|
Spring Data Elasticsearch Object Mapping is the process that maps a Java object - the domain entity - into the JSON representation that is stored in Elasticsearch and back.
|
|
|
|
Earlier versions of Spring Data Elasticsearch used a Jackson based conversion, Spring Data Elasticsearch 3.2.x introduced the <<elasticsearch.mapping.meta-model>>.
|
|
As of version 4.0 only the Meta Object Mapping is used, the Jackson based mapper is not available anymore and the `MappingElasticsearchConverter` is used.
|
|
|
|
The main reasons for the removal of the Jackson based mapper are:
|
|
|
|
* Custom mappings of fields needed to be done with annotations like `@JsonFormat` or `@JsonInclude`.
|
|
This often caused problems when the same object was used in different JSON based datastores or sent over a JSON based API.
|
|
* Custom field types and formats also need to be stored into the Elasticsearch index mappings.
|
|
The Jackson based annotations did not fully provide all the information that is necessary to represent the types of Elasticsearch.
|
|
* Fields must be mapped not only when converting from and to entities, but also in query argument, returned data and on other places.
|
|
|
|
Using the `MappingElasticsearchConverter` now covers all these cases.
|
|
|
|
[[elasticsearch.mapping.meta-model]]
|
|
== Meta Model Object Mapping
|
|
|
|
The Metamodel based approach uses domain type information for reading/writing from/to Elasticsearch.
|
|
This allows to register `Converter` instances for specific domain type mapping.
|
|
|
|
[[elasticsearch.mapping.meta-model.annotations]]
|
|
=== Mapping Annotation Overview
|
|
|
|
The `MappingElasticsearchConverter` uses metadata to drive the mapping of objects to documents.
|
|
The metadata is taken from the entity's properties which can be annotated.
|
|
|
|
The following annotations are available:
|
|
|
|
* `@Document`: Applied at the class level to indicate this class is a candidate for mapping to the database.
|
|
The most important attributes are:
|
|
** `indexName`: the name of the index to store this entity in.
|
|
This can contain a SpEL template expression like `"log-#{T(java.time.LocalDate).now().toString()}"`
|
|
** `type`: [line-through]#the mapping type.
|
|
If not set, the lowercased simple name of the class is used.# (deprecated since version 4.0)
|
|
** `shards`: the number of shards for the index.
|
|
** `replicas`: the number of replicas for the index.
|
|
** `refreshIntervall`: Refresh interval for the index.
|
|
Used for index creation.
|
|
Default value is _"1s"_.
|
|
** `indexStoreType`: Index storage type for the index.
|
|
Used for index creation.
|
|
Default value is _"fs"_.
|
|
** `createIndex`: flag whether to create an index on repository bootstrapping.
|
|
Default value is _true_.
|
|
See <<elasticsearch.repositories.autocreation>>
|
|
** `versionType`: Configuration of version management.
|
|
Default value is _EXTERNAL_.
|
|
|
|
* `@Id`: Applied at the field level to mark the field used for identity purpose.
|
|
* `@Transient`: By default all fields are mapped to the document when it is stored or retrieved, this annotation excludes the field.
|
|
* `@PersistenceConstructor`: Marks a given constructor - even a package protected one - to use when instantiating the object from the database.
|
|
Constructor arguments are mapped by name to the key values in the retrieved Document.
|
|
* `@Field`: Applied at the field level and defines properties of the field, most of the attributes map to the respective https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html[Elasticsearch Mapping] definitions (the following list is not complete, check the annotation Javadoc for a complete reference):
|
|
** `name`: The name of the field as it will be represented in the Elasticsearch document, if not set, the Java field name is used.
|
|
** `type`: the field type, can be one of _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_.
|
|
See https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html[Elasticsearch Mapping Types]
|
|
** `format` and `pattern` definitions for the _Date_ type.
|
|
** `store`: Flag whether the original field value should be store in Elasticsearch, default value is _false_.
|
|
** `analyzer`, `searchAnalyzer`, `normalizer` for specifying custom analyzers and normalizer.
|
|
* `@GeoPoint`: marks a field as _geo_point_ datatype.
|
|
Can be omitted if the field is an instance of the `GeoPoint` class.
|
|
|
|
NOTE: Properties that derive from `TemporalAccessor` or are of type `java.util.Date` must either have a `@Field` annotation of type `FieldType.Date` and a
|
|
format different from `DateFormat.none` or a custom converter must be registered for this type. +
|
|
If you are using a custom date format, you need to use _uuuu_ for the year instead of _yyyy_.
|
|
This is due to a https://www.elastic.co/guide/en/elasticsearch/reference/current/migrate-to-java-time.html#java-time-migration-incompatible-date-formats[change in Elasticsearch 7].
|
|
|
|
The mapping metadata infrastructure is defined in a separate spring-data-commons project that is technology agnostic.
|
|
|
|
==== Mapped field names
|
|
|
|
Without further configuration, Spring Data Elasticsearch will use the property name of an object as field name in Elasticsearch. This can be changed for individual field by using the `@Field` annotation on that property.
|
|
|
|
It is also possible to define a `FieldNamingStrategy` in the configuration of the client (<<elasticsearch.clients>>). If for example a `SnakeCaseFieldNamingStrategy` is configured, the property _sampleProperty_ of the object would be mapped to _sample_property_ in Elasticsearch. A `FieldNamingStrategy` applies to all entities; it can be overwritten by
|
|
setting a specific name with `@Field` on a property.
|
|
|
|
[[elasticsearch.mapping.meta-model.rules]]
|
|
=== Mapping Rules
|
|
|
|
==== Type Hints
|
|
|
|
Mapping uses _type hints_ embedded in the document sent to the server to allow generic type mapping.
|
|
Those type hints are represented as `_class` attributes within the document and are written for each aggregate root.
|
|
|
|
.Type Hints
|
|
====
|
|
[source,java]
|
|
----
|
|
public class Person { <1>
|
|
|
|
@Id String id;
|
|
String firstname;
|
|
String lastname;
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"_class" : "com.example.Person", <1>
|
|
"id" : "cb7bef",
|
|
"firstname" : "Sarah",
|
|
"lastname" : "Connor"
|
|
}
|
|
----
|
|
<1> By default the domain types class name is used for the type hint.
|
|
====
|
|
|
|
Type hints can be configured to hold custom information.
|
|
Use the `@TypeAlias` annotation to do so.
|
|
|
|
NOTE: Make sure to add types with `@TypeAlias` to the initial entity set (`AbstractElasticsearchConfiguration#getInitialEntitySet`) to already have entity information available when first reading data from the store.
|
|
|
|
.Type Hints with Alias
|
|
====
|
|
[source,java]
|
|
----
|
|
@TypeAlias("human") <1>
|
|
public class Person {
|
|
|
|
@Id String id;
|
|
// ...
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"_class" : "human", <1>
|
|
"id" : ...
|
|
}
|
|
----
|
|
<1> The configured alias is used when writing the entity.
|
|
====
|
|
|
|
NOTE: Type hints will not be written for nested Objects unless the properties type is `Object`, an interface or the actual value type does not match the properties declaration.
|
|
|
|
==== Geospatial Types
|
|
|
|
Geospatial types like `Point` & `GeoPoint` are converted into _lat/lon_ pairs.
|
|
|
|
.Geospatial types
|
|
====
|
|
[source,java]
|
|
----
|
|
public class Address {
|
|
|
|
String city, street;
|
|
Point location;
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"city" : "Los Angeles",
|
|
"street" : "2800 East Observatory Road",
|
|
"location" : { "lat" : 34.118347, "lon" : -118.3026284 }
|
|
}
|
|
----
|
|
====
|
|
|
|
==== GeoJson Types
|
|
|
|
Spring Data Elasticsearch supports the GeoJson types by providing an interface `GeoJson` and implementations for the different geometries.
|
|
They are mapped to Elasticsearch documents according to the GeoJson specification.
|
|
The corresponding properties of the entity are specified in the index mappings as `geo_shape` when the index mappings is written. (check the https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-shape.html[Elasticsearch documentation] as well)
|
|
|
|
.GeoJson types
|
|
====
|
|
[source,java]
|
|
----
|
|
public class Address {
|
|
|
|
String city, street;
|
|
GeoJsonPoint location;
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"city": "Los Angeles",
|
|
"street": "2800 East Observatory Road",
|
|
"location": {
|
|
"type": "Point",
|
|
"coordinates": [-118.3026284, 34.118347]
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
The following GeoJson types are implemented:
|
|
|
|
* `GeoJsonPoint`
|
|
* `GeoJsonMultiPoint`
|
|
* `GeoJsonLineString`
|
|
* `GeoJsonMultiLineString`
|
|
* `GeoJsonPolygon`
|
|
* `GeoJsonMultiPolygon`
|
|
* `GeoJsonGeometryCollection`
|
|
|
|
==== Collections
|
|
|
|
For values inside Collections apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <<elasticsearch.mapping.meta-model.conversions>>.
|
|
|
|
.Collections
|
|
====
|
|
[source,java]
|
|
----
|
|
public class Person {
|
|
|
|
// ...
|
|
|
|
List<Person> friends;
|
|
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
// ...
|
|
|
|
"friends" : [ { "firstname" : "Kyle", "lastname" : "Reese" } ]
|
|
}
|
|
----
|
|
====
|
|
|
|
==== Maps
|
|
|
|
For values inside Maps apply the same mapping rules as for aggregate roots when it comes to _type hints_ and <<elasticsearch.mapping.meta-model.conversions>>.
|
|
However the Map key needs to a String to be processed by Elasticsearch.
|
|
|
|
.Collections
|
|
====
|
|
[source,java]
|
|
----
|
|
public class Person {
|
|
|
|
// ...
|
|
|
|
Map<String, Address> knownLocations;
|
|
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
// ...
|
|
|
|
"knownLocations" : {
|
|
"arrivedAt" : {
|
|
"city" : "Los Angeles",
|
|
"street" : "2800 East Observatory Road",
|
|
"location" : { "lat" : 34.118347, "lon" : -118.3026284 }
|
|
}
|
|
}
|
|
}
|
|
----
|
|
====
|
|
|
|
[[elasticsearch.mapping.meta-model.conversions]]
|
|
=== Custom Conversions
|
|
|
|
Looking at the `Configuration` from the <<elasticsearch.mapping.meta-model, previous section>> `ElasticsearchCustomConversions` allows registering specific rules for mapping domain and simple types.
|
|
|
|
.Meta Model Object Mapping Configuration
|
|
====
|
|
[source,java]
|
|
----
|
|
@Configuration
|
|
public class Config extends AbstractElasticsearchConfiguration {
|
|
|
|
@Override
|
|
public RestHighLevelClient elasticsearchClient() {
|
|
return RestClients.create(ClientConfiguration.create("localhost:9200")).rest();
|
|
}
|
|
|
|
@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;
|
|
}
|
|
}
|
|
}
|
|
----
|
|
|
|
[source,json]
|
|
----
|
|
{
|
|
"ciudad" : "Los Angeles",
|
|
"calle" : "2800 East Observatory Road",
|
|
"localidad" : { "lat" : 34.118347, "lon" : -118.3026284 }
|
|
}
|
|
----
|
|
<1> Add `Converter` implementations.
|
|
<2> Set up the `Converter` used for writing `DomainType` to Elasticsearch.
|
|
<3> Set up the `Converter` used for reading `DomainType` from search result.
|
|
====
|