fos-blog/study
01 / 홈02 / 카테고리03 / 시리즈
01 / 홈02 / 카테고리03 / 시리즈

카테고리

  • AI 페이지로 이동
    • RAG 페이지로 이동
    • agent 페이지로 이동
    • langgraph 페이지로 이동
    • 사람용 CLI와 AI 에이전트용 CLI는 설계가 다르다
    • agents.md
    • BMAD Method — AI 에이전트로 애자일 개발하는 방법론
    • Claude Code 메모리: CLAUDE.md와 .claude/rules를 규칙으로 쓰는 법
    • Claude Code의 Skill 시스템 - 개발자를 위한 AI 자동화의 새로운 차원
    • Claude Code를 5주 더 쓴 결과 — 스킬·CLAUDE.md를 키워가는 방식
    • Claude Code를 11일 동안 쓴 결과 — 데이터로 본 나의 사용 패턴
    • Claude Code 멀티 에이전트 — Teams
    • AI 에이전트와 디자인의 새 컨벤션 — DESIGN.md, Google Stitch, Claude Design
    • Docling — IBM Research 의 문서 파싱 toolkit 상세 정리
    • 하네스 엔지니어링 실전 — 4인 에이전트 팀으로 코딩 파이프라인 구축하기
    • 하네스 엔지니어링 — 오래 실행되는 AI 에이전트를 위한 설계
    • 멀티모달 LLM (Multimodal Large Language Model)
    • AI 에이전트와 함께 MVP 만들기 — dooray-cli 사례
    • OpenClaw는 context와 memory를 어떻게 관리하나 — 나만의 에이전트를 구성하는 법
    • OpenClaw vs Hermes Agent — 갈아탈까 고민하며 정리한 비교
    • 스킬 문서를 신경망처럼 학습시킨다 — Microsoft SkillOpt 분석
  • ai 페이지로 이동
    • agent 페이지로 이동
    • [초안] AI 제품 백엔드 안정성 — 지연·비용·권한·관측·도구 실패·폴백/재시도/사람 에스컬레이션
    • [초안] LLM 평가 프레임워크: 골든셋, 회귀 테스트, LLM-as-a-judge, 사람 피드백 루프
  • algorithm 페이지로 이동
    • live-coding 페이지로 이동
    • 분산 계산을 위한 알고리즘
  • apartment 페이지로 이동
    • 구리 럭키아파트 24평 인테리어 레퍼런스 모음
  • architecture 페이지로 이동
    • [초안] 시니어 백엔드를 위한 API 설계 실전 스터디 팩 — REST · 멱등성 · 페이지네이션 · 버전 전략
    • [초안] API Versioning과 Backward Compatibility: 시니어 백엔드 관점 정리
    • 캐시 설계 전략 총정리
    • [초안] 커머스 Spring 서비스에 Clean/Hexagonal Architecture를 실용적으로 적용하기
    • [초안] 커머스 도메인 모델링: 주문·재고·노출의 세 축을 분리해서 설계하기
    • 커머스 주문 상태와 데이터 정합성 기본기
    • [초안] 쿠폰/프로모션 동시성과 정합성 기본기 — 선착순·중복 사용 방지·발급/사용/복구
    • [초안] DDD와 도메인 모델링: 시니어 백엔드 관점의 전술/전략 패턴 실전 가이드
    • [초안] Decorator & Chain of Responsibility — 행동을 체인으로 조립하는 두 가지 방식
    • 디자인 패턴
    • [초안] 분산 아키텍처 완전 정복: Java 백엔드 시니어 인터뷰 대비 실전 가이드
    • [초안] 분산 트랜잭션과 Outbox 패턴 — 왜 2PC를 피하고 어떻게 대신할 것인가
    • 분산 트랜잭션
    • [초안] e-Commerce 주문·결제 도메인 모델링: 상태머신, 멱등성, Outbox/Saga 실전 정리
    • [초안] Event Sourcing과 CQRS — 상태가 아니라 변화를 저장한다는 발상
    • [초안] F&B 쿠폰·프로모션·멤버십·포인트 설계
    • [초안] F&B · e-Commerce 디지털 채널 도메인 한 장 정리
    • [초안] F&B 주문/매장/픽업 상태머신 설계
    • [초안] F&B 이커머스 결제·환불·정산 운영 가이드
    • [초안] Hexagonal / Clean Architecture를 Spring 백엔드에 적용하기
    • [초안] 대규모 커머스 트래픽 처리 패턴 — 대규모 회원과 메가 프로모션을 버티는 설계
    • [초안] 레거시 JSP/jQuery 화면과 신규 API가 공존하는 백엔드 운영 전략
    • [초안] MSA 서비스 간 통신: Redis [Cache-Aside](../database/redis/cache-aside.md) × Kafka 이벤트 하이브리드 설계
    • [초안] Observability 입문: 시니어 백엔드가 장애를 탐지하고 대응하는 방식
    • [초안] Outbox / Inbox Pattern 심화 — 분산 메시징의 정합성 문제를 DB 트랜잭션으로 풀어내기
    • [초안] 결제 도메인 멱등성과 트랜잭션 재시도 기본기
    • [초안] 시니어 백엔드를 위한 Resilience 패턴 실전 가이드 — Timeout, Retry, Circuit Breaker, Bulkhead, Backpressure
    • [초안] REST API 버저닝과 모바일 앱 하위 호환성 — 디지털 채널 백엔드 관점
    • [초안] Spring Batch vs Event-Driven — 같은 비동기처럼 보이지만 전혀 다른 두 패러다임
    • [초안] Strategy Pattern — 분기문을 없애는 설계, 시니어 백엔드 인터뷰 핵심 패턴
    • [초안] 시니어 백엔드를 위한 시스템 설계 입문 스터디 팩
    • [초안] 템플릿 메서드 패턴 - 백엔드 처리 골격을 강제하는 가장 오래되고 가장 위험한 패턴
    • [초안] 대규모 트래픽 중 무중단 마이그레이션 — Feature Flag + Shadow Mode 실전
  • database 페이지로 이동
    • milvus 페이지로 이동
    • mysql 페이지로 이동
    • opensearch 페이지로 이동
    • qdrant 페이지로 이동
    • redis 페이지로 이동
    • vespa 페이지로 이동
    • 김영한의-실전-데이터베이스-설계 페이지로 이동
    • [초안] DB Connection Pool Saturation과 Thread Pool 격리
    • 커넥션 풀 크기는 얼마나 조정해야 할까?
    • 인덱스 - DB 성능 최적화의 핵심
    • [초안] JPA N+1과 커머스 조회 모델: 주문/메뉴/쿠폰 도메인에서 살아남기
    • [초안] MyBatis 기본기 — XML Mapper, resultMap, 동적 SQL, 운영 패턴 정리
    • [초안] MyBatis와 JPA/Hibernate 트레이드오프 — 레거시 백엔드를 다루는 시니어 관점
    • 벡터 DB 5종, 아키텍처는 어떻게 다른가
    • 벡터 DB 어떻게 고를까 — OpenSearch · Milvus · Qdrant · Vespa · pgvector 비교
    • 벡터 DB를 실제로 도입한 사례 — 빅테크 프로덕션
    • 역정규화 (Denormalization)
    • 데이터 베이스 정규화
  • devops 페이지로 이동
    • docker 페이지로 이동
    • k8s 페이지로 이동
    • k8s-in-action 페이지로 이동
    • observability 페이지로 이동
    • [초안] 커머스/F&B 채널 장애 첫 5분과 관측성 기본기
    • [초안] 운영 데이터 정합성 장애 대응 — 결제 취소 누락과 중복 적재 런북
    • Envoy Proxy
    • [초안] F&B / e-Commerce 운영 장애 대응과 모니터링 — 백엔드 관점 정리
    • Graceful Shutdown
    • [초안] 시니어 백엔드를 위한 SLO와 Error Budget 기반 장애 대응
  • http 페이지로 이동
    • HTTP Connection Pool
    • HTTPS는 어떻게 안전한가 — TLS, 인증서, 그리고 termination
  • interview 페이지로 이동
    • [초안] AI 서비스 팀 경험 기반 시니어 백엔드 면접 질문 뱅크 — Spring Batch RAG / gRPC graceful shutdown / 전략 패턴 / 12일 AI 웹툰 MVP
    • Observability — 면접 답변 프레임
    • [초안] 시니어 Java 백엔드 면접 마스터 플레이북 — 김병태
    • [초안] NSC 슬롯팀 경험 기반 질문 은행 — 도메인 모델링·동시성·성능·AI 협업
  • java 페이지로 이동
    • concurrency 페이지로 이동
    • jdbc 페이지로 이동
    • opentelemetry 페이지로 이동
    • spring 페이지로 이동
    • spring-batch 페이지로 이동
    • testing 페이지로 이동
    • 더_자바_코드를_조작하는_다양한_방법 페이지로 이동
    • [초안] Java 동시성 락 정리 — 커머스 메뉴/프로모션 정책 캐시 갱신 관점
    • [초안] JVM 튜닝 실전: 메모리 구조부터 Virtual Threads, GC 튜닝, 프로파일링까지
    • Java의 로깅 환경
    • MDC (Mapped Diagnostic Context)
    • Java StampedLock — 읽기 폭주에도 쓰기가 밀리지 않는 락
    • Virtual Thread와 Project Loom
  • javascript 페이지로 이동
    • typescript 페이지로 이동
    • AbortController
    • Async Iterator와 제너레이터
    • CommonJS와 ECMAScript Modules
    • 제너레이터(Generator)
    • Http Client
    • Node 백엔드 운영 패턴 — Streams 백프레셔, pipe/pipeline, 멱등성 vs 분산 락
    • Node.js
    • npm vs pnpm — 어떤 기준으로 선택했나
    • `setImmediate()`
  • kafka 페이지로 이동
    • [초안] Kafka 기본 개념 — 토픽, 파티션, 오프셋, 복제
    • Kafka를 사용하여 **데이터 정합성**은 어떻게 유지해야 할까?
    • [초안] Kafka 실전 설계: 파티션 전략, 컨슈머 그룹, 전달 보장, 재시도, 순서 보장 트레이드오프
    • 메시지 전송 신뢰성
    • [초안] Spring Kafka 컨슈머 오프셋 커밋과 트랜잭션 정렬: AckMode, manual ack, 멱등 처리
  • linux 페이지로 이동
    • fsync — 리눅스 파일 동기화 시스템 콜
    • tmux — Terminal Multiplexer
  • mlops 페이지로 이동
    • Python CUDA 버전 생태계 — nvidia-smi, nvcc, pip, conda가 다 다른 버전을 말하는 이유
    • GPU 컨테이너의 CUDA 버전 호환성 — nvidia-smi부터 이미지 다이어트까지
    • Kubernetes GPU 노드에서 /run tmpfs가 꽉 차서 Pod가 안 뜰 때
    • GPU·CUDA·MPS 기초 — 자바 백엔드 개발자가 처음 만나는 그림
    • Multi-process GPU 워크로드 — 자바 ThreadPool 사용자가 만나는 모델 차이
    • ML 서비스 성능 분석 워크플로 — 자바 백엔드 트러블슈팅과 다른 점
    • 한 GPU 를 여러 프로세스가 나눠 쓰기 — Time-Slicing 과 MPS
  • network 페이지로 이동
    • Connection reset by peer는 누가 보낸 걸까 — 리버스 프록시 홉마다 TCP 연결은 따로 논다
    • L2(스위치)와 L3(라우터)의 역할 차이
    • L4와 VIP(Virtual IP Address)
    • IP Subnet
  • python 페이지로 이동
    • Python async/await — CompletableFuture·Reactor 와 다른 점, 그리고 blocking I/O 함정
    • Python 의존성 관리 — Java Maven/Gradle 사용자가 만나는 첫 충격
    • FastAPI 기초 — Spring Boot 사용자가 빠르게 익히는 법
    • Java 개발자를 위한 Python 심화 — OOP·데코레이터·컨텍스트 매니저
    • PyTorch 기초 — 텐서, 디바이스, 그리고 모델 로딩이 무거운 이유
    • Java 개발자를 위한 Python 문법 핵심
    • ThreadLocal 에서 contextvars 로 — Python 의 요청 컨텍스트 전파
    • OCR 동작 원리 — Layout · Text · Post-process 3단계
    • Python 서버의 RSS 가 안 줄어드는 이유 — gc.collect 의 한계와 malloc_trim
  • rabbitmq 페이지로 이동
    • [초안] RabbitMQ Basics — 실전 백엔드 관점에서 정리하는 메시지 브로커 기본기
    • [초안] RabbitMQ vs Kafka — 백엔드 메시징 선택 기준과 실전 운영 관점
  • security 페이지로 이동
    • [초안] 시니어 백엔드를 위한 보안 / 인증 스터디 팩 — Spring Security, JWT, OAuth2, OWASP Top 10
    • [초안] Spring Security 6.x OAuth2 + JWT 상용 인증 설계 — Grant 선택, Resource Server, Refresh Rotation, 로그아웃
  • task 페이지로 이동
    • ai-service-team 페이지로 이동
    • nsc-slot 페이지로 이동
    • sb-dev-team 페이지로 이동
    • the-future-company 페이지로 이동
  • testing 페이지로 이동
    • [초안] 시니어 Java 백엔드를 위한 테스트 전략 완전 정리 — 피라미드부터 TestContainers, 마이크로벤치, Contract까지
  • travel 페이지로 이동
    • 오사카 3박 4일 일정표: 우메다 쇼핑, USJ, 난바·도톤보리, 오사카성
  • web 페이지로 이동
    • [초안] HTTP / Cookie / Session / Token 인증 기본기 — 레거시 JSP와 모바일 API가 공존하는 백엔드 관점
