Saltar al contenido principal
DB-1101 • 36 Horas • Nivel Avanzado / Principal Search Engine Architect

Motores de Búsqueda Textual y Analítica Documental: Elasticsearch / OpenSearch Internals, Apache Lucene, BM25 e ILM

Arquitectura interna de segmentos inmutables de Apache Lucene (FST, Inverted Index, Doc Values, BKD Trees), función probabilística Okapi BM25 y búsqueda híbrida RRF, pipelines de análisis léxico, prevención de Mapping Explosion e Index Lifecycle Management (ILM).

Módulo 1: Módulo 1: Internals de Apache Lucene: Segmentos Inmutables, FST, Índices Invertidos y Doc Values

Anatomía de un Shard de Lucene: Finite State Transducers (FST), Postings Lists y Segment Merging (50 min)

Anatomía de un Shard de Lucene: Finite State Transducers (FST), Postings Lists y Segment Merging

1. Cada Shard de Elasticsearch es una Instancia Independiente de Apache Lucene

Un índice en Elasticsearch/OpenSearch se particiona en Shards, y cada Shard es un directorio de Segmentos Inmutables de Apache Lucene. Dentro de cada segmento conviven cuatro estructuras físicas especializadas:

1. Term Index (.tip - Finite State Transducer en RAM): Autómata determinista minimal que comprime prefijos y sufijos compartidos del diccionario de términos para localizar el offset en disco de cualquier palabra en $\mathcal{O}(\text{len}(\text{term}))$. 2. Postings Lists (.doc, .pay, .pos - Índice Invertido): Lista ordenada de DocIDs comprimida mediante Frame-of-Reference (FOR) Delta Encoding y Roaring Bitmaps para intersecciones SIMD ultrarrápidas. 3. Doc Values (.dvd - Almacenamiento Columnar en Disco): Estructura columnar orientada por documento (DocID -> Valor) mapeada vía mmap en el Page Cache del kernel para ejecutar ordenamientos (sort) y agregaciones (terms, percentiles) sin llenar el Heap de la JVM. 4. BKD Trees (.kdd - Block K-D Trees): Índices espaciales multidimensionales para rangos numéricos, fechas y coordenadas geográficas.

Por Qué Elasticsearch es Near Real-Time (NRT): In-Memory Buffer, Refresh (1s), Translog y Flush (50 min)

Por Qué Elasticsearch es Near Real-Time (NRT): In-Memory Buffer, Refresh (1s), Translog y Flush

1. Diferencia Crítica entre Refresh (Visibilidad de Búsqueda) y Flush (Durabilidad fsync)

flowchart LR
    DOC["PUT /index/_doc/1"] --> BUF["In-Memory Indexing Buffer"]
    DOC --> TLOG["Translog (Write-Ahead Log en Disco)"]
    BUF -->|"Refresh (cada 1s por defecto)"| SEG["Nuevo Segmento Lucene en OS Page Cache (¡Ya Buscable!)"]
    SEG -->|"Flush (cada 30m o Translog > 512MB)"| DISK["fsync() de Segmentos a Disco + Truncate Translog"]

[!TIP]
Optimización de Ingesta Masiva (Bulk Indexing): Durante una carga o reindexación masiva de millones de documentos, el refresh_interval: "1s" genera miles de micro-segmentos diminutos y satura el disco con fusiones (Segment Merges). Ajustar temporalmente index.refresh_interval: "30s" (o "-1") multiplica el throughput de indexación entre $4\times$ y $8\times$.

Ingeniería de Memoria JVM y OS Page Cache: La Barrera de los 31 GB (Compressed OOPs) (45 min)

Ingeniería de Memoria JVM y OS Page Cache: La Barrera de los 31 GB (Compressed OOPs)

1. Por Qué Jamás Debes Asignar Más de $31\text{ GB}$ al Heap de la JVM en un Nodo Elasticsearch

1. Barrera de Punteros Comprimidos (Compressed Ordinary Object Pointers): Por debajo de $\approx 31.5\text{ GB}$ de Heap, la JVM de 64 bits direcciona objetos usando desplazamientos comprimidos de 32 bits. Si asignas -Xmx32g o -Xmx40g, la JVM pasa a punteros crudos de 64 bits, desperdiciando memoria y teniendo menos objetos efectivos disponibles que con $31\text{ GB}$. 2. Lucene Vive en el OS Page Cache Fuera de la JVM: Al menos el $50\%$ de la RAM física del servidor debe dejarse libre fuera de la JVM para que el kernel Linux cachee en memoria los segmentos .dvd (Doc Values), .doc (Postings) y vectores HNSW mediante mmap.

