I have an entity 'Product' and I want the primary key in ES to be used as a combination of 'id' and 'name' attributes. How can we do that using spring data elastic search.
public class Product {
@Id
private String id;
@Id
private String name;
@Field(type = FieldType.Keyword)
private Category category;
@Field(type = FieldType.Long)
private double price;
@Field(type = FieldType.Object)
private List<ValidAge> age;
public enum Category {
CLOTHES,
ELECTRONICS,
GAMES;
}
}
CodePudding user response:
I am not sure about spring data elasticsearch but spring jpa provides the facility of defining composite primary key by using @IdClass where we can define a separate class(let us say class A) in which we can define all the fields which we want to be a part of composite key Then we can use @IdClass(A.class) in entity class and use @Id annotation on all the fields which should be the part of the composite key
you can refer to this article, although I am not sure whether the same concept will be applicable for spring data es - https://www.baeldung.com/jpa-composite-primary-keys
CodePudding user response:
One way to achieve this would be the following:
- first rename your
id
property, I changed it todocumentId
here. This is necessary, because in Spring Data Elasticsearch an id-property can be either annotated with@Id
or it can be namendid
. As there can only be one id-property we need to get this out of the way. It can have the name id in Elasticsearch, set by the@Field
annotation, but the Java property must be changed. - second, add a method annotated with
@Id
and@AccessType(AccessType.Type.PROPERTY)
which returns the value you want to use in Elasticsearch. - third, you need to provide noop-setter for this property. This is necessary because Spring Data Elasticsearchsoe not check the id property to be read only when populating an entity after save or when reading from the index. This is a bug in Spring Data Elasticsearch, I'll create an issue for that
So that comes up with an entity like this:
@Document(indexName = "composite-entity")
public class CompositeEntity {
@Field(name="id", type = FieldType.Keyword)
private String documentId;
@Field(type = FieldType.Keyword)
private String name;
@Field(type = FieldType.Text)
private String text;
@Id
@AccessType(AccessType.Type.PROPERTY)
public String getElasticsearchId() {
return documentId '-' name;
}
public void setElasticsearchId(String ignored) {
}
// other getter and setter
}
The repository definition would be straight forward:
public interface CompositeRepository extends ElasticsearchRepository<CompositeEntity,
String> {
}
Remember that for every method that needs an Elasticsearch Id, you'll need to create like it's done in the entity class.