FOS-BLOG · FOOTERall systems normal·v0.1 · 2026.04.27·seoul, kr
Ffos-blog/study

개발 학습 기록을 정리하는 블로그입니다. 공부하면서 기록하고, 기록하면서 다시 배웁니다.

visitors
01site
  • Home↗
  • Posts↗
  • Categories↗
  • About↗
02policy
  • 소개/about
  • 개인정보처리방침/privacy
  • 연락처/contact
03categories
  • AI↗
  • Algorithm↗
  • DB↗
  • DevOps↗
  • Java/Spring↗
  • JS/TS↗
  • React↗
  • Next.js↗
  • System↗
04connect
  • GitHub@jon890↗
  • Source repositoryjon890/fos-study↗
  • RSS feed/rss.xml↗
  • Newsletter매주 1 회 · 한 편의 글→
© 2026 FOS Study. All posts MIT-licensed.
built with·Next.js·Tailwind v4·Geist·Pretendard·oklch
fos-blog/AI/HNSW 심화 — 파라미터 튜닝과 구현체별 …
aidb

HNSW 심화 — 파라미터 튜닝과 구현체별 성능 차이

벡터 검색 알고리즘 입문에서 HNSW가 kNN을 실시간에 쓰게 만든 표준 알고리즘이라는 걸 봤다. 이 글은 그 다음 단계다 — 파라미터를 어떻게 튜닝하고, 왜 같은 설정인데 제품마다 성능이 다른가. - HNSW 튜닝은 파라미터 3개로 끝난다 — M(그래프 밀도), efconstruction(빌드 품질), efsearch(검색 품질). 앞 둘은 인덱스에 고정...

