ElasticSearch ‐ @Document와 @Entity 같이 써도 괜찮을까? - dnwls16071/Backend_Study_TIL GitHub Wiki
📚 @Entity와 @Document를 함께 사용하는 경우
- 엔티티에 @Document를 부착해도 된다. 하지만 Repository를 사용할 때 문제가 생기는데 이는 @EnableJpaRepositories와 @EnableElasticsearchRepositories의 스프링 빈 충돌이 발생하기 때문에 JPA와 ElasticSearch를 분리해서 사용해야 한다.
- 하지만 동시에 사용하려고 하면은 빈 충돌이 발생하지 않도록 직접 수동으로 설정을 해줘야 한다. 이는 Repository를 추가할 때마다 설정을 해줘야 하기 때문에 번거로운 작업이 된다.
❗따라서 @Entity와 @Document를 분리해서 사용하는 것이 좋다.
package com.example.Kakfa_Data_Pipeline;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
// 아래와 같이 각 경로를 명확하게 패키지 기준으로 명확하게 분리하는게 훨씬 깔끔하고 관리도 쉽다.
// ----------------------------------------------------------------------------- //
@EnableJpaRepositories(basePackages = "com.example.Kakfa_Data_Pipeline.repository")
@EnableElasticsearchRepositories(basePackages = "com.example.Kakfa_Data_Pipeline.elasticSearch")
// ----------------------------------------------------------------------------- //
public class KakfaDataPipelineApplication {
public static void main(String[] args) {
SpringApplication.run(KakfaDataPipelineApplication.class, args);
}
}
📚 Document 작성
package com.example.Kakfa_Data_Pipeline.elasticSearch;
import com.example.Kakfa_Data_Pipeline.entity.Order;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(indexName = "orders")
public class OrderDocument {
@Id
private String id;
@Field(type = FieldType.Date)
private LocalDateTime orderDate;
@Field(type = FieldType.Integer)
private int totalAmount;
@Field(type = FieldType.Nested)
private List<OrderItemDocument> orderItems; // OrderItemDocument 리스트
public static OrderDocument fromEntity(Order order) {
if (order == null) {
return null;
}
List<OrderItemDocument> orderItemDocuments = order.getOrderItems().stream()
.map(OrderItemDocument::fromEntity)
.collect(Collectors.toList());
return OrderDocument.builder()
.id(order.getId().toString())
.orderDate(LocalDateTime.now())
.totalAmount(order.getTotalAmount())
.orderItems(orderItemDocuments)
.build();
}
}
package com.example.Kakfa_Data_Pipeline.elasticSearch;
import com.example.Kakfa_Data_Pipeline.entity.OrderItem;
import com.example.Kakfa_Data_Pipeline.entity.Product;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderItemDocument {
@Field(type = FieldType.Keyword)
private String productId;
@Field(type = FieldType.Text, fielddata = true)
private String productName;
@Field(type = FieldType.Integer)
private int orderPrice;
@Field(type = FieldType.Integer)
private int quantity;
@Field(type = FieldType.Integer)
private int totalPrice;
public static OrderItemDocument fromEntity(OrderItem orderItem) {
if (orderItem == null) {
return null;
}
Product product = orderItem.getProduct();
return OrderItemDocument.builder()
.productId(product.getId().toString())
.productName(product.getName())
.orderPrice(orderItem.getOrderPrice())
.quantity(orderItem.getQuantity())
.totalPrice(orderItem.getOrderPrice() * orderItem.getQuantity())
.build();
}
}