@RestController @RequestMapping("products") public class ProductController { ... @GetMapping("/suggestions") public ResponseEntity<List<String>> getSuggestions(@RequestParam String query) { List<String> suggestions = productService.getSuggestions(query); return ResponseEntity.ok(suggestions); } ... }
@Service public class ProductService { private final ProductRepository productRepository; private final ProductDocumentRepository productDocumentRepository; private final ElasticsearchOperations elasticsearchOperations; public ProductService(ProductRepository productRepository, ProductDocumentRepository productDocumentRepository, ElasticsearchOperations elasticsearchOperations) { this.productRepository = productRepository; this.productDocumentRepository = productDocumentRepository; this.elasticsearchOperations = elasticsearchOperations; } ... }
@Service public class ProductService { ... public List<String> getSuggestions(String query) { Query multiMatchQuery = MultiMatchQuery.of(m -> m .query(query) .type(TextQueryType.BoolPrefix) .fields("name.auto_complete", "name.auto_complete._2gram", "name.auto_complete._3gram") )._toQuery(); NativeQuery nativeQuery = NativeQuery.builder() .withQuery(multiMatchQuery) .withPageable(PageRequest.of(0, 5)) .build(); SearchHits<ProductDocument> searchHits = this.elasticsearchOperations.search(nativeQuery, ProductDocument.class); return searchHits.getSearchHits().stream() .map(hit -> { ProductDocument productDocument = hit.getContent(); return productDocument.getName(); }) .toList(); } ... }
{ "name": "곱창 돌김생김", "description": "신선한 곱창김으로 만든 전통 방식의 돌김입니다.", "price": 3900, "rating": 4.5, "category": "식품" } { "name": "구운 돌김", "description": "불에 구워 바삭한 식감을 살린 프리미엄 돌김.", "price": 4500, "rating": 4.7, "category": "식품" } { "name": "완도 곱창 돌김 100매", "description": "완도산 곱창김 100매 구성, 김밥용으로 적합.", "price": 12900, "rating": 4.8, "category": "식품" }


돌, 돌김, 곱, 곱창으로 요청을 보냈을 때 자동 완성 API의 응답값이 잘 날라오는 걸 확인할 수있다.