2026.07.01·6 min read·1 views

벡터 검색 알고리즘 입문에서 HNSW가 kNN을 실시간에 쓰게 만든 표준 알고리즘이라는 걸 봤다. 이 글은 그 다음 단계다 — 파라미터를 어떻게 튜닝하고, 왜 같은 설정인데 제품마다 성능이 다른가.

먼저 가져갈 결론

  • HNSW 튜닝은 파라미터 3개로 끝난다 — M(그래프 밀도), ef_construction(빌드 품질), ef_search(검색 품질). 앞 둘은 인덱스에 고정되고, ef_search만 질의 시점에 바꿀 수 있다. recall과 속도를 실시간으로 맞바꾸는 유일한 손잡이다.
  • 같은 M/ef를 줘도 구현체마다 recall·QPS가 갈린다. 이건 버그가 아니라 정상이다. 이웃 선택 방식, SIMD 거리계산, 메모리 레이아웃, 필터 처리가 다르기 때문이다.
  • 구현체 간 최대 차별점은 필터링 처리와 메모리 모델이다. 순수 속도보다 이 둘이 제품 선택을 가르는 경우가 많다.
  • 아래 수치는 대부분 벤더·공개 벤치의 "출처 주장"이다. 우리 워크로드로 재검증하기 전에는 단정하지 않는다.

