Elasticsearch 입문 3편 — Lucene 내부 깊이 (Segment·Inverted Index·Posting List·Tokenization)

2026-05-19Elasticsearch 입문에서 운영까지

Elasticsearch 입문 3편. 코어 라이브러리 Apache Lucene 깊이. Segment·Inverted Index·Posting List·Tokenization·Doc Values·BM25 한 호흡에.

📚 Elasticsearch 입문에서 운영까지 · 3편 — Lucene 내부 깊이 (Segment·Inverted Index·Posting List·Tokenization)

이 글은 Elasticsearch 입문에서 운영까지 시리즈 38편 중 3편이에요. 1편에서 "Elasticsearch = Lucene 위 분산 레이어" 라고 한 줄 정리했고, 2편에서 Index · Document · Shard · Replica · Mapping 다섯 단어를 깊이 짚었어요. 이번 편은 그 아래로 한 층 더 내려가서 — Elasticsearch 의 진짜 코어인 Apache Lucene디스크 위에서 무엇을 어떻게 들고 있는지 를 풀어요.

📚 학습 노트

이번 편은 Apache Lucene 공식 docs 의 file formats · index writer · BM25 similarity 섹션과 Elasticsearch 8.x 공식 near real-time search · refresh · flush · merge 문서를 묶어 한국어로 풀어쓴 자료예요.

코드 예시는 Elasticsearch 8.x REST API 기준. 한 번이라도 _segments · _forcemerge 를 직접 호출해 보면 본문이 훨씬 빨리 박혀요.

왜 Lucene 을 알아야 하나

운영 중에 만나는 사고의 70% 가량이 "Lucene 이 디스크 위에서 어떻게 동작하는가" 를 모르면 진단이 안 돼요. "왜 색인했는데 검색에 안 잡히지", "refresh interval 을 줄였더니 디스크 IO 가 폭증했다", "force merge 했는데 노드가 한 시간 멈춤", "keyword 필드 정렬 빠른데 text 필드 정렬은 왜 느릴까" — 이런 질문이 전부 Lucene 의 Segment · Posting List · Doc Values 세 단어로 정리돼요.

Elasticsearch 가 "분산·실시간·JSON 색인" 을 가능하게 만든 비밀은 그 자체의 마법이 아니라, 각 샤드 안에서 묵묵히 일하는 Lucene 인스턴스수십 년 묶인 정보 검색(Information Retrieval) 이론 을 그대로 구현해 둔 데 있어요. 그래서 이 시리즈가 입문 1·2편 → 운영 26~31편 으로 넘어가기 전에, 한 편을 통째로 잘라 Lucene 안을 들여다보고 가는 게 가성비가 가장 좋아요.

Lucene 이란

Apache Lucene = "Java 로 짠 풀텍스트 검색 라이브러리". 1999년 Doug Cutting 이 처음 발표했고, 2001년 Apache 재단으로 들어가서 지금은 Apache Lucene Core 프로젝트로 유지되고 있어요. 작성 시점(2026-05-19) 기준 Lucene 의 최신 메이저 버전은 9.x 대이고, Elasticsearch 8.x 가 이걸 임베드해서 씁니다.

Lucene 자체는 분산 X · 클러스터 X · REST API X 예요. "한 머신 안에서 디스크 위에 색인을 쌓고 검색 쿼리를 푸는 Java 라이브러리" 라고 보면 됩니다. 그래서 Lucene 만 들고는 대규모 검색 서비스 를 못 만들고, 누군가 그 위에 분산 레이어·REST API·관리 UI 를 얹어 줘야 해요. 그 역할을 2010년에 Shay Banon 이 만든 게 Elasticsearch, 2004년에 만든 게 Solr 예요.