Módulo 2: Módulo 2: Relevancia Probabilística Okapi BM25, Analizadores Léxicos y Búsqueda Híbrida (RRF)

Matemática de Relevancia Textual: De TF-IDF a Okapi BM25 y Ajuste de Hiperparámetros (k1, b) (55 min)

Matemática de Relevancia Textual: De TF-IDF a Okapi BM25 y Ajuste de Hiperparámetros (k1, b)

1. Saturación No Lineal de Frecuencia y Normalización por Longitud en Okapi BM25

En TF-IDF clásico, un documento que repite una palabra 50 veces obtiene un puntaje 10 veces mayor que uno que la menciona 5 veces. Okapi BM25 corrige este defecto mediante saturación hiperbólica controlada por $k_1 \in [1.2, 2.0]$ y penalización de longitud relativa controlada por $b \in [0, 1]$:

$\text{Score}_{\text{BM25}}(D, Q) = \sum_{q_i \in Q} \text{IDF}(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot \left(1 - b + b \cdot \frac{|D|}{\text{avgdl}}\right)}$

Donde la frecuencia inversa de documento suavizada de Lucene garantiza valores estrictamente no negativos:

$\text{IDF}(q_i) = \ln\left(1 + \frac{N - n(q_i) + 0.5}{n(q_i) + 0.5}\right)$

- En catálogos de SKUs, códigos técnicos o títulos cortos: Reducir $b \to 0.15$ y $k_1 \to 0.6$ evita penalizar descripciones concisas donde el término aparece una sola vez.

Pipelines de Análisis Textual: Character Filters, Tokenizers, Synonym Graphs (Index vs. Search Time) (50 min)

Pipelines de Análisis Textual: Character Filters, Tokenizers, Synonym Graphs (Index vs. Search Time)

1. Por Qué los Sinónimos Deben Aplicarse en search_analyzer y No en index_analyzer

Inyectar un diccionario de sinónimos durante la indexación tiene tres defectos graves en producción: 1. Cada actualización del archivo de sinónimos exige reindexar terabytes de documentos. 2. Infla el tamaño del índice invertido en disco. 3. Corrompe las estadísticas globales de $\text{IDF}(q_i)$ de los términos raros.

Configurar el filtro synonym_graph exclusivamente en el search_analyzer permite actualizar sinónimos en caliente vía recarga de analizadores y maneja correctamente sinónimos multi-palabra mediante grafos de posición de tokens (Phrase Queries).

Búsqueda Híbrida Lexical + Vectorial (BM25 + kNN HNSW) y Fusión Libre de Escala con RRF (45 min)

Búsqueda Híbrida Lexical + Vectorial (BM25 + kNN HNSW) y Fusión Libre de Escala con RRF

1. El Problema de las Escalas Incompatibles entre BM25 y Cosine Similarity

El puntaje $\text{BM25} \in [0, \infty)$ no está acotado y depende de la longitud de la consulta, mientras que la similitud coseno vectorial vive en $[-1, 1]$. Sumarlos linealmente sin calibración por consulta sesga el ranking.

Reciprocal Rank Fusion (RRF - Cormack et al.): Combina únicamente las posiciones ordinales $r_m(d) \in \{1, 2, \dots\}$ de cada motor con constante de suavizado $k = 60$:

$\text{RRF\_Score}(d) = \sum_{m \in \{\text{BM25}, \text{HNSW}\}} \frac{1}{k + r_m(d)}$

Módulo 3: Módulo 3: Gobernanza de Mappings, Paginación Profunda (search_after + PIT) e ILM

Prevención de Mapping Explosion: Dynamic Strict, Text vs. Keyword y el Tipo Flattened (50 min)

Prevención de Mapping Explosion: Dynamic Strict, Text vs. Keyword y el Tipo Flattened

1. Cómo un JSON con Llaves Dinámicas Destruye el Cluster State

Si ingieres payloads JSON donde los usuarios crean nombres de atributos arbitrarios (ej. labels.env_2026_01, labels.user_9981) con dynamic: true, el diccionario de mappings crece a decenas de miles de campos, hinchando el Cluster State que el nodo Master debe sincronizar a todos los nodos del clúster.

Regla de Gobernanza: 1. Configurar "dynamic": "strict" en todos los índices transaccionales/catálogo. 2. Para objetos con claves arbitrarias o etiquetas dinámicas de Kubernetes/telemetría, utilizar el tipo flattened, que indexa todo el subdocumento JSON dentro de un único campo Lucene sin crear sub-mappings en el Cluster State.