파라미터 3개 심화

세 파라미터는 **빌드 시점(1회) vs 검색 시점(매 쿼리)**으로 성격이 갈린다.

M — 노드당 연결 수 (빌드, 그래프 밀도)

각 노드가 유지하는 양방향 링크 수(최하층은 2M). 그래프가 얼마나 촘촘한지를 정한다.

  • 높을수록 연결이 많아져 지역 최소값(local minima)에 갇힐 확률이 줄어 recall이 오른다.
  • 메모리가 M에 선형 비례해 늘어난다(노드마다 링크를 저장).
  • 그래프가 촘촘해져 빌드가 느려진다.
  • 권장 범위는 8-64, 기본 16. 저차원·저용량이면 8-16, 고차원·고정밀이면 32-64.

ef_construction — 빌드 시 탐색 폭 (빌드, 그래프 품질)

벡터를 삽입할 때 이웃 후보를 몇 개까지 탐색하는지. 그래프 자체의 품질을 정한다.

  • 높을수록 삽입 때 더 좋은 이웃을 찾아, 같은 ef_search에서도 recall이 오른다.
  • 대신 빌드가 느려진다. 검색 속도·메모리에는 거의 영향이 없다(빌드가 끝나면 그래프에 흡수된다).
  • 일정 지점 이상은 수익이 체감된다 — 그래프 품질은 안 오르고 빌드만 느려진다.
  • 권장 범위는 100-500, 프로덕션 시작점 200. 조건은 ef_construction ≥ M.