같은 코어를 공유한다는 사실 때문에 Elasticsearch · OpenSearch · Solr 셋이 Lucene 기반 검색 엔진 으로 한 묶음이에요. 사용자 인터페이스와 운영 도구는 다르지만 디스크 위 파일 포맷 · 색인 알고리즘 · 스코어링 은 사실상 동일합니다. 1편에서 짚은 OpenSearch fork 가 가능했던 이유도, Lucene 이 Apache 2.0 으로 유지되고 있어서 그 위 레이어만 다시 만들면 됐기 때문이에요.

한 가지 더 — Lucene 은 "라이브러리" 라서 "데몬 프로세스" 가 아니에요. Elasticsearch 노드 안에서 샤드 하나당 Lucene 인스턴스 하나 가 생성되고, 그 인스턴스가 자기 샤드의 디스크 파일을 책임지고 쓰고 읽어요. 즉 Elasticsearch 클러스터 = 분산 Lucene 인스턴스 묶음 이에요.

Segment 파일 — Lucene 의 immutable 기본 단위

Lucene 이 디스크에 쌓는 가장 중요한 단위가 Segment 예요. 한 샤드는 여러 개의 segment 묶음 으로 이루어져 있고, 한 segment 는 그 안에 색인된 문서들의 inverted index · doc values · stored fields · norms 가 한 세트 로 들어 있는 작은 Lucene 인덱스 라고 보면 됩니다.

가장 중요한 성질은 immutable. 한 번 디스크에 쓰인 segment 는 수정·삭제 X. 새 문서가 들어오면 새로운 segment 가 만들어지고, 기존 문서 업데이트는 기존 segment 의 해당 문서에 "삭제" 표시(tombstone) + 새 segment 에 새 버전 이라는 append-only 방식으로 처리돼요. 이 한 줄이 Lucene 이 Lock-free 검색 · 동시성 · 캐시 친화 를 동시에 잡은 비결이에요.

흐름이 이렇게 흘러요. 클라이언트가 문서를 색인 API 로 보내면, Lucene 은 우선 메모리에 In-memory Buffer 로 쌓아 둬요. 이때는 아직 segment 가 아니라 Indexing Buffer 라는 임시 영역이에요. 일정 간격마다 (Elasticsearch 기본 1초) refresh 가 일어나서 이 버퍼가 "in-memory segment" 로 닫히고, 그 순간부터 검색 가능 한 상태가 돼요. 이게 near real-time search 의 정체.

여기서 refreshflush 는 다른 동작이에요. refresh 는 "버퍼 → segment (메모리 또는 OS 페이지 캐시) 로 닫고 검색 가능하게" 만드는 동작이고, flush 는 "segment 들을 진짜 디스크에 fsync 로 영구화 + translog 비우기" 동작이에요. Elasticsearch 는 refresh 가 기본 1초 이고, flush 는 30분 또는 translog 가 512MB 도달 시 발생해요.

# refresh interval 확인·변경
GET my-index/_settings
PUT my-index/_settings
{ "index.refresh_interval": "30s" }

# 강제 refresh — 거의 안 씀, 테스트 용도
POST my-index/_refresh

# segment 현황 확인
GET my-index/_segments

segment 가 계속 늘어나기만 하면 파일 핸들 폭증 · 검색 시 모든 segment 를 순회해야 해서 느려짐 같은 문제가 생겨요. 그래서 Lucene 이 백그라운드에서 merge 작업을 자동으로 돌려요. 작은 segment 여러 개를 모아 하나의 큰 segment 로 합치는 동작인데, 합치는 과정에서 삭제 표시된 문서가 진짜로 제거 돼요. 평소엔 자동에 맡기면 됩니다. 운영 중에 직접 강제 merge 하는 경우는 읽기 전용 인덱스 (시간 데이터, ILM 의 cold tier) 처럼 "이제 절대 안 쓸 거다" 라는 보장이 있을 때만 — _forcemerge?max_num_segments=1 호출이 그 자리예요.

Inverted Index — 단어가 먼저, 문서가 나중