El Anti-Patrón de Deep Pagination (from + size) y Paginación Escalable con search_after + Point-in-Time (PIT) (50 min)

El Anti-Patrón de Deep Pagination (from + size) y Paginación Escalable con search_after + Point-in-Time (PIT)

1. Complejidad $\mathcal{O}(S \cdot (\text{from} + \text{size}))$ en el Nodo Coordinador

En un índice con $S = 20$ shards, pedir la página 1,000 con { "from": 50000, "size": 50 } obliga a cada uno de los 20 shards a ordenar y enviar sus mejores $50,050$ resultados al nodo coordinador, el cual debe fusionar una cola de prioridad de $20 \times 50,050 = 1,001,000$ documentos en el Heap JVM solo para devolver 50 y descartar $999,950$. Por ello Elasticsearch bloquea por defecto index.max_result_window = 10000.

Solución de Producción: Abrir un Point-in-Time (PIT) (que congela una vista consistente de segmentos) y paginar usando search_after con el vector de ordenamiento del último documento recibido + llave de desempate única (_shard_doc).

Arquitectura Multi-Tier con Index Lifecycle Management (ILM): Hot, Warm, Cold y Searchable Snapshots (S3) (45 min)

Arquitectura Multi-Tier con Index Lifecycle Management (ILM): Hot, Warm, Cold y Searchable Snapshots (S3)

1.Dimensionamiento Óptimo de Shards (20 GB – 50 GB) y Tiering FinOps

- Anti-patrón de Oversharding: Tener $2,000$ shards de $50\text{ MB}$ agota el Heap de la JVM con metadatos FST y sobrecarga el hilo Master. El tamaño ideal por shard se ubica entre $20\text{ GB}$ y $50\text{ GB}$. - Ciclo ILM Automatizado: 1. Hot Tier (NVMe Local): Ingesta activa; rollover automático al alcanzar max_primary_shard_size: "40gb" o max_age: "1d". 2. Warm Tier: forcemerge a max_num_segments: 1 y puesta en solo-lectura. 3. Cold / Frozen Tier (Searchable Snapshots): Monta snapshots almacenados directamente en Amazon S3 / GCS descargando bajo demanda solo los bloques de rango consultados, reduciendo el costo de almacenamiento en un $85\%$.

Módulo 4: Módulo 4: Laboratorio de Auditoría de Oversharding / RRF y Evaluación de Certificación

Migraciones de Esquema Zero-Downtime en Elasticsearch mediante Read/Write Aliases Atómicos (45 min)

Migraciones de Esquema Zero-Downtime en Elasticsearch mediante Read/Write Aliases Atómicos

En Lucene no es posible cambiar el tipo ni el analizador de un campo existente sin reindexar. Por ello, ningún microservicio debe apuntar jamás al nombre físico de un índice (catalog_v1), sino a un Alias Lógico (catalog_read / catalog_write), permitiendo ejecutar _reindex hacia catalog_v2 y conmutar el alias en una operación atómica de $< 1\text{ ms}$ vía POST /_aliases.

Laboratorio Práctico: Implementación del Ranking Híbrido Reciprocal Rank Fusion (RRF k=60) en SQL (60 min)

Laboratorio Práctico: Implementación del Ranking Híbrido Reciprocal Rank Fusion (RRF k=60) en SQL

Contexto del Desafío de Motores de Búsqueda

Nuestro buscador híbrido consulta simultáneamente el índice invertido BM25 y el índice vectorial HNSW. La tabla hybrid_search_candidates contiene las posiciones ordinales (bm25_rank y vector_rank) obtenidas por cada documento candidato para una consulta técnica: - doc_id (TEXT) - bm25_rank (INTEGER: posición en el ranking léxico BM25, 1 es el mejor) - vector_rank (INTEGER: posición en el ranking semántico vectorial, 1 es el mejor)

Objetivo de la Consulta SQL

Calcula el puntaje Reciprocal Rank Fusion (RRF) con constante k = 60: $\text{rrf\_score} = \frac{1.0}{60 + \text{bm25\_rank}} + \frac{1.0}{60 + \text{vector\_rank}}$ Devuelve las columnas: 1. doc_id 2. bm25_rank 3. vector_rank 4. rrf_score: redondeado a 6 decimales (ROUND(..., 6)). Ordena el resultado por rrf_score DESC.

Evaluación de Certificación: Motores de Búsqueda Textual, Apache Lucene y Analítica Documental (45 min)

Evaluación de Certificación: DB-1101

Demuestra tu dominio de los internals de Apache Lucene, Okapi BM25, gestión de memoria JVM/Page Cache y búsqueda híbrida.