ef_search — 검색 시 탐색 폭 (매 쿼리, recall-속도 슬라이더)

바닥 레이어에서 유지하는 후보 리스트 크기. 질의마다 바꿀 수 있는 유일한 파라미터다.

  • 높을수록 더 많은 노드를 방문해 recall이 오르고 QPS가 떨어진다.
  • ef_search ≥ k는 필수다. 후보 리스트가 k보다 작으면 top-k를 반환할 수 없다(Milvus는 아예 ef < k 설정을 막는다).
  • 권장은 k보다 넉넉히 — 10(빠름·저recall) → 100(균형) → 500(고recall·느림).

상호작용 — 한 장으로

파라미터시점올리면바꾸려면
M빌드recall↑ 메모리↑ 빌드↑재빌드
ef_construction빌드recall↑ 빌드↑ (검색 무관)재빌드
ef_search매 쿼리recall↑ QPS↓즉시(재빌드 불필요)

M과 ef_construction은 역할이 다르다. M은 "이웃을 몇 개 저장할지"(구조·메모리)이고, ef_construction은 "그 이웃을 얼마나 잘 고를지"(탐색 품질)다. M을 키우면 채울 슬롯이 늘어나므로, 좋은 후보로 채우려면 ef_construction도 함께 올려야 효과가 난다. M만 키우고 ef_construction을 낮추면 슬롯이 부실한 이웃으로 채워져 메모리만 쓰고 recall이 안 오른다.