검색 엔진의 핵심 자료구조가 Inverted Index (역인덱스) 예요. 일반적인 데이터베이스 인덱스가 "문서 ID → 필드 값" 매핑이라면, inverted index 는 그 반대로 "단어 → 그 단어가 등장한 문서 ID 들" 매핑이에요.

직관적으로 보면 이래요. 책 뒤편의 색인(찾아보기) 페이지가 inverted index 예요. "단어 '스키마' → 47쪽, 89쪽, 132쪽" 이라고 적혀 있죠. 검색 엔진이 "스키마 들어간 페이지 찾아 줘" 라는 쿼리를 풀 때, 본문을 처음부터 읽는 게 아니라 색인 페이지를 펴는 거예요. RDBMS 의 LIKE '%스키마%' 가 본문을 처음부터 끝까지 읽는 동작이고, Lucene 의 풀텍스트 검색이 책 뒤편의 색인을 펴는 동작이라고 보면 됩니다.

구조를 한 단계 더 풀면 inverted index 는 두 갈래 자료구조 로 구성돼요. Term Dictionary"색인된 모든 unique 단어의 정렬된 사전" 이에요. Lucene 은 이걸 FST (Finite State Transducer, 유한 상태 변환기) 로 압축해서 수억 개 단어를 메모리에 적은 비용으로 들고 있어요. 다른 한 갈래 Posting List"각 단어에 매달린 문서 ID 리스트" 예요. 이 둘이 term → posting 으로 연결돼 있어서 "어느 단어가 어느 문서들에 있나"O(log N) 또는 그 이하 로 풀려요.

여기서 한 가지 짚을 게 — text 필드와 keyword 필드는 inverted index 의 모양이 다릅니다. text 필드는 analyzer 를 거쳐 토큰 단위로 잘려서 색인돼요 ("빠른 갈색 여우"빠른 · 갈색 · 여우 세 단어). keyword 필드는 값 전체가 통째로 단일 토큰 으로 색인돼요 ("running-shoes-001" → 그 문자열 그대로 하나). 그래서 text 는 부분 검색·동의어·형태소 가 되고, keyword 는 정확 일치·정렬·집계 가 빨라요. 1편의 Mapping 에서 왜 둘을 multi-field 로 같이 두는가 가 여기에 기원을 둬요.

검색 점수를 매기는 스코어링 알고리즘은 Lucene 6.0(2016) 부터 BM25 (Best Matching 25) 가 기본이에요. 그 이전 TF-IDF (Term Frequency · Inverse Document Frequency) 를 한 단계 발전시킨 알고리즘인데, 문서 길이단어 빈도의 포화 를 함께 고려해서 짧은 문서에 같은 단어가 여러 번 나오면 점수가 더 후하게 매겨지도록 보정돼 있어요. 직접 튜닝할 일은 거의 없고 기본값으로 운영하면 90% 자리에서 OK. 18편(Aggregations) 과 19편(Search Features) 에서 자세히 다룰 자리예요.

Posting List — 토큰별 문서 ID 리스트

Posting List 가 inverted index 의 실제 데이터 가 담긴 자리예요. "단어 '빠른'" 에 매달린 posting list 가 "문서 1·5·12·45·128·…" 같은 정렬된 문서 ID 리스트예요. 검색 쿼리가 들어왔을 때 posting list 의 교집합·합집합 을 잡으면 AND·OR 쿼리 결과가 풀려요. "빠른 AND 여우" 면 두 posting list 의 교집합, "빠른 OR 여우" 면 합집합.

