검색엔진 3종 전격 비교! OpenSearch vs Typesense vs PostgreSQL
OpenSearch, Typesense, PostgreSQL pg_trgm에 직접 한국어 데이터를 넣고 검색 품질, 속도, 메모리를 비교해봤습니다. 예상과 달랐던 결과와 결국 OpenSearch를 걷어낸 이유를 정리합니다.
앱에 검색을 붙이다 보면 생각보다 일이 커집니다.
처음에는 그냥 DB에서 찾으면 될 것 같습니다.
그런데 실제 사람들은 검색을 정확하게 하지 않습니다.
강남 스시
강남스시
강남에 있는 스시
오마카새
성수카
띄어쓰기를 빼먹고, 오타를 내고, 문장처럼 검색하기도 합니다.
그래도 우리는 검색창이 알아서 비슷한 결과를 찾아주길 기대합니다.
그래서 검색 기능이 조금만 복잡해지면 결국 별도 검색엔진을 보게 됩니다.
DB 검색만으로는 아쉬운 순간이 옵니다
단순히 이름에 강남이 포함됐는지 찾는 정도라면 SQL의 LIKE로 충분합니다.
문제는 그다음입니다.
강남스시를 검색해도강남 스시가 나와야 하고오마카새라고 쳐도오마카세를 찾아주면 좋고성수카까지만 입력해도 관련 결과가 바로 나오면 좋습니다
여기에 자동완성, 오타 허용, 동의어, 필터, 지역 검색, 검색 결과 순위까지 들어갑니다.
이쯤 되면 DB만으로 처리하는 게 점점 귀찮아집니다.
검색엔진을 찾으면 OpenSearch가 먼저 보입니다
Elasticsearch나 OpenSearch는 워낙 유명합니다.
한국어 검색을 찾아봐도 자주 등장합니다.
OpenSearch에 Nori 형태소 분석기를 붙이면 한국어 검색도 꽤 정교하게 만들 수 있습니다.
기능만 보면 부족할 게 별로 없습니다.
그런데 실제로 로컬에 띄워보면 체감되는 게 하나 있습니다.
생각보다 꽤 무겁습니다.
거의 아무 데이터도 넣지 않은 상태에서 OpenSearch가 약 760MB의 메모리를 사용하고 있었습니다.
검색할 데이터도 거의 없는데 검색엔진 혼자 꽤 많은 메모리를 먹고 있었습니다.
이유는 단순합니다.
OpenSearch는 JVM 위에서 동작하고, 여러 검색 기능과 플러그인도 함께 올라옵니다.
대규모 검색이나 로그 분석을 한다면 충분히 감수할 수 있는 비용입니다.
그런데 이름, 주소, 업종 정도를 검색하는 서비스라면 조금 다른 질문이 생깁니다.
이 정도 검색에 정말 이만한 엔진이 필요한가?
후보를 세 가지로 줄였습니다
| 방식 | 장점 | 아쉬운 점 |
|---|---|---|
| OpenSearch | 형태소 분석, 동의어, 랭킹 튜닝, 대규모 분산 검색 | 무겁고 설정할 게 많음 |
| Typesense | 오타 허용, 자동완성, 필터, 패싯, 지역 검색을 비교적 간단하게 제공 | 한국어 형태소 분석기는 아님 |
| PostgreSQL + pg_trgm | 별도 서비스가 필요 없고 부분 일치, 유사도 검색 가능 | 검색 랭킹과 오타 대응은 전문 검색엔진보다 단순함 |
문서만 읽어서는 결론이 잘 안 났습니다.
그래서 그냥 직접 돌려보기로 했습니다.
한국어 데이터 5천 건을 넣어봤습니다
실제 서비스에서 나올 법한 한국어 매장 데이터를 약 5,000개 만들었습니다.
그리고 세 방식에 같은 검색어를 넣었습니다.
정상적인 검색어만 넣으면 큰 의미가 없어서 일부러 사람이 실제로 검색할 법하게 만들었습니다.
| 검색어 | 의도 |
|---|---|
강남스시하루 |
띄어쓰기 제거 |
오마카새 |
오타 |
강남에 있는 스시 하루 |
문장형 검색 |
성수카 |
입력 중인 접두어 검색 |
이런 식으로 총 12개 검색어를 만들고 원하는 결과가 몇 위에 나오는지 확인했습니다.
결과는 생각보다 의외였습니다
원하는 결과가 1위로 나온 횟수를 비교했습니다.
| 방식 | 12개 중 1위 |
|---|---|
| OpenSearch 기본 구성 | 2개 |
| PostgreSQL + pg_trgm | 4개 |
| Typesense | 10개 |
| Typesense 필드 보강 후 | 11개 |
처음에는 조금 의외였습니다.
OpenSearch가 훨씬 잘 나올 거라고 생각했기 때문입니다.
그런데 이유를 보면 이해가 됩니다.
OpenSearch 자체가 검색을 못하는 게 아닙니다.
기본 구성으로 너무 대충 쓰고 있었던 겁니다.
Nori도 없고, 한국어에 맞춘 분석기나 랭킹 튜닝도 하지 않았습니다.
좋은 엔진을 가져다 놓고 장점은 거의 쓰지 않은 셈입니다.
반대로 Typesense는 별다른 튜닝 없이도 오타와 짧은 검색어에서 꽤 괜찮은 결과를 보여줬습니다.
띄어쓰기 문제는 의외로 단순하게 풀렸습니다
한국어에서는 이런 경우가 흔합니다.
저장된 이름은
강남 스시 하루
사용자는
강남스시하루
라고 입력합니다.
Typesense도 처음부터 이걸 완벽하게 처리한 건 아니었습니다.
그래서 검색용 필드를 하나 추가했습니다.
- 원본 필드:
강남 스시 하루 - 검색 보조 필드:
강남스시하루
이렇게 넣으니 붙여 쓴 검색에서도 원하는 결과가 1위로 올라왔습니다.
복잡한 형태소 분석을 붙인 게 아닙니다.
데이터에 맞게 필드 하나를 추가했을 뿐입니다.
이 부분이 꽤 인상적이었습니다.
5만 건까지 늘려봤습니다
5천 건에서 끝내기에는 조금 아쉬워서 5만 건까지 늘렸습니다.
테스트 환경에서 Typesense 응답시간은 대략 이 정도였습니다.
| 항목 | 결과 |
|---|---|
| p50 응답시간 | 약 4.7ms |
| p95 응답시간 | 약 5.7ms |
| 메모리 사용량 | 약 208MB |
비교 대상이었던 OpenSearch는 데이터가 거의 없는 상태에서도 약 760MB를 사용하고 있었습니다.
물론 이 숫자만 보고 Typesense가 무조건 OpenSearch보다 빠르고 가볍다고 말할 수는 없습니다.
OpenSearch는 JVM 설정, 인덱스 구조, 분석기 설정 등 튜닝할 부분이 많고 해결할 수 있는 문제의 범위도 훨씬 넓습니다.
이번 비교의 목적은 최고의 검색엔진을 찾는 게 아니었습니다.
작은 서비스에서 한국어 이름, 주소, 업종 같은 데이터를 검색할 때 뭐가 더 잘 맞는가.
그걸 보고 싶었습니다.
pg_trgm도 생각보다 괜찮았습니다
PostgreSQL의 pg_trgm도 꽤 괜찮았습니다.
무엇보다 별도 서비스가 필요 없습니다.
이미 PostgreSQL을 사용하고 있다면 그대로 붙일 수 있습니다.
부분 일치는 잘했고 속도도 충분히 빨랐습니다.
다만 이번 테스트에서는 오타 대응과 검색 결과 순위에서 Typesense가 더 좋았습니다.
그래서 개인적으로는 이런 구성이 꽤 마음에 들었습니다.
| 역할 | 방식 |
|---|---|
| 기본 검색 | Typesense |
| 검색엔진 장애 시 | PostgreSQL + pg_trgm |
검색엔진이 죽었다고 서비스 검색까지 같이 죽을 필요는 없습니다.
원본 데이터는 PostgreSQL에 두고, 검색 인덱스는 언제든 다시 만들 수 있는 구조로 두는 게 오히려 마음이 편합니다.
OpenSearch가 나쁘다는 얘기는 아닙니다
오히려 검색 요구사항이 복잡해지면 OpenSearch가 훨씬 강력합니다.
- 한국어 형태소 분석이 중요하고
- 긴 문서를 검색해야 하고
- 동의어 사전을 운영해야 하고
- 검색 랭킹을 세밀하게 조정해야 하고
- 대규모 분산 검색이 필요하다면
OpenSearch를 다시 볼 이유가 충분합니다.
이번에 검색한 건 매장 이름이나 주소처럼 비교적 짧은 데이터였습니다.
이 조건에서는 OpenSearch의 강력한 기능 대부분을 쓰지 않았습니다.
그런데 메모리와 운영 비용은 그대로 들고 있었습니다.
그럴 이유가 없다고 판단했습니다.
결국 직접 넣어보는 게 제일 빠릅니다
검색이라고 하면 자연스럽게 Elasticsearch나 OpenSearch부터 떠올리게 됩니다.
유명하고 검증된 기술이니까요.
그런데 이번에 직접 비교해보니 다시 느꼈습니다.
가장 강력한 기술이 항상 가장 좋은 선택은 아닙니다.
내 데이터가 무엇인지, 검색량이 얼마나 되는지, 사람들이 실제로 어떤 검색어를 넣는지, 어디까지 검색 품질이 필요한지가 더 중요합니다.
특히 검색은 벤치마크만 봐서는 잘 모릅니다.
한국어 데이터를 직접 넣고, 오타도 내보고, 띄어쓰기도 빼보고, 이상한 문장도 넣어봐야 합니다.
이번에는 그렇게 해봤고 결국 OpenSearch를 빼고 Typesense 쪽으로 방향을 잡았습니다.
성능을 올리려고 뭔가를 더 추가한 게 아닙니다.
오히려 하나를 걷어냈습니다.
더 좋은 기술을 찾는 것보다, 지금 필요 없는 기술을 빼는 게 더 좋은 선택일 때도 있습니다.