JavaScript로 오프라인-퍼스트 시맨틱 검색 엔진을 만들었습니다

발행: (2025년 12월 29일 오후 03:57 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

Introduction

검색은 겉보기와 달리 어렵습니다. 대부분의 JavaScript 검색 라이브러리는 키워드나 퍼지 매칭에 머물고, 대부분의 의미 기반 검색 솔루션은 외부 API, 벡터 데이터베이스, 혹은 호스팅 서비스를 전제로 합니다. 저는 다음과 같은 것이 필요했습니다:

  • 완전히 로컬에서 실행
  • Node.js 혹은 브라우저에서 동작
  • 텍스트뿐 아니라 의미를 이해
  • 새로운 인프라를 구축할 필요 없음

이 때문에 저는 Simile Search—오프라인‑우선 의미 + 퍼지 검색 엔진을 JavaScript로 만들었습니다.

Core Techniques

Simile은 단일 스코어링 방식에 의존하지 않고 여러 기술을 결합합니다:

  • Transformer‑based embeddings (transformers.js 사용) 로 의미를 포착합니다. 따라서 “phone charger” → “USB‑C cable” 같은 쿼리도 키워드가 겹치지 않아도 동작합니다.
  • HNSW (Hierarchical Navigable Small World) 인덱싱 으로 근사 최근접 이웃 검색을 수행해, 서브리니어 검색 시간, 카탈로그가 커져도 예측 가능한 성능, 인터랙티브 검색에 적합한 지연 시간을 제공합니다.
  • Vector quantization 으로 메모리 사용량을 줄이면서도 유사도 품질을 유지합니다. 이는 Node.js 내부에서 실행하거나 대규모 카탈로그를 임베딩하거나 모든 데이터를 메모리에 유지할 때 중요합니다.

Performance Optimizations

임베딩은 의미 기반 검색에서 가장 느린 단계입니다. Simile은 다음을 통해 중복 작업을 피합니다:

  • 이전에 본 텍스트에 대한 벡터를 캐시합니다.
  • 전체 스냅샷 저장/로드를 지원해 재임베딩 없이 즉시 복원합니다.

Scoring Blend

의미 유사도만으로는 충분하지 않습니다. Simile은 다음을 혼합합니다:

  • Fuzzy matching (오타, 부분 입력)
  • Exact keyword boosting (정밀도)
  • Normalized scoring 으로 어느 한 방법이 과도하게 지배하지 않도록 함

가중치는 도메인에 따라 조정할 수 있습니다.

Structured Data Support

데이터를 수동으로 평탄화하는 대신, Simile은 중첩 경로를 직접 검색할 수 있습니다. 예시:

  • metadata.author.firstName
  • metadata.tags
  • items[0].name

이를 통해 실제 제품 카탈로그와 구조화된 데이터를 실용적으로 검색할 수 있습니다.

Ideal Use Cases

Simile이 가장 잘 맞는 경우:

  • 제품 및 재고 카탈로그
  • 내부 도구 및 대시보드
  • 지식 베이스
  • 자동완성 / 타입어헤드 검색
  • 프라이버시‑우선 또는 오프라인‑가능 앱
  • 별도 검색 인프라 없이 NestJS 백엔드

MeiliSearch, Elastic, 대형 벡터 데이터베이스를 대체하려는 것이 아니라, 의미가 중요하고 인프라를 단순하게 유지하고 싶은 중소 규모 데이터셋을 목표로 합니다.

Why Simile Exists

다음과 같은 프로젝트들을 보면서 느꼈습니다:

  • 전체 검색 엔진은 과도한 요구사항이었다.
  • 인덱스를 저장하기 위해 별도의 데이터베이스가 필요했다.
  • 퍼지 검색만으로는 충분하지 않았다.
  • 의미 기반 검색을 위해서는 설정이 너무 복잡했다.

Simile은 이러한 격차를 메우기 위한 시도입니다.

Installation & Source

  • npm:
  • GitHub:
Back to Blog

관련 글

더 보기 »