Cuando escribes tres palabras en Google y la respuesta llega en una fracción de segundo, con tus faltas corregidas, no es una base de datos SQL la que examina miles de millones de páginas: es un índice invertido, un diccionario «palabra → páginas que la contienen». Elasticsearch y OpenSearch aplican exactamente este principio a tus propios datos. Y cuando Netflix te sugiere «a los que les gustó esto también les gustó…», o Facebook te propone un amigo de un amigo, son relaciones que se recorren, no filas que se filtran: ese es el trabajo de una base de datos de grafos como Neo4j.
| Quién | Herramienta | Para qué |
|---|---|---|
| Wikipedia | Elasticsearch | la barra de búsqueda de todos los artículos, en todos los idiomas, tolerante a faltas |
| Netflix, Uber, Slack | Elasticsearch + Kibana | miles de millones de líneas de registros por día, exploradas en tiempo real para encontrar un fallo en segundos |
| Stack Overflow, GitHub | Elasticsearch | la búsqueda full-text de preguntas, respuestas y código |
| Amazon | OpenSearch | el motor que Amazon creó y mantiene para mantener una versión 100% de código abierto, vendido como servicio gestionado en AWS |
| NASA | Neo4j | la base de «lecciones aprendidas» de 50 años de misiones, conectadas entre sí para encontrar un precedente en unos pocos saltos |
| Consorcio ICIJ (Panama Papers) | Neo4j | 11,5 millones de documentos y los vínculos entre sociedades pantalla, directivos y bancos, explorados en grafo por 370 periodistas |
| eBay, Walmart | Neo4j | recomendaciones en tiempo real: «los que compraron esto…», calculadas siguiendo las relaciones de compra |
Lo que estas empresas tienen en común: también tienen bases de datos SQL, para pagos, pedidos, facturas. Añaden un motor de búsqueda junto a los datos para buscar, y una base de grafos junto a los datos para conectar. Exacto lo que vas a montar en este laboratorio, en pequeño.
Imagina una gran escuela en línea. En recepción, una bibliotecaria encuentra en un segundo todos los cursos que hablan de «desplegar contenedores», incluso si escribiste «despliegue» sin tilde: eso es Elasticsearch. En la pared, pantallas muestran el tráfico del sitio en vivo, las páginas con error, los países de origen de los visitantes: eso es Kibana, que no almacena nada pero dibuja lo que contiene Elasticsearch. En la oficina de orientación, un consejero conoce los vínculos entre la gente: quién ha seguido qué, qué curso es requisito de cuál, qué estudiantes se parecen: eso es Neo4j. ¿Y OpenSearch? Es la bibliotecaria gemela, formada en la misma escuela que Elasticsearch, contratada por quienes quieren un contrato 100% de código abierto. Cuatro herramientas, dos formas de organizar la información: por palabras (motor de búsqueda) o por vínculos (grafo).
| Herramienta | Versión del lab | Función | Hablas con ella mediante |
|---|---|---|---|
| Elasticsearch | 9.5.3 | almacena documentos JSON y los recupera por texto, filtros, agregaciones | Query DSL (JSON), ES|QL |
| Kibana | 9.5.3 | interfaz web de Elasticsearch: Dev Tools, Discover, Lens, dashboards | clics, KQL, Dev Tools para JSON |
| OpenSearch (+ Dashboards) | 3.8.0 | fork de código abierto de Elasticsearch y Kibana, misma API al 95% | misma Query DSL, además SQL y PPL |
| Neo4j Community | 5.26 | base de datos de grafos: nodos, relaciones, propiedades | Cypher |
Elasticsearch y OpenSearch comparten el mismo motor interno, Apache Lucene, y el mismo principio: el índice invertido. En lugar de leer cada documento en cada búsqueda, el motor construye una vez para siempre un diccionario «palabra → lista de documentos que la contienen». Buscar «docker kubernetes» es entonces cruzar dos listas de identificadores, lo que toma milisegundos en millones de documentos. Neo4j hace una apuesta opuesta: almacena las relaciones como punteros físicos entre nodos, por lo que «los amigos de mis amigos» se calcula siguiendo flechas, sin uniones.
Cada motor inventa sus palabras, pero a menudo designan la misma idea que en una base relacional. Esta tabla traduce los términos básicos entre SQL clásico, motores de búsqueda y grafos.
| SQL clásico | Elasticsearch / OpenSearch | Neo4j (grafo) | En claro |
|---|---|---|---|
| base de datos | cluster (conjunto de índices) | base de grafos | todo el contenido gestionado por el servidor |
| tabla | índice | etiqueta de nodo (label) | una colección de elementos del mismo tipo |
| fila / registro | documento (JSON) | nodo | un elemento |
| columna | campo (field) | propiedad | un atributo del elemento |
| esquema / DDL | mapping | esquema flexible (opcional) | la definición de los tipos de campos |
| clave primaria | _id del documento | identidad del nodo | el identificador único |
| clave foránea + unión | sin unión: curso_id desnormalizado | relación (-[:REQUISITO_DE]->) | el vínculo entre dos elementos |
| índice (B-tree) de aceleración | índice invertido | índice en una propiedad | la estructura que acelera la búsqueda |
SELECT … WHERE | Query DSL (JSON), ES|QL | MATCH … WHERE … RETURN | interrogar los datos |
GROUP BY / agregado | agregaciones (aggs) | count(), collect() | agrupar y contar |
| SQL (lenguaje) | Query DSL / ES|QL / KQL | Cypher | el lenguaje de consulta |
Cuidado con la palabra «índice». En SQL, un índice es una estructura de aceleración (B-tree) aplicada a una tabla. En Elasticsearch, un índice es el equivalente de la tabla misma. Y el índice invertido es algo completamente diferente: el mecanismo interno «palabra → documentos» que hace la búsqueda instantánea. Tres significados para una palabra.
Tomemos tres conceptos de nuestra escuela: cursos, estudiantes, reseñas dejadas por estudiantes en cursos.
1. En SQL (tablas y uniones) — tres tablas normalizadas, la información nunca se duplica, los vínculos van por claves foráneas:
SELECT c.titulo, AVG(a.nota)
FROM cursos c
JOIN resenas a ON a.curso_id = c.id
JOIN estudiante e ON e.id = a.estudiante_id
WHERE e.ciudad = 'Montreal'
GROUP BY c.titulo;Perfecto para coherencia (una nota modificada se modifica en todas partes), peor para «todos los cursos cuya descripción contiene desplegar»: LIKE '%desplieg%' examina toda la tabla.
2. En documentos (Elasticsearch / OpenSearch) — un curso es un solo documento JSON que contiene lo que la búsqueda necesita, incluido el nombre del profesor y el promedio de calificación ya calculado. Aquí, tal como es, el primer documento del índice cursos del laboratorio:
{
"id": "C0001",
"titulo": "Docker explicado simplemente",
"descripcion": "En este curso sin requisitos previos, aprendes a automatizar tus aplicaciones con Docker. …",
"categoria": "DevOps", "tema": "Docker", "nivel": "principiante", "idioma": "es",
"precio": 129, "gratis": false, "duracion_horas": 5,
"tags": ["docker", "linux", "helm", "devops"],
"fecha_publicacion": "2024-08-14",
"promedio_nota": 4.4, "num_resenas": 327,
"profesor": { "id": "P001", "nombre": "Karim Caron", "ciudad": "Gatineau" },
"competencias": ["Containerización", "Integración continua"]
}El nombre del profesor está desnormalizado (copiado en cada curso). Si cambia de nombre, hay que reindexar sus cursos: ese es el precio de la búsqueda instantánea. Las reseñas viven en un segundo índice, resenas, con curso_id en un campo simple, sin posibilidad de unión en el momento de la consulta.
3. En grafo (Neo4j) — los mismos conceptos se convierten en nodos, y los vínculos se convierten en relaciones de primera clase que llevan ellas mismas propiedades. Aquí, tres relaciones reales del grafo del laboratorio alrededor del curso C0001:
(:Estudiante {nombre: "Hugo"})-[:INSCRITO_EN {progreso: 100, nota: 4}]->(:Curso {id: "C0001", titulo: "Docker explicado simplemente"})
(:Curso {id: "C0001"})-[:REQUISITO_DE]->(:Curso {id: "C0003", titulo: "Docker: la guía completa"})
(:Profesor {nombre: "Karim", apellido: "Caron"})-[:ENSEÑA]->(:Curso {id: "C0001"})La pregunta «¿qué cursos han seguido los estudiantes que les gustó el mismo curso que a mí?» se escribe en una línea de Cypher y se calcula siguiendo tres relaciones, donde SQL encadenaría tres uniones y Elasticsearch simplemente no sabría responder.
| Pregunta | Mejor herramienta | Por qué |
|---|---|---|
| «cursos sobre desplegar contenedores, tolerante a faltas» | Elasticsearch / OpenSearch | índice invertido, analizador español, fuzzy |
| «distribución de errores 500 por país en 30 días» | Elasticsearch + Kibana | agregaciones y visualización en tiempo real |
| «ruta de requisitos para llegar al curso C0230» | Neo4j | recorrido de relaciones, camino más corto |
| «recomendar un curso basándose en inscripciones similares» | Neo4j | filtrado colaborativo = motivo de grafo |
| «pago, factura, coherencia estricta» | SQL (fuera del lab) | transacciones ACID |
En la vida real, los registros llegan continuamente (Filebeat, Logstash o la aplicación misma) y la base de grafos se alimenta del sistema empresarial. En el laboratorio, dos comandos reemplazan todo: importar envía archivos NDJSON a la API _bulk de Elasticsearch, cargar-grafo ejecuta un script Cypher que lee CSV. Los dos mundos no se comunican entre sí: tú, o tu aplicación, eliges a quién plantear cada pregunta.
Nada que escribir en esta lección: el laboratorio se inicia en la lección 03. Los extractos abajo fueron tomados del laboratorio del curso, para que sepas qué vas a encontrar dentro.
El conjunto de datos: una plataforma de cursos en línea. Un solo universo alimenta los tres motores, para comparar qué hace mejor cada uno.
| Conjunto | Volumen exacto | Contenido |
|---|---|---|
índice cursos | 504 documentos | título, descripción (analizador español), categoría, tema, nivel, precio, etiquetas, promedio de nota, profesor |
índice resenas | 609 documentos | nota de 1 a 5, texto, nombre, ciudad, país, fecha, votos «útil» |
índice acceso | 12 000 líneas | registros web del 2026-08-10 al 2026-09-08: ruta, estado HTTP, IP, país, dispositivo, referente |
| grafo Neo4j | 872 nodos · 3 712 relaciones | Cursos 504, Estudiante 300, Profesor 30, Competencia 22, Ciudad 16 |
Lo que hay que ver: los 504 cursos del grafo son los mismos que en el índice cursos (mismos identificadores C0001…C0504). Podrás buscar un curso en Elasticsearch y luego explorar sus requisitos en Neo4j.
Las categorías están perfectamente equilibradas. Una agregación términos en categoría devuelve:
Nube 84 · DevOps 84 · Datos 84 · Desarrollo web 84 · IA 84 · Seguridad 84Y en otros campos: nivel → principiante 252, avanzado 158, intermedio 94 ; idioma → es 375, en 129 ; gratis → 75 cursos gratis ; 72 temas distintos (Docker, Kubernetes, Elasticsearch, Neo4j, React, AWS…) ; 30 profesores. Lo que hay que ver: números redondos y conocidos de antemano, útiles para verificar tus consultas de los módulos 2 y 3.
Una reseña, tal como se almacena. Primer documento del índice resenas:
{ "id": "A00001", "curso_id": "C0028", "estudiante": "Nathan", "ciudad": "Sherbrooke", "pais": "Canada",
"nota": 3, "texto": "Los videos son buenos, la parte teórica es densa.", "fecha": "2024-06-21", "util": 33 }Lo que hay que ver: curso_id es una simple cadena. Ninguna unión conecta esta reseña con su curso en Elasticsearch; es tu aplicación quien hace el vínculo.
Una línea de registro. La más reciente del índice acceso:
{ "id": "L012000", "@timestamp": "2026-09-08T23:39:29.000Z", "metodo": "GET", "ruta": "/cursos/C0430",
"curso_id": "C0430", "categoria": "Nube", "estado": 200, "bytes": 168403, "duracion_ms": 351,
"ip": "169.199.97.7", "pais": "CA", "dispositivo": "escritorio", "navegador": "Chrome", "referente": "directo" }De las 12 000 líneas: 10 829 en 200, 403 en 404, 355 en 301, 235 en 304, 122 en 500, 56 en 503. Lo que hay que ver: el campo @timestamp, esencial en Kibana Discover para el eje temporal (módulo 4).
El grafo, contado por etiqueta y tipo de relación. Resultado real de dos consultas Cypher:
Cursos 504 · Estudiante 300 · Profesor 30 · Competencia 22 · Ciudad 16
INSCRITO_EN 1654 · CUBRE 994 · ENSEÑA 504 · VIVE_EN 330 · REQUISITO_DE 230Lo que hay que ver: 1 654 inscripciones para 300 estudiantes, aproximadamente 5,5 cursos por estudiante. Este es el malla que hará interesantes las recomendaciones del módulo 7.
«Conozco SQL, ¿por qué no hacerlo todo con PostgreSQL?» → Puedes, hasta cierto punto. PostgreSQL sabe hacer búsqueda full-text y consultas recursivas. Pero en el momento en que quieras tolerancia a faltas, ranking por relevancia, agregaciones en millones de líneas en tiempo real o recorridos de grafo con profundidad variable, cada motor especializado hace el trabajo en milisegundos donde SQL requiere índices exóticos y consultas ilegibles. El buen reflejo: SQL para la fuente de verdad transaccional, Elasticsearch a un lado para buscar, Neo4j a un lado para conectar.
«¿Elasticsearch u OpenSearch, debo elegir ahora?» → No. El curso te hace trabajar en Elasticsearch; el módulo 5 replantea las mismas consultas en OpenSearch y lista las diferencias (solo un puñado). Lo que aprendes vale para ambos.
«¿Kibana es una base de datos?» → No, y es confusión frecuente. Kibana solo almacena tu configuración (dashboards, vistas) en un índice oculto de Elasticsearch. Todos los datos que ves vienen de Elasticsearch; si Elasticsearch se detiene, Kibana muestra «Kibana server is not ready yet» (lección 04).
La palabra «índice» designa dos cosas diferentes: en SQL, una estructura de aceleración (B-tree) adjunta a una tabla ; en Elasticsearch, el equivalente de la tabla misma, dividida en shards (índices Lucene autónomos). El módulo 2, lección 01, retoma este vocabulario en práctica en el laboratorio.