# 작동하는 간단한 검색 엔진 만들기

> Clean Markdown view of GeekNews topic #24438. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24438](https://news.hada.io/topic?id=24438)
- GeekNews Markdown: [https://news.hada.io/topic/24438.md](https://news.hada.io/topic/24438.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-18T11:33:24+09:00
- Updated: 2025-11-18T11:33:24+09:00
- Original source: [karboosx.net](https://karboosx.net/post/4eZxhBon/building-a-simple-search-engine-that-actually-works)
- Points: 9
- Comments: 1

## Summary

복잡한 **검색 SaaS 의존성** 없이, 기존 **데이터베이스 위에서 직접 동작하는 검색 엔진 구조**를 설계한 사례입니다. 핵심은 텍스트를 **Word·Prefix·N-Gram 토크나이저**로 분해해 저장하고, 동일한 방식으로 쿼리를 처리해 **가중치 기반 스코어링**으로 관련도를 계산하는 점입니다. 모든 로직이 **SQL로 투명하게 구현**되어 있어 토크나이저 추가나 가중치 조정이 자유롭고, 디버깅도 직관적입니다. “검색은 결국 데이터와 수학의 문제”라는 사실을 다시 느끼게 하는, 실용적이면서도 개발자다운 접근입니다.

## Topic Body

- 기존 데이터베이스를 활용해 **외부 서비스 없이 동작하는 검색 엔진 구조**를 구현, 토큰화·가중치·스코어링을 중심으로 구성  
- 핵심 아이디어는 **모든 텍스트를 토큰화 후 저장하고**, 검색 시 동일한 방식으로 토큰을 매칭해 관련도를 계산하는 방식  
- **Word, Prefix, N-Gram 토크나이저**를 조합해 정확 일치·부분 일치·오타 대응을 모두 처리하며, 각 토크나이저는 고유한 가중치를 가짐  
- **가중치 시스템과 SQL 기반 스코어링 알고리듬**을 통해 문서 길이, 토큰 다양성, 평균 품질 등을 종합 평가  
- **확장성과 투명성**이 높아, 새로운 토크나이저나 문서 타입 추가, 가중치 조정, 스코어링 수정이 자유로운 구조  

---

### 직접 검색 엔진을 만드는 이유
- Elasticsearch나 Algolia 같은 외부 서비스는 강력하지만 **복잡한 API 학습과 인프라 관리 부담**이 존재  
- 단순히 **기존 데이터베이스와 통합되어 작동하고, 디버깅이 쉬운 검색 기능**이 필요할 때 직접 구축이 유용  
- 목표는 **외부 의존성 없이 관련성 높은 결과를 반환하는 단순한 검색 엔진**  

### 핵심 개념: 토큰화와 매칭
- 기본 원리는 **모든 텍스트를 토큰화(tokenize)하여 저장하고**, 검색 시 동일한 방식으로 토큰을 생성해 매칭  
- **인덱싱 단계**에서 콘텐츠를 토큰 단위로 분리하고 가중치와 함께 저장  
- **검색 단계**에서는 쿼리를 동일하게 토큰화하여 일치하는 토큰을 찾고 점수를 계산  
- **스코어링 단계**에서 저장된 가중치를 활용해 관련도 점수를 산출  

### 데이터베이스 스키마 설계
- 두 개의 테이블 사용: `index_tokens`와 `index_entries`  
  - `index_tokens`: 고유 토큰과 토크나이저별 가중치 저장  
  - `index_entries`: 토큰과 문서를 연결하며, 필드·문서·토크나이저 가중치를 반영한 최종 점수 저장  
- 최종 가중치 계산식:  
  `field_weight × tokenizer_weight × ceil(sqrt(token_length))`  
- 인덱스는 문서 조회, 토큰 조회, 필드별 쿼리, 가중치 필터링을 위해 설정  

### 토큰화 시스템
- **WordTokenizer**: 단어 단위 분리, 짧은 단어 제거, 정확 일치용 (가중치 20)  
- **PrefixTokenizer**: 단어 접두사 생성, 자동완성 및 부분 일치용 (가중치 5)  
- **NGramsTokenizer**: 고정 길이 문자 조합 생성, 오타 및 부분 일치 대응 (가중치 1)  
- 모든 토크나이저는 **소문자 변환, 특수문자 제거, 공백 정규화**를 공통 수행  

### 가중치 시스템
- **필드 가중치**: 제목·본문·키워드 등 중요도 반영  
- **토크나이저 가중치**: Word > Prefix > N-Gram 순  
- **문서 가중치**: 위 두 요소와 토큰 길이를 결합해 계산  
- `ceil(sqrt())` 함수를 사용해 긴 토큰의 영향력을 완화하며, 필요 시 로그나 선형 함수로 조정 가능  

### 인덱싱 서비스
- `IndexableDocumentInterface`를 구현한 문서만 인덱싱 가능  
- 문서 생성·수정 시 이벤트 리스너나 명령어(`app:index-document`, `app:reindex-documents`)로 인덱싱 수행  
- 절차:
  - 기존 인덱스 제거 후 새 토큰 생성  
  - 각 필드에 대해 모든 토크나이저 실행  
  - 토큰 존재 여부 확인 후 생성(`findOrCreateToken`)  
  - 계산된 가중치로 `index_entries`에 **배치 삽입(batch insert)**  
- 중복 방지, 성능 향상, 업데이트 대응 구조  

### 검색 서비스
- 쿼리를 동일한 토크나이저로 처리해 **인덱싱과 동일한 토큰 세트** 확보  
- 토큰 중복 제거 후 길이순 정렬(긴 토큰 우선), 최대 300개로 제한  
- SQL 쿼리를 통해 토큰과 문서를 조인하고, **관련도 점수 계산 및 정렬**  
- 결과는 `SearchResult(documentId, score)` 형태로 반환  

### 스코어링 알고리듬
- 기본 점수: `SUM(sd.weight)`  
- **토큰 다양성 보정**: `LOG(1 + COUNT(DISTINCT token_id))`  
- **평균 가중치 보정**: `LOG(1 + AVG(weight))`  
- **문서 길이 패널티**: `1 / (1 + LOG(1 + token_count))`  
- **정규화(normalization)** : 최대 점수로 나누어 0~1 범위로 조정  
- 최소 토큰 가중치 필터(`st2.weight >= ?`)를 통해 **의미 없는 저가중치 일치 제거**  

### 결과 처리
- 검색 결과는 문서 ID와 점수로 반환되며, 저장소(repository)를 통해 실제 문서로 변환  
- `FIELD()` 함수를 사용해 **검색 결과 순서를 유지한 채 문서 조회**  

### 시스템 확장성
- 새로운 토크나이저는 `TokenizerInterface` 구현으로 추가 가능  
- 새로운 문서 타입은 `IndexableDocumentInterface` 구현으로 등록  
- 가중치나 스코어링 로직은 **SQL 수정만으로 조정 가능**  

### 결론
- 이 구조는 **단순하지만 실제로 작동하는 검색 엔진**으로, 외부 인프라 없이도 충분한 성능 제공  
- **명확한 로직, 완전한 제어, 쉬운 디버깅**이 장점  
- 복잡한 시스템보다 **직접 이해하고 제어 가능한 코드**가 더 가치 있다는 점을 강조

## Comments



### Comment 46474

- Author: neo
- Created: 2025-11-18T11:33:25+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45950720)   
- 검색의 기본 아이디어는 단순하고 흥미로운 문제 영역임  
  하지만 **대량의 데이터**를 다루는 것과 **모호한 쿼리**를 처리하는 것이 진짜 어려움   
  DBMS 기반 접근은 작은 웹사이트 수준에서는 괜찮지만, 영어 위키피디아 규모에서는 금방 한계에 부딪힘  
  입문용으로는 [SeIRP e-book](https://ciir.cs.umass.edu/irbook/)이 좋은 무료 자료  
  - 대량 데이터는 당연히 어렵지만, 모호한 쿼리를 다루는 건 “가장 관련 있는 결과를 어떻게 정할 것인가”의 하위 문제라고 생각함  
    **정답이 명확하지 않다는 점**이 특히 까다로움  
    Google은 광고를 ‘가장 관련 있는 결과’로 보여주기도 해서, [Marginalia Search](https://marginalia-search.com)는 좋은 대조 사례임  
    혹시 [TREC 논문들](https://trec.nist.gov/)을 참고해본 적 있는지 궁금함  
  - 요즘은 오히려 **SEO 스팸 회피**가 더 큰 문제라고 생각함  
    검색 엔진은 광고 수익을 노리는 **적대적 플레이어**들과 끊임없이 싸워야 함  
    품질 지표를 계속 바꿔가며 그들이 역이용하지 못하게 하는 **끝없는 고양이와 쥐의 게임**이 됨  
  - SQLite로 단일 서버(약 천 달러 수준)에서 텍스트 중심 비즈니스 프로세스를 돌린다면, 실질적으로 다룰 수 있는 **문서 저장소의 규모**가 어느 정도인지 궁금함  
    1쿼리당 5초, 분당 12쿼리 정도의 속도를 기준으로 어느 정도의 코퍼스를 검색할 수 있을지 알고 싶음  
  - [Marginalia Search](https://marginalia-search.com)를 정말 좋아함  
  - 검색의 어려움은 단순히 데이터 크기뿐 아니라, **어떤 결과를 반환할지 결정하는 문제**라고 생각함  
    예를 들어 Gilligan’s Island 위키 문서와 팬 블로그 중 어느 쪽이 더 “좋은” 결과인지 판단하기 어려움  
    여기에 **랭크 조작**이나 **키워드 스터핑**까지 더해지면, 확장성 문제보다 훨씬 복잡한 도전이 됨  
  
- 검색은 정말 어려운 일임  
  Apple, Microsoft, OpenAI 같은 자원과 기술력이 넘치는 회사조차 **검색 기능 품질이 낮음**  
  이는 단순한 기술 문제가 아님  
  - 대부분의 회사가 검색을 잘 구현하지 못하는 이유는, **기업 문화와 개발 방식**이 검색 개발과 충돌하기 때문임  
    검색 품질을 높이려면 **랭킹 파라미터를 세밀하게 조정**해야 하는데, 이런 일은 스프린트나 Jira 같은 관리 체계로는 계획하기 어려움  
    결국 개발자에게 **신뢰와 자율성**이 필요한 영역임  
  - 하지만 어떤 회사들은 단순히 **검색이 우선순위가 아니기 때문**에 품질이 낮은 것  
    AI 모델에는 수십억을 투자하지만, 웹앱이나 검색은 부차적이라서 그런 결과가 나오는 것임  
  
- 10년 전쯤 **검색 엔진 설계로 박사과정을 하던 동료**와 함께 일한 적이 있음  
  그는 검색과 데이터베이스 통합에 대해 매우 열정적으로 이야기했고, 덕분에 많은 걸 배웠음  
  언젠가 Apache **Solr**와 **Lucene**의 내부를 깊이 파보고 싶음  
  - 나도 내 분야 이야기를 몇 시간이고 할 수 있을 정도로 좋아하지만, **대형 시스템의 세부 구현**에 관심 있는 사람은 많지 않음  
  
- 예전에는 오픈소스 검색 솔루션이 없어서 직접 만들어야 했음  
  그 경험으로 얻은 교훈은 “**직접 검색 엔진을 만들지 말라**”는 것임  
  수년간 수많은 인력이 이 문제에 매달려왔고, 직접 만들면 **끝없는 유지보수 지옥**에 빠짐  
  “오타 교정 기능 추가해달라”, “내년엔 분류 체계도 넣자” 같은 요구가 이어지면 끝남  
  
- 예전에 **Virginia University의 David Evans 교수**가 진행한 검색 엔진 구축 강의를 정말 즐겼음  
  “고전적인 검색 엔진”을 직접 만들어보는 건 매우 재미있는 프로젝트였음  
  [강의 링크](https://www.cs.virginia.edu/~evans/courses/cs101/)와 [YouTube 재생목록](https://www.youtube.com/watch?v=9nkR2LLPiYo&list=PLAwxTw4SYaPmjFQ2w9j05WDX8Jtg5RXWW) 참고 가능  
  - 나도 그 강의를 들었는데, **초보 프로그래머에게도 흥미롭고 밀도 높은 수업**이었음  
  
- 내가 자주 쓰는 검색 엔진들은 **2~3글자 약어나 단어를 무시**하는 게 불만임  
  “mp3”나 “PHP” 같은 짧은 단어를 검색할 때 제거해버리면 정말 불편함  
  
- Toby Segaran의 **Programming Collective Intelligence**를 읽고 **검색, 추천, 분류기** 등 다양한 아이디어에 영감을 받았음  
  - 나도 그 책을 좋아했지만, 저자가 나중에 유튜브에서 “이제는 구식이니 쓰지 말라”고 말한 걸 봤음  
  - 정말 좋은 책이었는데, **2025년에 해당하는 최신판**이 있다면 궁금함  
  
- 흥미로운 글이었음  
  인기 검색 엔진들이 사용하는 **토크나이저 최적화 수준**이 얼마나 높은지 궁금해짐  
  
- 이 시스템이 얼마나 **확장성 있게 작동할지** 궁금함  
  Elasticsearch는 권장 스케일을 넘어도 꽤 인상적인 성능을 보임  
  
- 간단한 텍스트 검색 엔진은 만들기 어렵지 않음  
  하지만 **좋은 검색 엔진**을 만드는 건 전혀 다른 이야기임  
  단순히 BM25 같은 알고리즘을 구현하는 수준으로는 부족함  
  내가 컨설팅한 회사들 대부분이 자체 솔루션을 쓰다가 결국 **Elasticsearch나 Opensearch**로 옮김  
  자체 구현은 처음엔 단순하지만, 시간이 지나면 **랭킹 문제와 성능 저하**로 복잡해짐  
  “느리다”, “엉뚱한 결과가 나온다” 같은 증상이 반복됨  
  Elasticsearch는 이미 **10년 전부터 이런 문제를 해결**해왔고, 지금은 훨씬 더 발전함  
  “설정이 어렵다”는 말도 있지만, 요즘은 대부분 **자동 구성**되고, 관리형 서비스도 많음  
  Postgres보다 오히려 다루기 쉬움  
  결국 중요한 건 **인덱스 매핑 최적화**임  
  “그런 고급 기능은 필요 없다”고 말하는 사람도 있지만, 실제로는 **검색 품질이 비즈니스 생존에 직결**됨  
  제대로 된 검색을 원한다면 결국 이런 복잡함을 감수해야 함  
  - 나도 Elasticsearch를 기본으로 쓰고 있음  
    최근 HN에서 자주 언급되는 [SeekStorm](https://github.com/SeekStorm/SeekStorm) 같은 **신흥 대안**도 흥미로워 보이지만, 실제 프로덕션 사례는 아직 못 봤음  
  - “불필요한 기능은 없다”는 말에 공감함  
    특히 **dynamic mapping을 끄고 불필요한 필드 인덱싱을 막는 팁**이 유용했음  
  - **ManticoreSearch**에 대해서는 어떻게 생각하는지 궁금함  
    Lucene보다 오래된 프로젝트로 알고 있음