Lucene 의 posting list 는 단순한 문서 ID 배열이 아니라 세 종류 정보 를 함께 들고 있을 수 있어요. doc id 는 그 단어가 등장한 문서 ID, frequency (또는 term frequency, tf) 는 그 문서 안에서 그 단어가 몇 번 등장했는가, position문서 안 몇 번째 토큰 자리에 있었는가, offset원문 글자 단위의 시작·끝 인덱스 예요. 매핑 옵션 index_optionsposting list 에 어디까지 적어 둘지 결정해요.

  • docs — doc id 만. 가장 가볍지만 phrase query (구문 검색) 가 X.
  • freqs — doc id + frequency. BM25 스코어링은 가능.
  • positions — doc id + frequency + position. match_phrase · proximity 쿼리 가능. text 필드 기본값.
  • offsets — doc id + frequency + position + offset. highlighting (검색어 하이라이트) 가 빨라짐.

posting list 가 무한정 커지지 않는 비결이 Postings Format 의 압축이에요. Lucene 의 기본 postings format 은 FOR (Frame Of Reference) · PFOR-Delta · vbyte 같은 정수 압축 알고리즘 으로 doc id 리스트를 Delta 인코딩 한 다음 블록 단위로 비트 패킹 해 둬요. 그 결과 문서 수가 10억 개여도 posting list 의 디스크 크기가 수 GB 단위 로 유지되는 거예요. 운영자 입장에서 이 압축은 튜닝할 일이 거의 없고 그냥 기본이면 OK 라고 알아 두면 충분합니다.

# index_options 를 mapping 에 명시하는 예시
PUT my-index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "index_options": "positions"
      },
      "body": {
        "type": "text",
        "index_options": "offsets"
      },
      "sku": {
        "type": "keyword",
        "index_options": "docs"
      }
    }
  }
}

Tokenization 흐름 — Character filter → Tokenizer → Token filter

text 필드에 들어온 문자열이 inverted index 에 어떤 토큰으로 쪼개져 들어가는가 를 결정하는 게 Analyzer 예요. Lucene·Elasticsearch 에서 analyzer 는 항상 세 단계의 파이프라인 으로 동작합니다. 이 3단계는 한국어 분석기 Nori (11편) · 영어 standard · 커스텀 analyzer 가 다 똑같은 골격으로 짜여 있어요.

1단계 — Character Filter

원문 문자열 단위 에서 일어나는 전처리예요. "HTML 태그 제거" (html_strip), "특정 문자 치환" (mapping), "패턴 치환" (pattern_replace) 같은 작업이 여기 자리예요. 토큰화 이전 단계 라서 전체 문자열에 적용 됩니다. 예 — <p>안녕 세상</p>안녕 세상.

2단계 — Tokenizer

여기서 문자열 → 토큰 배열 변환이 일어나요. 한 analyzer 안에 반드시 정확히 한 개 의 tokenizer 가 있어야 해요. 영어 기본은 standard (Unicode 표준 텍스트 세그멘테이션), 한국어는 nori_tokenizer, 공백 기준은 whitespace, n-gram 은 ngram 같은 식이에요. 예 — 안녕 세상 빠른여우nori_tokenizer 를 거치면 [안녕, 세상, 빠르, 여우] 같이 형태소 단위 로 잘려요.

3단계 — Token Filter

토큰 배열을 다시 손보는 단계예요. "소문자 변환" (lowercase), "불용어 제거" (stop), "형태소 원형 복원" (stemmer · nori_part_of_speech), "동의어 확장" (synonym), "edge n-gram" (검색어 자동완성용) 같은 작업이 여기 자리예요. 여러 개를 순서대로 체인할 수 있어요. 예 — [Quick, Brown, Foxes] → lowercase → [quick, brown, foxes] → stemmer → [quick, brown, fox].

이 3단계가 색인 시점 (index-time)검색 시점 (search-time) 양쪽에 적용돼요. 둘이 같아야 합니다. 색인 때 소문자로 잘라 넣고 검색 때 대문자 그대로 던지면 인덱스의 토큰과 쿼리 토큰이 안 맞아서 검색 결과가 0건이 나와요. 이 사고가 신규 팀 첫 주의 단골 자리예요. 운영 안전 기본값은 index analyzer 와 search analyzer 를 한 이름으로 통일 하는 거고, 일부러 다르게 쓰는 건 edge n-gram 자동완성처럼 특정 패턴 에서만이에요.

