0. 서론
티켓 예매 서비스를 개발하면서 기존에는 LIKE 연산을 이용한 검색을 사용하고 있었습니다.
하지만 데이터가 많아질수록 LIKE 검색의 성능의 저하 문제가 발생할 뿐만 아니라, 검색어 자동완성, 실시간 인기 검색어 등의 고급 기능을 구현하기 위해서는 기존의 방식에는 한계가 많이 있었습니다.
이 문제를 해결하기 위해 Elasticsearch를 도입하게 되었습니다.
앞으로 두 편의 글을 통해 거쳐 Elasticsearch가 무엇인지 알아보고, Elasticsearch를 활용한 검색어 자동완성, 실시간 인기검색어 등의 기능을 구현하는 과정을 공유하려고 합니다. 1편에서는 Elasticsearch가 무엇인지 알아보고 설치까지 진행해보도록 하겠습니다!!
1. Elasticsearch란?
엘라스틱서치(Elasticsearch)는 대용량 데이터를 실시간으로 검색하고 분석할 수 있는 검색 및 분석 엔진입니다. Apache Lucene을 기반으로 하며, RESTful API를 제공해 JSON 형식의 데이터를 저장하고 검색할 수 있습니다.
주로 로그 분석, 검색 시스템, 보안 데이터 분석 등 다양한 분야에서 사용되며, ELK(Stack) 핵심 요소로 사용됩니다.
1-1. Elasticsearch가 빠른 이유는?
기존 RDBS에서 %를 통해 데이터를 검색하는 경우에는 Ticket의 테이블의 데이터가 많아질수록 느려지는 구조를 가집니다. 하지만 Elasticsearch는 역색인 구조를 사용해 검색 성능을 개선할 수 있습니다.
📌RDBMS에서 검색이 느린이유는?
RDBMS는 데이터를 행(row) 단위로 저장하고 LIKE %검색어% 같은 연산을 사용해야 합니다. 하지만 이 때 데이터가 많아질수록 문제가 발생하게 됩니다.
- 전체 테이블을 조회해야 한다(Full Table Scan)
- SELECT * FROM Ticket WHERE title LIKE '%모차르트%'
- 해당 검색어를 찾기 위해 모든 행을 탐색해야 함.
- 데이터가 많아질수록 검색 속도가 느려짐.
- B-Tree 기반 인덱스의 한계
- RDBMS에서 INDEX를 사용해도, 문자열 검색에서는 효율이 떨어짐.
- 일반적인 인덱스는 정확한 값 검색에 최적화되어 있지만, 부분 문자열 검색에는 비효율적!
📌그렇다면 Elasticsearch는 왜 빠를까요?
Elasticsearch는 역색인(Inverted Index) 구조를 사용해 데이터를 저장하고 검색합니다.
- 단어 단위로 인덱싱한다.
- 문장을 저장할 때, 단어(토큰) 단위로 잘라서 색인을 생성
- 예를 들어 "모차르트 환상의 연주" -> ["모차르트", "환상의", "연주"]의 형태로 저장
2. 검색 시 단어 기반 매칭을 수행한다.
- 검색어 "모차르트" 가 포함된 문서를 찾을 때, 역색인 테이블에서 즉시 해당 문서 목록을 반환
- 모든 문서를 일일이 비교할 필요가 없음
그림으로 나타낸 Elasticsearch의 역색인 구조는 아래와 같습니다.
위의 사진과 같이 역색인 구조(단어 -> 포함된 문서 목록)의 형태로 데이터를 저장하게 되고 "2025", "모차르트의" 같은 검색어를 입력하면 해당 키워드가 포함된 문서의 [1,2]를 즉시 반환해 전체 데이터를 탐색할 필요 없이 빠른 응답이 가능하게 됩니다.
지금까지 엘라스틱서치가 무엇인지 그리고 엘라스틱서치를 이용한 검색이 왜 빠른지 이유에 대해 알아보았습니다.
다음엔 본격적으로 엘라스틱서치를 설치해보도록 하겠습니다!
2. Elasticsearch, Kibana 설치하기
2-1 Docker-compose.yml파일 작성
version: '3.8'
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.6.0
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
ports:
- "9200:9200"
- "9300:9300"
volumes:
- esdata:/usr/share/elasticsearch/data
networks:
- es_network
kibana:
image: docker.elastic.co/kibana/kibana:8.6.0
container_name: kibana
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- es_network
networks:
es_network:
driver: bridge
volumes:
esdata:
driver: local
Kibana란?
키바나는 엘라스틱서치의 데이터를 시각화하고 대시보드로 보여주는 도구로 엘라스틱 서치의 데이터를 쉽게 조회, 분석, 모니터링 할 수 있도록 도와주는 도구
+ 주의할 점
- xpack.security.enabled=false 설정을 true로 해주면 접속시 username, password가 필요하게 됩니다.
이 때 엘라스틱서치의 기본 username은 elastic으로 설정되어 있는데 kibana에서 해당 USERNAME을 통해 접근하려할 때 아래와 같은 문제가 발생합니다.
"value of "elastic" is forbidden. This is a superuser account that cannot write to system indices that Kibana needs to function. "
이는 Elasticsearch 8.x 버전에서 elastic 사용자가 Kibana에 필요한 시스템 인덱스를 작성할 수 없기 때문입니다. 이를 해결하려면 서비스 계정 토큰을 사용하거나 kibana_system 사용자를 사용해야 합니다.
2-2 설치가 제대로 되었는지 확인하기
엘라스틱서치와 키바나가 제대로 설치되었는지 확인해줍니다.
엘라스틱서치 : localhost:9200
Kibana : localhost: 5601
2-2 Nori 형태소 분석기 설치하기
엘라스틱서치는 "아름다운 금수강산 우리나라" 라는 말이 있으면 "아름다운", "금수강산", "우리나라" 와 같은 단위로 분할하는데 이 때 tokenizer를 이용해 문서를 분할하게 되고 분할된 조각은 Token이라고 합니다.
tokenizer란? 텍스트를 토큰(단어 단위 조각)으로 나누는 역할을 한다.
기본적으로 제공되는 standard tokenizer를 이용하게되면 아래와 같이 띄어쓰기를 기준으로 분할되는 것을 확인할 수 있습니다.
GET _analyze
{
"tokenizer": {
"type": "standard"
},
"text": "아름다운 금수강산 우리나라"
}
//아름다운 //금수강산 //우리나라
다음으로는 한글 형태소의 분석을 세밀하게 도와줄 Nori(한글 형태소 분석기)를 설치해주겠습니다.
아래 명령어를 통해 nori 플러그인을 설치하고 엘라스틱서치를 재시작해줍니다.
docker exec -it elasticsearch bin/elasticsearch-plugin install analysis-nori
이후 nori_tokenizer를 이용해 테스트를 진행해보면
GET _analyze
{
"tokenizer": {
"type": "nori_tokenizer"
},
"text": "아름다운 금수강산 우리나라"
}
//아름답 //ㄴ //금수 //강산 //우리 //나라
위와 같이 아름답 // ㄴ // 금수 // 강산 // 우리 // 나라 형태로 좀 더 세밀하게 분할된 것을 확인할 수 있습니다.
(아름답// ㄴ 형태의 분할은 추후 조치가 필요할 것으로 예상됩니다.)
3. 총정리 및 다음편 예고
✅ Elasticsearch는 빠른 검색을 위한 역색인 구조를 사용한다.
✅ Kibana를 통해 Elasticsearch 데이터를 시각화하고 모니터링할 수 있다.
✅ Nori(한글 형태소 분석기)를 통해 한글의 세밀한 분할이 가능하다.
이제 설치까지 마쳤으니 2편에서는 본격적으로 검색, 실시간 검색순위 등 다양한 기능들을 구현해보겠습니다!

'Backend > 프로젝트' 카테고리의 다른 글
Elasticsearch 활용한 검색서비스 만들기 2편(feat. Spring Boot) (0) | 2025.03.12 |
---|---|
무중단 배포 적용하기 (0) | 2025.01.01 |
[Spring] 커버링 인덱스를 통한 페이징 성능 개선하기 (0) | 2024.12.12 |
[Spring] Redis 캐시 적용하기 (0) | 2024.10.31 |
nGrinder Docker 설치 및 사용방법 (0) | 2024.10.25 |