멘탈모델은 이렇다 — M·ef_construction으로 그래프의 "recall 천장"을 정하고, ef_search로 그 천장 안에서 recall-속도 지점을 고른다. 그래서 여러 제품을 공정하게 비교하려면 재빌드 없이 ef_search만 여러 값으로 훑어(sweep) 같은 recall 지점에서 QPS를 비교한다.

거리 계산 — 코사인 유사도는 사실 내적이다

HNSW가 "가깝다"를 판정하는 건 결국 벡터 간 거리 계산이고, RAG의 표준인 코사인 유사도는 실제로 내적으로 계산된다.

코사인 유사도 공식은 이렇다.

plaintext
cos(θ) = (A · B) / (|A| · |B|)
  • A · B = 내적 = 성분끼리 곱해서 합한 값. 크기와 방향을 모두 반영한다.
  • |A|, |B| = 각 벡터의 크기(L2 norm).
  • 내적을 크기로 나눠 방향(각도)만 남긴 게 코사인이다.

실무에서는 매 검색마다 나눗셈이 비싸서, 저장할 때 모든 벡터를 L2 정규화(크기를 1로)한다. 그러면 |A|=|B|=1이 되어 cos = A·B — 코사인이 그냥 내적으로 단순화된다. OpenSearch space_type=cosinesimil, faiss cosine이 내부적으로 이 방식(정규화 후 inner product)이다.

임베딩 모델이 의미가 비슷한 텍스트를 벡터 공간에서 방향이 비슷하게 배치하도록 학습되기 때문에, 각도(코사인)가 의미 유사도를 대변한다. HNSW는 유사도가 아니라 "거리"로 다루므로 코사인 거리 = 1 − 코사인 유사도로 변환해 쓴다(작을수록 가깝다).

구현체별 성능 차이

같은 M/ef라도 recall·속도가 갈리는 원인은 넷이다.

  • 이웃 선택 휴리스틱 — 단순 최근접 vs 다양성(diverse) 기반 가지치기.
  • 거리계산 SIMD — AVX2/AVX512 지원 여부와 런타임 자동 선택.
  • 메모리 레이아웃 — 인메모리 연속 배열 vs 세그먼트 파일 vs 디스크.
  • 필터·refine 처리 — 필터를 탐색 중에 적용하는지, 결과를 원본 벡터로 재정렬하는지.
구현체특징관점
FAISS IndexHNSWFlat원본 저장(refine 정확), 순수 라이브러리조합·기준용
hnswlibHNSW 원저자 계열, diverse 이웃 휴리스틱ann-benchmarks 순정 기준선
Lucene (OpenSearch)초기엔 단일 레이어, 세그먼트별 그래프이후 계층·SIMD·양자화로 개선 — 현행은 실측 필요
Qdrant (Rust)GC 정지 없음, filterable HNSW(추가 엣지)필터링 강점 주장
pgvectorIVFFlat 대비 2~5배 메모리, pgvectorscale로 개선 주장대규모 열세가 통설
Milvus KnowhereFAISS 통합, SIMD 자동선택, Dual-Pool 필터필터링을 다른 방식으로 해결

특히 눈여겨볼 지점이 둘 있다.