# analyzer 동작 확인 — _analyze API
POST my-index/_analyze
{
  "text": "<p>The Quick Brown Foxes Jump</p>",
  "analyzer": "standard"
}

# 결과 토큰 — the · quick · brown · foxes · jump

Doc Values — keyword·numeric·date 정렬·집계용 컬럼 저장

inverted index 만으로는 "검색은 빠른데 정렬·집계가 느린" 문제가 생겨요. 검색은 "단어 → 문서" 방향이 빠르지만, "문서 1번의 price 필드 값을 가져와 정렬하라" 같은 "문서 → 필드 값" 역방향 조회는 inverted index 로는 비효율적이에요.

Lucene 이 이 문제를 푸는 자료구조가 Doc Values 예요. 컬럼 지향 으로 "각 필드의 값을 문서 ID 순서대로 디스크에 죽 늘어놓은" 별도 파일이에요. 정렬·집계·스크립트·function_score 처럼 문서 → 필드 값 접근이 필요한 모든 쿼리가 doc values 를 읽어요. RDBMS 의 columnar storage (열 지향 저장) 와 비슷한 발상이에요.

doc values 는 기본적으로 keyword · numeric · date · boolean · geo_point 필드 에서 자동으로 켜져 있어요. text 필드는 doc values 가 기본 X — 그래서 text 필드를 정렬·집계에 쓰면 fielddata 라는 비효율적 메모리 캐시 가 동작해서 OOM (Out of Memory) 사고가 잘 나요. 그래서 정렬·집계 요구가 있는 필드는 keyword 로 두라 는 가이드가 1편·8편에서 반복돼 나오는 거예요.

필드 타입 inverted index doc values 사용 자리
text O X (기본) 풀텍스트 검색
keyword O O 정확 일치 · 정렬 · 집계
long · double O (range tree) O 숫자 검색 · 정렬 · 집계
date O O 시간 범위 · 집계
boolean O O 필터
geo_point 별도 BKD tree O 위치 검색 · 거리

운영 운영 권장 — 정렬·집계가 절대 안 들어가는 필드만 doc_values: false 로 끄세요. 끄면 디스크 절약은 되지만 나중에 정렬·집계 요구가 생기면 재색인 이 필요해서, 의심스러우면 그냥 기본값으로 두는 게 안전 합니다.

자주 만나는 사고

사고 1 — refresh interval 너무 짧음

원인 — 검색 결과가 빨리 보이게 하려고 refresh_interval기본 1초 → 100ms 로 줄이면, 작은 segment 가 폭증 해서 merge 부담 + 파일 핸들 폭증 + 검색 지연 이 동시에 일어나요. 대량 색인 자리에서는 오히려 refresh_interval = 30s 또는 -1 (비활성) 로 두는 게 표준.

해결 — 대량 bulk 색인 동안은 일시적으로 refresh_interval: -1 로 끄고 끝나면 다시 켜는 패턴. 검색 응답성이 0.1초 단위 까지 필요한 자리는 refresh_interval 보다 cache 전략 으로 푸는 게 맞아요. 23편(Bulk Indexing) 에서 깊이.

사고 2 — too many open segments

원인 — segment 가 수천 개 단위 로 쌓이면 파일 핸들 한도 (ulimit -n) 가 터지거나, 각 검색 쿼리가 모든 segment 를 순회 해야 해서 latency 가 P99 단위로 폭증 해요. 인덱스가 작은데 색인이 잦으면 잘 일어납니다.

해결refresh_interval 을 늘리고, force merge 는 읽기 전용 인덱스 한정 으로 돌려요. 그리고 시간 데이터는 일자별 인덱스로 쪼개고 ILM 으로 자동 merge 정책 을 박는 패턴. 6편(ILM) · 26편(Cluster Ops) 에서 깊이.

