Soluciones de opción múltiple
Respuestas y explicaciones de las quince comprobaciones de conocimientos sobre migración.
Primero realiza la evaluación interactiva de la Parte 4. Solo revela respuestas y explicaciones tras enviar las 15 preguntas. Esta referencia conserva las notas técnicas extensas.
| P | Respuesta |
|---|---|
| 1 | B |
| 2 | B |
| 3 | C |
| 4 | C |
| 5 | B |
| 6 | B |
| 7 | B |
| 8 | C |
| 9 | B |
| 10 | C |
| 11 | B |
| 12 | C |
| 13 | B |
| 14 | B |
| 15 | B |
P1. Coincidencia con el prefijo de ordenación — B
El índice primario de ClickHouse es disperso: una entrada por cada index_granularity filas (8192 por defecto). Omite gránulos que no pueden coincidir según las primeras columnas de la clave. Filtrar por:
- El prefijo completo
(ServiceName, SeverityText, TimestampTime), con las tres columnas yTimestampTimecomo rango final, maximiza la poda.
A solo filtra la columna final; puede usar min/max por gránulo, pero no todo el índice disperso. C usa LIKE en una columna ajena y necesita un índice como tokenbf_v1 o una exploración. D tampoco está en la clave.
La columna temporal a la que se refiere el ejemplo es TimestampTime.
Modelo mental: «¿Cuánto del prefijo de la clave restringe mi predicado?»
P2. Granularidad de eliminación TTL — B
SETTINGS ttl_only_drop_parts = 1 hace que ClickHouse espere hasta caducar una parte MergeTree completa (su máximo TimestampDate cruza INTERVAL 30 DAY) y la desvincule del disco. Es mucho más barato que reescribir la parte sin filas caducadas y encaja con particiones por fecha.
A describe el comportamiento predeterminado sin ttl_only_drop_parts = 1. C solo sucede con DROP TABLE. D no existe.
Modelo mental: En series temporales, TTL debe eliminar partes, no filas; alinea partición y TTL.
P3. Uso de LowCardinality — C
LowCardinality(String) crea un diccionario local que asigna cada string a un entero. Comprime muy bien con pocos valores (ServiceName, SeverityText, Region, EnvironmentName). El equilibrio está cerca de ~10 000 valores; después el diccionario domina el coste.
A anularía la ventaja: cada fila tendría código nuevo. B necesita texto completo + índice de salto. D corresponde a Date/DateTime, cuyos tipos nativos ya son eficientes.
P4. Finalidad del motor Null — C
El patrón otel_logs (Null engine) → otel_logs_mv → otel_logs_v2 (MergeTree) acepta inserciones con el esquema OTel bruto conocido por el collector y persiste solo el esquema transformado (GeoCountry, BrowserFamily, RequestPage, etc.). Sin Null, habría que almacenar dos veces o acoplar el collector al esquema personalizado.
A/B/D no son el motivo. El collector puede escribir MergeTree directamente, pero acoplaría ingesta y almacenamiento.
P5. Dónde viven los atributos en OTel — B
OpenTelemetry separa:
- Atributos de recurso: describen la entidad (host, contenedor, servicio, pod); se definen al iniciar el SDK y se propagan.
- Atributos de span/log/métrica: describen un evento y varían por registro.
service.name, service.version, host.name, cloud.region, k8s.pod.name son recursos. ServiceName promueve ResourceAttributes['service.name'] para ser la primera columna de ordenación.
P6. Índices de salto para filtros sin prefijo — B
Un índice de salto aporta pistas por gránulo para columnas fuera de la clave. bloom_filter(0.01) es el estándar para búsquedas de igualdad de alta cardinalidad (TraceId, UserId, RequestId).
A empeora búsquedas: gránulos mayores significan fallos mayores. C exige reconstruir la tabla (ORDER BY es inmutable en MergeTree). D no cambia planes.
Modelo mental: «Clave de ordenación para el patrón dominante; índices de salto para el resto».
P7. Por qué escribir en ambos destinos desde el collector — B
Si el mismo escritor envía lotes idénticos a ES y CH, las diferencias de paridad pertenecen al almacenamiento o al motor. Leer ambos desde el dashboard introduce orquestación entre sistemas, confunde el origen de las diferencias y complica la reversión: habría que revertir código del dashboard, no quitar un exportador.
A es irrelevante. C es falso: Grafana, HyperDX e incluso Kibana pueden leer varias fuentes. D es incorrecto.
P8. Finalidad de AggregatingMergeTree — C
Aquí ClickHouse supera claramente las transformaciones de Elasticsearch, que exploran periódicamente eventos brutos y vuelven a agregarlos; el coste crece con el volumen.
En AggregatingMergeTree:
- Cada inserción genera un estado parcial:
countState()es un entero;avgState()es (suma, recuento). - Los merges combinan estados adyacentes; incluso sketches como t-digest se pueden combinar.
- Las consultas usan agregados
*Merge.
Las filas brutas nunca se releen después de calcular el estado. El coste se paga al insertar y no crece con la retención.
P9. Por qué los diccionarios IP_TRIE son rápidos — B
Los diccionarios viven en memoria tras SYSTEM RELOAD DICTIONARY. IP_TRIE es un árbol radix por prefijo, así que una búsqueda CIDR cuesta O(prefix-length), unas 32 comparaciones para IPv4, sin disco ni exploración.
A es falso: el planificador conoce los diccionarios. C es improbable con MaxMind (~3 MB para países). D es cierto, pero no explica la velocidad.
P10. Equivalencia de ILM — C
ClickHouse Cloud elimina la mayor parte de ILM:
- Sin capas de nodos: objetos con caché local automática; no hay asignación hot/warm.
- Sin rollover: una tabla MergeTree particionada sustituye índices rotativos.
- Sin forcemerge programado: los merges son continuos.
- TTL elimina: una cláusula sustituye la fase de 30 días.
Es uno de los mensajes más importantes en una conversación ES → CH: reduce la complejidad operativa un orden de magnitud.
P11. Por qué filtrar SpanKind = 'Server' — B
Los spans EventStream de long-poll de flagd duran ~10 minutos a propósito; son contabilidad de conexiones, no solicitudes de usuario, y dominan un «top 10 más lento» ingenuo.
En producción ocurre con RPC de larga duración (SignalR, streaming gRPC, suscripciones GraphQL, keep-alive MQTT). Filtra por SpanKind = 'Server' o un patrón SpanName al estudiar latencia visible por el usuario.
Modelo mental: spans Server = «lo que esperó el usuario»; Internal/Client/Producer/Consumer = «lo que ocurrió debajo».
P12. Indexación de texto completo — C
El índice text es el enfoque moderno, GA en ClickHouse 26.2, y es el que usa el esquema otel_logs_v2 del laboratorio en Body:
El tipo text está pensado expresamente para este acceso.
INDEX idx_body Body TYPE text(tokenizer='sparseGrams') GRANULARITY 8Propiedades:
- Tokenizer configurable:
tokens,ngrams(N),sparseGramso regex. - Más precisión que
tokenbf_v1: postings reales por token, tasa de falsos positivos ~0 frente al~0.025predeterminado de tokenbf_v1. - Mayúsculas y CJK en tokenizadores nuevos; tokenbf_v1 no segmentaba Unicode.
B (tokenbf_v1) sigue siendo correcto antes de 26.2 y puede coexistir durante un rollover. A (minmax) sirve para columnas numéricas/fecha monotónicas. D (bloom_filter sin tokenizar) solo ayuda a igualdad de string completo, como WHERE Body = 'an exact full string', no subcadenas.
Modelo mental: para texto/subcadenas en String, text en 26.2+ y tokenbf_v1 en clústeres antiguos; para igualdad de un string de alta cardinalidad como TraceId, bloom_filter.
P13. Por qué ClickHouse no incluye un índice invertido como ES — B
Es un punto de diseño diferente, no una función ausente. Ambos permiten predicados de texto, optimizados para accesos distintos.
Índice invertido de Elasticsearch
Lucene lo usa como ruta primaria:
- Granularidad: por documento; guarda
token → posting list of (doc_id, term_frequency, positions). - Finalidad: encuentra documentos reales, no candidatos.
- Ranking integrado: BM25 / TF-IDF.
- Obligatorio por defecto: todo campo
textpaga el coste. - Almacenamiento: normalmente 30–50 % del documento.
- Semántica rica: frases con slop, Levenshtein, boosting y DSL de scoring.
Índice text de ClickHouse (GA en 26.2)
Este índice text sigue siendo opcional.
Índice de salto sobre almacenamiento columnar:
- Granularidad: por gránulo (8192 filas). Indica que «podría contener token X», no qué filas.
- Finalidad: poda gránulos y después aplica
LIKEfila a fila. - Sin ranking. Devuelve en orden de almacenamiento; sin BM25/TF-IDF.
- Opcional: DDL explícita en una columna.
- Almacenamiento: ~1–5 % de la columna, postings por gránulo.
- Semántica:
LIKE,ILIKE,hasToken, regex; sin fuzzy ni scoring.
Recorrido de WHERE Body LIKE '%timeout%' sobre 1.000 millones de filas
| Paso | Elasticsearch | ClickHouse |
|---|---|---|
| 1 | Tokeniza 'timeout' → [timeout] | Igual |
| 2 | Busca el token y obtiene 2,3 M de doc IDs | Recorre el índice; quizá 5 K de 122 K gránulos contienen timeout |
| 3 | Obtiene documentos, puntúa y ordena | Lee columnas de 5 K gránulos (~41 M filas) |
| 4 | (ninguno) | Aplica LIKE '%timeout%' y obtiene ~2,3 M |
| Coste dominante | Recorrer postings | Explorar filas candidatas (~24× menos datos que sin índice) |
Cuándo gana cada uno
| Caso | Mejor | Motivo |
|---|---|---|
| Búsqueda de productos ("running shoes $40–80") | ES | El ranking es esencial |
| Autocompletado de documentación | ES | Fuzzy, frases y autocomplete |
| Logs («errores 5xx con timeout en una hora») | CH | Filtrar y agregar miles de millones; ranking irrelevante |
| Seguridad («alerta por malicious_pattern») | CH | Exploración con poda |
| «100 logs más relevantes para texto libre» | ES | CH no puntúa |
«Suma bytes_transferred donde path coincide /api/.* en 90 d» | CH | Domina la agregación |
Resumen para el cliente
Ambos encuentran 'timeout'. La siguiente pregunta revela la diferencia:
- Tras encontrar coincidencias, ES pregunta «¿cómo las ordeno por relevancia?».
- ClickHouse pregunta «¿cuál es ahora la latencia p99 agrupada por servicio?».
Una disposición física no puede ser óptima para ambas: ES elige documentos + ranking; ClickHouse, columnas + analítica.
P14. Estrategia de evolución de esquema — B
Procede de la Decisión 3 del ADR de la Parte 2:
- Map por defecto conserva flexibilidad; una clave nueva llega a
LogAttributessin DDL. - Promover claves usadas a columnas cuando ≥30 % de filas la tienen y ≥2 dashboards/alertas la usan.
- Es no destructivo:
ALTER TABLE ... ADD COLUMN MATERIALIZED LogAttributes['X']permite coexistir a filas antiguas y nuevas.
A (JSON sin promoción) es flexible, pero sin vía rápida y ~2× más lento que Map en este volumen. C (una columna por atributo posible) falla con atributos nuevos. D no es migración.
P15. Contrapartida del muestreo — B
El muestreo por cola aplaza la decisión hasta recibir todos los spans y puede usar señales de la traza completa: ¿algún error? ¿latencia alta? tail_sampling_processor de OpenTelemetry es la implementación canónica; cuesta búfer y complejidad en el collector.
A (cabecera) decide al empezar, antes del error, incompatible con «conservar todas las trazas con error». C (por span) rompe la coherencia. D (sin muestreo) rara vez es viable con 1 millón de trazas/s.
En producción suele usarse cola con reglas: 100 % de errores, 5 % de lentas correctas y 0,1 % de rápidas correctas.
Guía de puntuación
| Puntuación | Significado |
|---|---|
| 14–15 | Has interiorizado ClickHouse y OTel; puedes dirigir una migración. |
| 11–13 | Aprobado; revisa las explicaciones falladas. Esquema y modelo de datos predicen mejor el éxito con clientes. |
| 8–10 | Al límite. Revisa las respuestas modelo de la Parte 2. |
| ≤ 7 | Repite los puntos didácticos antes de los escenarios aplicados. |