[Elasticsearch] Elasticsearch + SpringBoot로 검색 기능 구현

CodeKong의 기술 블로그·2024년 2월 16일
3

ElasticSearch

목록 보기
1/1
post-thumbnail

안녕하세요 진행중인 ShareMore 프로젝트에서 검색기능 구현이 필요해 ElasticSearch를 구현해보았습니다!

📌 ElasticSearch란?

ElasticSearch는 분산형 RESTful 검색 및 분석 엔진입니다.
검색에 최적화된 엔진인 만큼 로깅 서치 등에 많이 활용되고 있습니다!

📌 ElasticSearch vs RDB

ElasticSearch와 RDB는 어떻게 다를까요?

RDB는 기본적으로 행 저장 형태입니다!

때문에 저장과 삭제가 용이하다는 장점이 있는데요
특정 조건으로 검색을 할 때는 모든 행을 다 탐색해야 한다는 단점또한 가지고 있습니다!

반면 ElasticSearch는 단어 기반 역인덱스 저장 방식입니다.

이와 같이 역 인덱스를 통해 단어기반으로 쉽게 검색할 수 있도록 하였고
검색에 특화 될 수 있습니다.
하지만 그만큼 삭제는 RDB에 비해 용이하지 않다는 단점도 있습니다.


🛠️ 세팅 - docker-compose

먼저 docker-compose를 통해 여러 image들을 한꺼번에 실행 시켜줄겁니다!

els.yml

version: '3.7'
services:
  es:
    container_name: es
    environment:
      - node.name=single-node
      - cluster.name=backtony
      - discovery.type=single-node
    ports:
      - 9200:9200
      - 9300:9300
    networks:
      - es-bridge

  kibana:
    container_name: kibana
    image: docker.elastic.co/kibana/kibana:7.15.2
    environment:
      SERVER_NAME: kibana
      ELASTICSEARCH_HOSTS: http://es:9200
    ports:
      - 5601:5601
    # Elasticsearch Start Dependency
    depends_on:
      - es
    networks:
      - es-bridge

networks:
  es-bridge:
    driver: bridge

🚩 여기서 kibana란?

간단하게 일래스틱서치용의 소스 이용이 가능한 데이터 시각화 대시보드 소프트웨어입니다.
자세한 정보는 추후 포스팅하겠습니다!

참고로 docker는 설치되어야 있어야하며 window 환경은 docker-desktop까지 실행되어있어야 합니다!

docker compose -f els.yml up -d

로 실행 시켜 줍니다!

잘실행되었고 http://localhost:5601 로 접속하면

kibana를 통한 시각화 화면이 나오게됩니다!


🛠️ 세팅 - SpringBoot

먼저 의존성 추가해줍니다!

implementation 'org.springframework.boot:spring-boot-starter-data-elasticsearch'

Spring Data Elasticsearch는 기존의 의존성을 추가하여 사용자로 하여금 쿼리를 편하게 해주는 라이브러리 등을 추가하여 지원해줍니다!

실제로 elastic 공식문서에서 권장하는 기본적인 의존성을 모두 포함하고 있습니다.


또한 ElasticSearch에 접근하여 Opration을 수행하기 위해 Configuration해줍니다!

@Configuration
@EnableElasticsearchRepositories(basePackages = "org.springframework.data.elasticsearch.repository")
public class ElasticSearchConfig extends ElasticsearchConfiguration {

    @Override
    public ClientConfiguration clientConfiguration() {
        return ClientConfiguration.builder()
                .connectedTo("localhost:9200")
                .build();
    }
}

✏️ Entity

@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@Builder
@Document(indexName = "item")
@Mapping(mappingPath = "static/elastic-mapping.json")
@Setting(settingPath = "static/elastic-token.json")
public class ItemDocument {

    @Id
    @Field(name = "id", type = FieldType.Keyword)
    private String itemId;

    @Field(type = FieldType.Keyword)
    private String user;

    @Field(type = FieldType.Text)
    private String name;

    @Field(type = FieldType.Text)
    private String description;

    @Field(type = FieldType.Text)
    private String category;

    @Field(type = FieldType.Integer)
    private int price;

    @Field(type = FieldType.Text)
    private String itemImage;

}
  • @Document를 통해 ElasticSearch의 "item" 인덱스에 매핑합니다.
    -@Mapping, @Setting 를 통해 클래스에 해당하는 매핑/세팅 정보를 json파일에서 가져옵니다.
    자세한 설정은 ElasticSearch 번역문서 에서 확인해주세요! 굉장히 잘 번역되어있습니다.

✏️ Repository

public interface ItemSearchRepository extends ElasticsearchRepository<ItemDocument, Long> {

    List<ItemDocument> findByName(String keyword);
}

저는 이름으로 찾을 수 있도록 쿼리를 추가하였습니다.


✏️ Service

@Service
@RequiredArgsConstructor
public class ItemSearchService {

    private final ItemSearchRepository itemSearchRepository;

    public ItemDocument createItem(ItemDocument itemDocument) {
        return itemSearchRepository.save(itemDocument);
    }

    public List<ItemDocument> getItemByName(String keyword) {
        List<ItemDocument> byName = itemSearchRepository.findByName(keyword);
        return byName;
    }

}

간단하게 생성과 조회만 해보도록할게요!


✏️ Controller

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/item/search")
public class ItemSearchController {

    private final ItemSearchService itemSearchService;

    @GetMapping
    public ApiResponse<List<ItemDocument>> search(@RequestParam("keyword") String keyword) {
        return ApiResponse.onSuccess(itemSearchService.getItemByName(keyword));
    }

    @PostMapping
    public ApiResponse<ItemDocument> create(@RequestBody ItemDocument itemDocument) {
        return ApiResponse.onSuccess(itemSearchService.createItem(itemDocument));
    }

}

🚩 테스트

❇️ 생성

❇️ 조회


잘 조회되었습니다!🔫🔫


🚩 결론

ElasticSearch를 통해 거의 실시간으로 검색 기능을 사용할 수 있었습니다.
다음에는 ELK같은 로깅 시스템에 적용해보도록하겠습니다!

0개의 댓글