사고 3 — force merge 운영 사고

원인쓰기 트래픽이 살아 있는 인덱스_forcemerge?max_num_segments=1 을 잘못 호출하면, 수십 GB segment 가 한 덩어리로 합쳐지는 IO 가 몇 시간 단위로 노드를 점유해서 클러스터 응답 폭망 이 나요. 더 큰 문제는 그렇게 합쳐진 거대 segment 가 더 이상 자동 merge 후보로 안 잡혀서 이후로 삭제 문서 회수가 안 되는 자리.

해결 — force merge 는 반드시 읽기 전용 인덱스 (ILM 의 warm·cold tier, 시간 데이터의 이전 일자) 한정. 그리고 off-peak 시간대. max_num_segments=1영원히 합치지 않을 자리 에서만 쓰고, 일반은 3~5 정도가 안전 합니다. 26편에서 다시.

사고 4 — doc values disabled 후 집계 폭망

원인 — 디스크 절약하려고 doc_values: false집계가 들어올 가능성이 있는 필드 에 박아 두면, 나중에 집계 요청이 들어왔을 때 fielddata 가 동작하면서 JVM heap 폭증 → OOM 이 일어나요.

해결집계·정렬 요구가 절대 없다고 확신 하지 않는 한 doc values 는 기본값 그대로 둬요. 디스크가 정말 빡빡하면 오래된 인덱스를 cold tier · frozen tier 로 옮기는 ILM 전략이 더 안전. 6편에서 깊이.

사고 5 — analyzer 색인·검색 불일치

원인 — 색인 시점 analyzer 와 검색 시점 analyzer 가 달라서, 색인 토큰검색 토큰 이 안 맞아 검색 결과 0건 이 나는 사고. 가장 단골은 index_analyzer 에 lowercase 있는데 search_analyzer 에는 없음 자리.

해결mapping 의 analyzer 하나만 지정해서 양쪽이 같은 걸 쓰게 해요. 일부러 다르게 쓰는 edge n-gram 자동완성 같은 패턴은 명시적으로 두 analyzer 를 따로 잡고 검증 케이스를 함께 둬요. 10편(Analyzer) 과 20편(Suggesters) 에서 깊이.

사고 6 — text 필드 정렬 시도

원인제목·본문 같은 text 필드에 sort: { title: "asc" } 를 박으면, doc values 가 X 라서 fielddata 가 켜지면서 JVM heap 폭증 + 정렬 결과가 토큰 단위로 이상하게 나와요.

해결multi-field 매핑 으로 title.keyword 같은 keyword sub-field 를 같이 두고, 정렬·집계는 그쪽으로 보내요. text 자체의 정렬은 fielddata: true 로 강제할 수도 있지만, 권장 X. 8편(Mapping Deep) 에서 깊이.

사고 7 — translog 폭증

원인 — flush 가 늦거나 translog durability 설정이 request 가 아니라 async 인 상태에서 부하가 폭증하면 translog 파일이 수십 GB 단위로 쌓여서 복구 시간 폭증 + 디스크 빠른 소모 가 일어나요.

해결 — translog flush 임계 (index.translog.flush_threshold_size) 와 durability 를 워크로드에 맞게 조정, 그리고 복구 시 translog replay 시간 을 모니터링에 포함. 30편(Monitoring) 에서 다시 묶음.

운영 권장 패턴

운영 시작 전에 다음 네 가지를 항상 한 화면에서 같이 결정해 두면 Lucene 관련 사고의 80% 가 사라져요.

첫째, refresh_interval 은 기본 1초가 적정 한지 워크로드별로 다시 잡아요. 검색 응답 SLA 가 몇 초 지연을 허용 하는 ELK 로그 인덱스는 30s · 60s 가 표준이고, e-commerce 상품 검색 처럼 수정이 즉시 반영 돼야 하는 자리만 1초.