첫째, Lucene HNSW의 역사적 함정이다. 초기 Lucene HNSW는 논문의 계층 구조를 안 따르고 단일 그래프 레이어만 썼다. 그 탓에 같은 데이터셋에서 hnswlib 대비 QPS가 약 9배 낮았다는 벤치가 있다(2021 무렵, 출처 주장). 기본 beamWidth(=ef_construction)가 16으로 너무 낮았던 것도 원인이다. 다만 이후 계층 구조 도입, SIMD(Panama Vector API), 양자화로 크게 개선됐으므로, 현행 OpenSearch를 이 옛 수치로 판단하면 안 된다.

둘째, 필터 처리 방식의 차이다. 메타데이터 필터를 걸면 그래프 탐색이 깨진다 — 필터를 탐색 전에 적용하면 그래프 연결이 끊겨 recall이 급락하고, 탐색 후에 적용하면 필터가 빡셀 때 k개를 못 채운다.

  • Qdrant는 payload 값 기반으로 그래프에 추가 엣지를 넣어 탐색 중 필터를 적용한다(filterable HNSW).
  • Milvus는 Dual-Pool — 필터로 걸러진 노드도 네비게이션용으로만 유지해, 탐색 예산이 필터된 벡터에 잠식되지 않게 한다. 같은 문제를 서로 다르게 푼 것이라, 필터를 많이 쓰는 워크로드에서는 이 설계 차이가 곧 성능 차이가 된다.

ann-benchmarks에서의 위치

ann-benchmarks(erikbern)는 표준 데이터셋에서 recall@k·QPS·빌드시간·메모리를 재는 사실상 표준 도구다.

  • recall-QPS 곡선 최상단은 양자화를 얹은 HNSW 변종(Glass 등)이고, 순정 HNSW 중에서는 hnswlib가 오래 기준선이었다.
  • 주의할 점 — ann-benchmarks는 라이브러리(hnswlib·FAISS·Glass 등)를 비교하지, 완제품 DB(OpenSearch·Qdrant 서버·Milvus 서버·pgvector)의 엔드투엔드 성능을 비교하지 않는다.
  • DB 완제품 비교는 vector-db-benchmark가 쓰이는데, 이건 Qdrant가 주최하므로 결과 해석 시 주최측 편향을 감안해야 한다.

즉 "누가 제일 빠른가"는 라이브러리 벤치와 DB 벤치, 그리고 벤더 자사 벤치가 다 다르게 말한다. 그래서 자체 워크로드 실측이 필요하다.

한계와 함정

  • 필터링과의 충돌 — 위에서 본 대로 HNSW의 가장 큰 실무 함정이다. ACORN·UNIFY 등 최근 연구의 활발한 주제다.
  • 삭제·갱신 — 갱신이 그래프 전반에 연쇄 수정을 일으켜 write amplification이 크다. 삭제·재삽입이 쌓이면 도달 불가 노드가 생겨 recall이 조용히 떨어진다. 통상 일정량 누적 후 재빌드한다 — 실시간 대량 갱신에는 부적합하다.
  • 메모리 상주 요구 — HNSW는 전체 그래프가 RAM에 있다고 가정한다. 메모리가 조금만 부족해 디스크로 스왑되면 성능이 부드럽게 저하되지 않고 절벽처럼 떨어진다. DiskANN·pgvectorscale 같은 디스크 기반 대안이 나온 이유다.
  • 고차원에서의 거동 — 거리계산마다 고차원 벡터를 반복해 읽어 read amplification이 심하다. 여기서 SIMD·양자화가 성능을 좌우한다. 또 그래프가 커질수록 같은 ef_search로는 상대적으로 덜 탐색하게 되므로, 규모에 맞춰 ef_search를 올려야 한다.

