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();
	}
}