둘째, force merge 는 ILM 정책 안에 박아 둬요. 사람 손으로 직접 호출하지 말고 시간 데이터의 warm tier 진입 시 자동 force merge 처럼 자동화 가 안전합니다. 6편(ILM) 에서 다시.

셋째, Mapping 단계에서 index_options · doc_values 를 명시 합니다. 동적 매핑에 맡기면 모두 기본값으로 잡혀서 나중에 원하는 검색 기능이 없거나 디스크 폭증 같은 사고가 잘 나요. 8편(Mapping Deep) 에서 깊이.

넷째, index analyzer 와 search analyzer 는 한 이름으로 통일. 다르게 가야 하는 자동완성·동의어 확장 같은 특수 자리만 명시적으로 둘을 잡고 검증 케이스를 함께 둬요.

시험 직전 한 번 더 — 압축 노트

  • Apache Lucene = Java 풀텍스트 검색 라이브러리. 1999 Doug Cutting 발표, Apache Lucene 9.x 가 ES 8.x 의 코어.
  • Segment = Lucene 의 immutable 기본 단위. 한 샤드 = 여러 segment.
  • refresh = 버퍼 → segment 닫고 검색 가능. 기본 1초.
  • flush = segment 디스크 fsync + translog 비움. 기본 30분 or 512MB.
  • merge = 작은 segment → 큰 segment 자동 합치기. 삭제 문서 진짜 제거 자리.
  • force merge = 사람이 직접 호출. 읽기 전용 인덱스 한정, ILM 으로 자동화 권장.
  • Inverted Index = 단어 → 문서 ID 매핑. Term Dictionary (FST 압축) + Posting List 두 갈래.
  • Posting List = 토큰별 doc id + frequency + position + offset. index_options 로 어디까지 적을지 결정.
  • Postings Format 압축 = FOR · PFOR-Delta · vbyte · Delta 인코딩. 운영 튜닝 거의 X.
  • Tokenization 3단계 = Character filter → Tokenizer → Token filter. 색인·검색 analyzer 통일 이 안전 기본.
  • Doc Values = 컬럼 지향 문서 → 필드 값 저장. 정렬·집계·스크립트 자리에서 동작.
  • text 는 doc values X 기본, keyword · numeric · date 는 O 기본.
  • BM25 = Lucene 6.0+ 기본 스코어링. TF-IDF 의 문서 길이 + 단어 빈도 포화 보정판.
  • text 필드 정렬은 multi-field keyword sub-field 로 우회.
  • refresh 짧게 · force merge 잘못 · doc values disable 셋이 3대 Lucene 운영 사고.

시리즈 다른 편

  • 이전 글 = 2편 Elasticsearch 핵심 개념 — Index·Document·Shard·Replica·Mapping 깊이
  • 다음 글 = 4편 Quickstart — Docker·curl·Kibana 첫 화면
  • 5편 = Index 관리 — Create·Settings·Alias·Reindex
  • 6편 = ILM — Hot·Warm·Cold·Frozen·Delete 자동화
  • 8편 = Mapping Deep — Static·Dynamic·Multi-field·Runtime
  • 10편 = Analyzer — Character filter·Tokenizer·Token filter
  • 11편 = Korean Analyzer — Nori·mecab-ko·사용자 사전
  • 18편 = Aggregations — Pipeline·BM25 스코어링 튜닝
  • 23편 = Bulk Indexing — refresh_interval 비활성·재시도
  • 26편 = Cluster Operations — Red 상태·force merge·shard reroute

한 줄 정리 — Lucene = ES 의 코어. Segment immutable · Inverted Index (Term Dict + Posting List) · Tokenization 3단계 · Doc Values 네 단어가 운영 사고의 80% 를 결정. refresh · flush · merge · force merge 네 동작을 분리해서 기억하면 near real-time search 의 정체가 풀려요.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!