해줘야 할 일은 크게 3가지
1. 인덱스 생성
2. 데이터 저장
3. 검색 API 요청
* Elasaticsearch의 Client
자바에서 ES API를 이용하기 위해서 ES에서 만들어 놓은 클라이언트가 필요함.
ES 7버전까지 Client는 HighLevelClient와 LowLevelClient가 있음.
HighLevelClient는 API를 추상화시켜 놓아서 SDK 형식으로 사용할 수 있음.
ES 8버전으로 넘어오면서 이 기능이 더이상 사용되지 않음.
Elasticsearch 연결
build.greadle에 아래의 의존성 추가
implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'
Elasticsearch 구성
application.properties에 ES관련 설정.
spring.data.elasticsearch.cluster-nodes=localhost:9300
spring.data.elasticsearch.cluster-name=docker-cluster
Config 작성
http port와 통신할 주소를 적어줌.
@Configuration
@EnableElasticsearchRepositories
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Value("${elasticsearch.host}")
private String host;
@Value("${elasticsearch.port}")
private int port;
@Override
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo(host+":"+port)
.build();
return RestClients.create(clientConfiguration).rest();
}
}
Document 생성
Document로 관리할 클래스에 @Document를 달아줘야하는데 Entity와 Document를 따로 만들어야함.
Spring boot의 AutoConfiguration이 작동할 때 JPA와 Elastic search 중 Repository에 어떤 걸 사용할지 충돌이 발생하기 때문.
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Setting(settingPath = "/elastic/elastic-settings.json")
@Mapping(mappingPath = "/elastic/product-mappings.json")
@Document(indexName = "product")
public class ProductDocument {
@Id
private Long id;
private String productName;
private Long price;
private int ranking;
public static ProductDocument from(Product product) {
return ProductDocument.builder()
.id(product.getId())
.productName(product.getProductName())
.price(product.getPrice())
.ranking(product.getRanking())
.build();
}
}
- ES에 타입을 매핑하는 방법 2가지
1. @Field 어노테이션을 통해 직접 타입 설정.
2. @Setting, @Mapping 사용
@Setting은 분석기를 매핑, @Mapping은 타입을 매핑.
여기서 keyword는 analyzer 적용이 안 됨.
<elastic-settings.json>
{
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "nori"
}
}
}
}
<product-mappings.json>
{
"properties": {
"id": {
"type": "keyword"
},
"productName": {
"type": "text",
"analyzer": "my_analyzer"
},
"price": {
"type": "long"
},
"ranking": {
"type": "Integer"
}
}
}
setting과 mapping을 해줬다.
ProductSearchRepository.java
ElasticsearchRepository를 상속받아 구현.
@Repository
public interface ProductSearchRepository extends ElasticsearchRepository<ProductDocument, Long> {
List<ProductDocument> findByProductName(String productName, Pageable pageable);
}
ProductService.java
@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
private final ProductSearchRepository productSearchRepository;
public void saveProduct(SaveProduct saveProduct) {
Product productEntity = productRepository.save(saveProduct.toEntity());
productSearchRepository.save(
ProductDocument.from(productEntity));
}
public List<SearchProduct.Response> findByProductName(
SearchProduct.Request request, Pageable pageable) {
return productSearchRepository.findByProductName(
request.getProductName(), pageable)
.stream()
.map(Response::from)
.collect(Collectors.toList());
}
}
ProductController.java
@RestController
@RequiredArgsConstructor
@RequestMapping("/product")
@Slf4j
public class ProductController {
private final ProductService productService;
@PostMapping("/save")
public ResponseEntity<Void> save(@RequestBody SaveProduct saveProduct) {
productService.saveProduct(saveProduct);
return ResponseEntity.ok().build();
}
@PostMapping("/search")
public ResponseEntity<List<Response>> search(
@RequestBody SearchProduct.Request request,
Pageable pageable) {
return ResponseEntity.ok(
productService.findByProductName(request, pageable));
}
}
테스트
키바나로 접속해서 Discover -> create Index pattern 해서 product* 이름의 인덱스 패턴을 생성한다.
하는 도중에 product가 index로 등록되어있는 것이 보이는데 코드상에 @Document(indexName = "product") 했던 것이 생성된 것이다.
인덱스 패턴을 생성하고 discover 에 들어가면 입력한 데이터가 잘 저장되어있는 것을 확인할 수 있다.
Dev tools 가서도 인덱스 잘 생성되었나 확인해볼 수 있다.
막상 구현하니까 공부했던 것만큼 어렵지가 않다.
이제껏 했던 거는 GCP에서 하느라 엄청 오래 걸렸던 것 같다.
상세한 검색옵션은 계속 추가해나가는 걸로 하고 이쯤에서 1차 구현 완료 !
참조
'프로젝트' 카테고리의 다른 글
협업 프로젝트 Keyword) Github Organization Repository 초기 설정 (fork, clone, upstream) (1) | 2023.12.29 |
---|---|
GiftFunding) 스켸줄러 이용해 친구 요청 거절 항목을 하루 뒤 삭제 (0) | 2023.12.13 |
GiftFunding) Docker Compose로 es와 kibana 띄우기 + nori 까지 설치 (1) | 2023.12.09 |
GiftFunding) 도커에 Elasticsearch, Kibana 컨테이너 다운 및 실행 (2) | 2023.12.08 |
GiftFunding) 헤더에 JWT 토큰으로 로그인 후 사용자 정보 얻기 (0) | 2023.12.01 |