포스트

(멋쟁이사자처럼_백엔드스쿨플러스) Day15 엘라스틱 서치

엘라스틱 서치

검색 알고리즘

1세대

  • Sql의 like 연산자를 활용하여 검색
  • 모든 컬럼의 값을 확인해야 하므로 검색 속도가 느림
1
2
3
4
5
6
SELECT * FROM post WHERE (
    subject LIKE '%검색어%'
    OR
    content LIKE '%검색어%'
)
AND createdDate BETWEEN '2025-01-01' AND '2025-01-31';

2세대(해시태그)

  • 중간에 브릿지 테이블을 만들어 검색어를 index화
  • 중간 테이블을 직접 만들어야 한다.
  • 해시태그와 같이 미리 테이블을 만들 경우 사용한다.
1
2
3
4
5
6
7
SELECT P.*
FROM postKeyword AS PK
INNER JOIN postTag AS PT 
ON PK.id = PT.postKeywordId
INNER JOIN post AS P
ON P.id = PT.postId
WHERE PK.content = '검색어'

3세대(엘라스틱 서치)

  • 엘라스틱 서치를 사용하여 검색
  • 모든 단어를 index화하여 별도의 테이블에 저장한다.
  • 모든 테이블을 검색하지 않아 검색속도가 빠르다.

엘라스틱 서치의 특징

  • RESTful API를 통한 검색엔진
  • 대용량 데이터 처리
  • 실시간 검색
  • 분산처리

엘라스틱 서치의 구성

클러스터의 구성요소

  • 하나의 마스터 노드와 여러개의 데이터노드로 구성
  • 마스터 노드 : 클러스터의 상태를 관리
  • 데이터 노드 : 데이터를 저장하고 검색 Image

Document, Index, 노드

  • 엘라스틱 서치는 document, index, 노드로 구성
  • 노드의 주요 구성 요소는 샤드가 있고, 샤드는 인덱스를 구성한다. Image

Document

  • 단일 데이터의 단위를 document라고 한다.
  • 관계형 DB의 row와 같은 개념

    1
    2
    3
    4
    5
    6
    
    {
        // Document 1 -  번째 
        "id": "book1",
        "title": "해리포터와 마법사의 돌",
        "category": "판타지"
    }
    

index

  • 도큐먼트의 집합
  • 관계형 DB의 daatabase와 같은 개념
  • 데이터를 저장하는 공간
  • 하나의 인덱스가 여러 노드에 분산저장

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    // books (Index) - 책들의 집합
    {
        // Document 1 -  번째 
        "id": "book1",
        "title": "해리포터와 마법사의 돌",
        "category": "판타지"
    }
      
    {
        // Document 2 -  번째 
        "id": "book2",
        "title": "해리포터와 비밀의 방",
        "category": "판타지"
    }
      
    {
        // Document 3 -  번째 
        "id": "book3",
        "title": "해리포터와 아즈카반의 죄수",
        "category": "판타지"
    }
    

Shard

  • 인덱스는 기본적으로 샤드 단위로 분리되어 노드에 저장
  • 인덱스 내부에 색인된 데이터는 여러개의 파티션으로 나누어 구성

    Image

index와 shard의 관계

  • Document를 모은 index 정보는 각노드의 shard에 저장 Image

엘라스틱 서치의 저장과정

  • 데이터를 저장할 때, 데이터를 index화하여 저장한다. Image

Elasticsearch(검색에 최적화된 데이터 공간, DB)

  • ELK에서 가장 중요한 역할을 하는 엘라스틱 서치
  • 데이터를 저장하고 검색하는 역할
  • 데이터를 저장할 때, 데이터를 index화하여 저장
  • 데이터를 검색할 때, index화된 데이터를 검색하여 결과를 반환

Logstash(데이터동기화, 파이프라인)

  • 다양한 소스에서 데이터를 수집하고, 변환하여 엘라스틱 서치에 전달
  • DB에 저장된 데이터를 엘라스틱 서치에 전달하는 역할

Kibana의(데이터 시각화)

  • 엘라스틱 서치에 저장된 데이터를 시각화하여 보여주는 역할

엘라스틱 서치 구동하고 접속하기

기본 프로젝트 구성

  • 기본 프로젝트 구성을 한다.

Docker-compose.yml 파일 작성

  • DockerCompose는 스프링부트가 실행될때 실행된다.
  • elasticsearch image를 넣고 실행 되면 elasticsearch가 실행된다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    services:    
      elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:8.3.3
        container_name: elasticsearch
        environment:
          - discovery.type=single-node
          - xpack.security.enabled=false
        ports:
          - "9200:9200"
    

    Document, Repository, Service 생성

  • Entity와 유사한 방식으로 Document객체를 정의한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    @Document(indexName="app1_posts")   
    // indexName은 데이터베이스명
    @Getter
    @Setter
    @Builder
    public class PostDoc {
        @Id
        private String id;
        private String title;
        private String content;
    }
    
  • Repository를 생성한다. 이때 JPARepository가 아닌 ElasticsearchRepository를 상속받는다.

    1
    2
    
    public interface PostDocRepository extends ElasticsearchRepository<PostDoc, String> {
    }
    

Service 생성

  • Service단에서 Repository를 주입받아서 사용한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    @Service
    @RequiredArgsConstructor
    public class PostDocService {
        private final PostDocRepository postDocRepository;
          
        public PostDoc save(PostDoc postDoc) {
            return postDocRepository.save(postDoc);
        }
    }
    

Elasticsearch 서버 접근 하기

  • elasticsearch는 기본적으로 9200포트로 접속한다.
  • localhost:9200으로 접속하여 확인한다.
  • elasticsearch는 RESTful API를 사용하여 데이터를 주고 받는다.

    GET /_cat/indices : 모든 인덱스 목록 조회
    GET /_search : 모든 인덱스에서 검색
    GET /{인덱스명}/_search : 특정 인덱스에서 검색 * 예제에서는 app1_posts
    PUT /{인덱스명} : 인덱스 생성
    DELETE /{인덱스명} : 인덱스 삭제
    POST /{인덱스명}/_doc : 문서 생성(ID 자동생성)
    PUT /{인덱스명}/_doc/{ID} : 문서 생성(ID 지정)
    GET /{인덱스명}/_doc/{ID} : 문서 조회
    DELETE /{인덱스명}/_doc/{ID} : 문서 삭제

데이터를 조회하기

  • 데이터를 조회하기 위해서는 API요청에 Json형식으로 Body에 담아 데이터를 전달한다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    {
        "query": {
            "match_all": {}
        }
    }
      
    # 검색어가 포함된 모든 문서 검색
    {
        "query": {
            "match": {
                "title": "검색어"
            }
        }
    }
    

데이터 저장 및 조회 구조

  • elastic 서버에 직접 접속하여 데이터를 저장하고 호출하는 구조이다. Image
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.