≣ 목차
유연한 검색 기능이 필요한 이유
유명한 브라우저나 쇼핑몰 플랫폼에서 검색을 해보면, 사용자가 입력한 단어의 순서가 바뀌었거나, 등록된 상품명과 정확히 일치하지 않아도 관련된 검색 결과가 노출되는 것을 볼 수 있습니다.
하지만 MySQL로 단순하게 검색 쿼리를 작성하면
SELECT * FROM table WHERE name = '사용자가 검색한 내용'
SELECT * FROM table WHERE name LIKE '%사용자가 검색한 내용%'
이 쿼리들은 입력된 단어가 정확하게 일치하거나 포함되어 있어야만 검색 결과를 반환합니다. 따라서 단어 순서가 바뀌었거나 일부 단어만 일치하는 경우, 원하는 결과가 검색되지 않을 수 있습니다.
이러한 문제점들은 Elasticsearch를 통해 효과적으로 해결될 수 있습니다. 물론 모든 브라우저 플랫폼이 Elasticsearch를 사용하는 것은 아니며 독자적인 검색 엔진을 활용하는 경우도 있고 MySQL의 풀텍스트(full-text) 검색 기능으로도 해결이 가능하지만 성능 및 확장성 측면에서 명확한 한계가 존재하므로, 본 포스팅에서는 Elasticsearch에 대해 이야기해 보겠습니다.
Elasticsearch의 유연한 검색이 가능한 이유
Elasticsearch가 유연한 검색을 제공할 수 있는 가장 핵심적인 이유는 역인덱스(Inverted Index) 덕분입니다. 이 구조 덕분에 단순한 텍스트 검색이 아니라, 단어 단위로 분해된 데이터에 기반한 고속 및 유연한 검색이 가능합니다.
역인덱스(Inverted Index)란?
일반적인 데이터베이스는 각 문서를 저장할 때 전체 내용을 그대로 저장하고, 검색 시 이를 순차적으로 비교합니다. 반면, Elasticsearch는 문서를 저장할 때 내용을 단어(Token) 단위로 분해(tokenizing) 하여, 각 단어가 어떤 문서에 존재하는지를 인덱스로 별도 관리합니다.
아래와 같이 4개의 도큐먼트를 Elasticsearch에 저장했다고 가정해봅니다.
POST /products/_create/1
{
"name": "Apple 정품 아이폰 16 Pro 자급제, 블랙 티타늄, 256GB"
}
POST /products/_create/2
{
"name": "Apple 정품 아이폰 16 Pro 자급제, 블랙 티타늄, 128GB"
}
POST /products/_create/3
{
"name": "Apple 정품 아이폰 16 자급제, 블랙 티타늄, 256GB"
}
POST /products/_create/4
{
"name": "Apple 정품 아이폰 15 Pro 자급제, 블랙 티타늄, 256GB"
}
Elasticsearch는 내부적으로 아래와 같이 각 단어를 기준으로 토큰화하고, 해당 단어가 등장한 도큐먼트 ID 목록을 저장합니다.
토큰(Token) | 도큐먼트 id |
apple | [1, 2, 3, 4] |
정품 | [1, 2, 3, 4] |
아이폰 | [1, 2, 3, 4] |
16 | [1, 2, 3] |
15 | [4] |
... | ... |
정확한 역인덱스 구조
이러한 역인덱스 구조 덕분에 사용자가 "아이폰 16 pro"라고 검색하면 Elasticsearch는 이 세 단어 각각이 포함된 도큐먼트 id를 빠르게 조회하고 Elasticsearch 자체적으로 점수(score)를 매겨서 점수가 가장 높은 순으로 조회합니다.
대략적인 점수 계산 로직
1. TF (Term Frequency)
- 문서 안에 특정 단어가 몇 번 등장했는지
- 자주 등장할수록 score 증가
2. IDF (Inverse Document Frequency)
- 전체 문서 중 특정 단어가 얼마나 희귀한지
- 드물게 나타나는 단어일수록 score 증가
- 예: "아이폰"보다 "티타늄 / 256GB" 같은 단어가 더 높은 점수
3. Field Length (필드 길이)
- 단어 수가 짧은 필드에서 검색어가 일치할 경우 score 증가
- 예: 문서 제목 같은 짧은 필드가 본문보다 점수가 더 높아질 수 있음(제목 > 본문)
이 과정은 전체 문서를 일일이 순회하는 것이 아니라, 미리 구축된 역인덱스를 참조하기 때문에 매우 빠르고 효율적이며, 단어 순서나 일부 누락에도 유연하게 대응할 수 있습니다. 이런 작동은 데이터 타입의 TEXT 타입에 한해서만 작동됩니다.