정리 — 벤치를 설계한다면

  • 파라미터를 맞추되 이름이 다름을 명시하라 — pgvector ef_search, Milvus ef, Lucene beamWidth, Qdrant hnsw_ef. 같은 개념이라도 제품마다 플래그가 다르다.
  • 같은 M/ef여도 recall이 다르게 나오는 게 정상이다. 그래서 QPS를 그냥 비교하지 말고 ef_search를 sweep해 같은 recall 지점에서 비교한다.
  • 필터링 성능을 반드시 축으로 넣어라 — 순수 벡터 검색 속도만으로는 Qdrant·Milvus의 필터 설계 강점이 드러나지 않는다.
  • 메모리 상주 vs on-disk를 먼저 계산하라 — HNSW는 RAM 상주 전제라, 목표 규모가 인스턴스 메모리에 올라가는지(M에 비례하는 그래프 오버헤드 포함) 확인해야 한다.

이 글의 수치는 공개 벤치·벤더 문서 기반의 "출처 주장"이다. 실제 제품 선택은 자체 워크로드 벤치로 재검증한 뒤 판단한다.

on this page
  • 01먼저 가져갈 결론
  • 02파라미터 3개 심화
  • M — 노드당 연결 수 (빌드, 그래프 밀도)
  • ef_construction — 빌드 시 탐색 폭 (빌드, 그래프 품질)
  • ef_search — 검색 시 탐색 폭 (매 쿼리, recall-속도 슬라이더)
  • 상호작용 — 한 장으로
  • 03거리 계산 — 코사인 유사도는 사실 내적이다
  • 04구현체별 성능 차이
  • 05ann-benchmarks에서의 위치
  • 06한계와 함정
  • 07정리 — 벤치를 설계한다면
tags
#심화

이런 글도

  • 엔터프라이즈 AI Agent 설계 — reasoning, tool, memory, cost를 운영 시스템으로 묶기
    AI Agent를 엔터프라이즈 환경에 올린다는 건 "LLM이 알아서 일하게 한다"가 아니다. 모델의 reasoning 능력, 도구 호출, 메모리, 비용 예산, 권한, 감사 로그를 하나의 운영 시스템으로 묶는 일이다. 이 글은 Chain of Thought부터 MCP, LangGraph, Agent SDK, memory, cost control, risk g...
    🤖 ai
    ai
    2026.06.25
  • 사람용 CLI와 AI 에이전트용 CLI는 설계가 다르다
    예전에는 CLI를 사람만 썼다. 지금은 Claude Code 같은 AI 에이전트가 CLI를 호출해 업무를 자동화한다. 같은 도구라도 "에이전트가 쓰기 좋게" 설계하면 자동화가 훨씬 매끄럽고, 그러지 않으면 자동화가 자주 깨진다. 여러 업무 자동화 CLI를 직접 만들어 에이전트로 호출해 보면서 정리한 설계 원칙을 공유한다. (예시는 공개한 개인 도구 door...
    🤖 ai
    ai
    2026.06.17
  • 벡터 검색 알고리즘 — kNN에서 HNSW까지
    임베딩으로 텍스트를 벡터로 바꾸고 나면, "질문 벡터와 가장 가까운 문서 벡터"를 찾아야 한다. 이 글은 그 검색을 담당하는 알고리즘을 kNN(개념) → 왜 느린가 → ANN → HNSW(실전 표준) 순서로 정리한다. - kNN(k-Nearest Neighbors) = 어떤 벡터(쿼리)와 가장 가까운 k개의 이웃 벡터를 찾는 알고리즘 - 예를 들어 - 문서...
    🤖 ai
    ai
    2026.06.16
  • OpenClaw vs Hermes Agent — 갈아탈까 고민하며 정리한 비교
    지금 나는 OpenClaw로 개인 에이전트를 돌리고 있다. 잘 동작하지만, 에이전트를 여러 개 구성하고 그 위에 제대로 된 화면을 얹는 그림을 그리다 보니 Hermes Agent가 자꾸 눈에 들어온다. 갈아탈지 말지를 결정하기 전에, 두 프레임워크가 메모리·구성·UI·자기개선에서 실제로 무엇이 다른지 공식 문서 기준으로 정리했다. OpenClaw 자체의 내...
    🤖 ai
    ai
    2026.06.16

댓글 (0)