Este proyecto fue diseñado de forma didáctica para poder aprender y entender cómo funcionan los algoritmos de grafos como BFS, DFS y el de Prim. Para ello se utiliza la librería de Python llamada NetworkX y así realizar el análisis de los datos.
Por otro lado, se utiliza el proyecto como punto de partida para explorar qué es Neo4J, así como entender a nivel general el funcionamiento de las bases de datos orientadas a grafos. Es importante hacer la salvedad que únicamente es exploratorio y con fines de entendimiento, aplicando ideas creadas a partir de la indicación del entregable.
Se trabaja con una arquitectura de microservicios con el fin de emular un escenario lo más cercano a la realidad empresarial posible y que además permita la reutilización de segmentos de código en otros proyectos de exploración o incluso desarrollo más adelante.
El proyecto utiliza como base de datos a Neo4J, esto añade complejidad sin embargo exploramos términos avanzados que nos permiten comprender de forma introductoria el cómo funciona esta base de datos. Aparte del uso en Docker, se recomienda instalar Neo4J Desktop y ejecutar las consultas aquí compartidas, para visualizar la herramienta a nivel gráfico y familiarizarse con la misma.
graph-analysis/
│
├── common/ # Código compartido: logging, utils, etc.
│ └── logging_config.py # Configuración de logging global
│
├── ingest-service/ # Microservicio de exportación de datos desde Neo4j
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI app con endpoint /export-graph
│ │ ├── neo4j_client.py # Cliente Neo4j y consulta Cypher
│ │ └── schemas.py # Pydantic models (GraphEdge, etc.)
│ ├── Dockerfile
│ ├── README.md # Guía de microservicio
│ └── requirements.txt
│
├── maintenance-service/ # Microservicio para calculo de nodos en mantenimiento
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI app con endpoint /maintenance
│ │ ├── orchestrator.py # Orquestador del calculo (Aritmetica Modular)
│ │ └── schemas.py # Pydantic models
│ ├── data/
│ │ └── groups_map.json # Arreglo con ciclos de mantenimiento
│ ├── Dockerfile
│ ├── README.md # Guía de microservicio
│ └── requirements.txt
│
├── routing-service/ # Microservicio de cálculo de rutas
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI app con endpoint /route
│ │ ├── orchestrator.py # Lógica de orquestación de rutas
│ │ └── schemas.py # Pydantic models (RouteRequest, RouteResponse)
│ ├── Dockerfile
│ ├── README.md # Guía de microservicio
│ └── requirements.txt
│
├── graph-normalizer/ # Paquete reutilizable de carga y normalización
│ ├── __init__.py
│ ├── loader.py # Función que transforma JSON de ingest a NetworkX
│ └── algorithms/ # Implementaciones de BFS, DFS, Prim
│ ├── __init__.py
│ ├── bfs.py
│ ├── dfs.py
│ ├── full.py
│ └── prim.py
│
├── queries/ # Consultas para poblar datos de ejemplo
│ ├── README.md # Instrucciones de uso de Query's
│ ├── 01-nodos-clientes.cypher
│ ├── 02-nodos-cruces.cypher
│ └── 03-conexiones-bidireccionales.cypher
│
└── .env Este proyecto utiliza puertos consistentes tanto en modo local como Docker:
| Servicio | Puerto | URL | Descripción |
|---|---|---|---|
| Neo4j Browser | 7474 | http://localhost:7474 | Interfaz web de Neo4j |
| Neo4j Bolt | 7687 | bolt://localhost:7687 ó bolt://neo4j:7687 | Conexión de base de datos |
| ingest-service | 8001 | http://localhost:8001 | API de exportación de grafos |
| routing-service | 8002 | http://localhost:8002 | API de cálculo de rutas |
Ventaja: Puedes usar la misma configuración de Postman sin importar el modo de ejecución.
Para poder ejecutar la aplicación he instalado el subsistema de Linux para Windows WSL, la documentación está en la siguiente página:
https://learn.microsoft.com/es-es/windows/wsl/installInstalar Ubuntu en el Subsistema de Linux para Windows.
Luego configuramos el .env:
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password
INGEST_LOGFILE=ingest.logDescargar e instalar Docker Desktop para Windows. Importante: al ejecutar el instalador marcar la opción "Use the WSL 2 based engine". Además, seleccionar la distribución Ubuntu, tal como hicimos en nuestro WSL.
Una vez instalado Docker ir a: Configuración (Settings) → Recursos (Resources) → WSL Integration Enable integration with additional distros: "Ubuntu"
Guardar y reiniciar.
Para probar que todo esté en orden, abrir el terminal de Linux:
docker --version
# Debería devolvernos la versión de docker
Docker version 28.3.2, build 578ccf6
# Luego probamos el contenedor de bienvenida
docker run --rm hello-world
# Si hay un mensaje de bienvenida todo está listoTrabajaremos con entornos virtuales, así como realizaremos pruebas, instalaremos estas librerías:
sudo apt update
# Python y para crear entornos virtuales
sudo apt install python3 python3-venv python3-pip
# Para hacer bonito los JSON
sudo apt install jq
# Evita problemas con lectura de variables en Windows
sudo apt update && sudo apt install dos2unixCrear entorno virtual usando terminal de Linux:
# En la carpeta raíz
cd ~/ruta/a/graph-analysis
# Crea el entorno virtual
python3 -m venv .venv
# Activar entorno virtual
source .venv/bin/activate
# Para salir del entorno virtual
deactivateUn entorno virtual instala librerías únicamente en el entorno aislado, evitando instalarlas en el sistema operativo, minimizando así problemas de compatibilidad entre librerías. Es útil cuando se desarrollan distintos sistemas que pueden necesitar distintas librerías que no son compatibles entre sí.
Ahora sí, con el entorno virtual activado instalamos librerías:
# Primero actualiza pip
pip install --upgrade pip
# Instalar paso a paso según requirements.txt:
pip install -r ingest-service/requirements.txt
pip install -r routing-service/requirements.txtUsando la consola de Linux vamos a ejecutar los siguientes comandos:
# Ir a la raíz del proyecto
cd graph-analysis
# Normalizamos el .env para Unix
dos2unix .env
# Crea un repositorio persistente de los datos
mkdir -p ~/neo4j-data
# Cargue su .env en el terminal
set -o allexport
source .env
set +o allexport
# Verificar variable de entorno
echo "Password en shell: [$NEO4J_PASSWORD]"
# Levanta la instancia de neo4j
docker run -d --name neo4j-wsl \
-p 7474:7474 \
-p 7687:7687 \
-e NEO4J_AUTH="neo4j/$NEO4J_PASSWORD" \
-v ~/neo4j-data:/data \
neo4j:5.9Comandos clave, de ahora en adelante para levantar o frenar nuestra base de datos haremos lo siguiente:
# Levantar Base
docker start neo4j-wsl
# Detener Base
docker stop neo4j-wsl
# Ver Logs
docker logs -f neo4j-wslSí, es necesario levantar la base para que nuestro sistema funcione.
Si ha seguido los pasos a este punto tendremos una base de datos orientada a grafos levantada en Docker. Esta está vacía, pero tiene persistencia de datos, necesitamos poblar esta base para realizar nuestras pruebas.
Vamos a ir al README que se aloja dentro de "queries", seguimos los pasos, esto va a poblar con datos para nuestro ejemplo la base, se basan en un laboratorio universitario.
Debemos levantar los distintos microservicios. Primero, tenemos ingest-service, este microservicio lo que hace es conectarse a la base de datos de Neo4J y permitirnos realizar consultas a la base de datos.
Para levantar el microservicio:
# Ir a la raíz del proyecto
cd graph-analysis
# Activamos nuestro entorno virtual
source .venv/bin/activate
# Instalamos requerimientos si no lo hemos hecho
pip install -r ingest-service/requirements.txt
# Levantamos servidor
uvicorn ingest-service.app.main:app --reload --host 127.0.0.1 --port 8001Una vez levantado uvicorn abrimos otra consola sin cerrar la actual. Como recomendación, siempre renombro mis consolas para saber qué estoy haciendo en cada una, a esta le puse ingest-service. En la otra consola lo que vamos a probar es que la consulta funcione, por ende que exista conexión.
Para probar la conexión:
curl -s http://127.0.0.1:8001/export-graph | jq .Debería devolver los datos en formato JSON, a este punto ya tenemos que haber seguido las instrucciones dentro del README.md que está en queries.
Abrimos una nueva consola, ejecutamos lo siguiente:
# Ir a la raíz del proyecto
cd graph-analysis
# Activamos nuestro entorno virtual en esta nueva consola
source .venv/bin/activate
# Instalamos requerimientos si no lo hemos hecho
pip install -r routing-service/requirements.txt
# Levantamos servicio de rutas
uvicorn routing-service.app.main:app \
--reload --host 127.0.0.1 --port 8002Siguiendo todos los pasos podemos levantar el sistema de forma sencilla. Primero abrimos 3 consolas y las renombramos, todas en Linux (WSL):
- neo4j-docker
- ingest-server
- routing-service
docker start neo4j-wslcd graph-analysis
source .venv/bin/activate
uvicorn ingest-service.app.main:app --reload --host 127.0.0.1 --port 8001cd graph-analysis
source .venv/bin/activate
uvicorn routing-service.app.main:app \
--reload --host 127.0.0.1 --port 8002Creamos una carpeta, en mi caso la llamaré Graph Algorithms, creamos un nuevo Environment, le pondremos GraphAPI y usaremos las siguientes variables:
- host = 127.0.0.1
- ingest_port = 8001
- route_port = 8002
http://{{host}}:{{ingest_port}}/export-graph
Veremos un JSON con la información en nuestra base de datos o bien la tabla con los nodos y el peso de las aristas.

http://{{host}}:{{route_port}}/route
Definimos en el body (RAW) los parámetros que espera nuestro sistema:
{
"start": "A",
"end": "B",
"algo": "prim"
}Veremos un JSON con la información del path seguido por el algoritmo seleccionado.

Recordemos que la variable "algo" espera el algoritmo, ahí solo cambiamos cual queremos ejecutar:
- "bfs"
- "dfs"
- "prim"
El despliegue que hemos realizado a este punto ha sido manual, y es muy útil para comprender cómo funciona el sistema y qué operaciones realiza. Sin embargo, para simplificarlo y tener algo más robusto similar a lo que veríamos en un entorno empresarial, podemos desplegar el sistema en Docker mediante el uso de imágenes.
Primero, cambiaremos nuestro .env para que sea compatible con Docker y no el modo de pruebas locales, tenemos que descomentar NEO4J_URI=bolt://neo4j:7687 Para Docker y comentar NEO4J_URI=bolt://localhost:7687:
# NEO4J_URI=bolt://localhost:7687
NEO4J_URI=bolt://neo4j:7687 # Para Docker
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password_here
INGEST_LOGFILE=ingest.log
INGEST_SERVICE_URL=http://ingest-service:8001/export-graph
ROUTING_LOGFILE=routing.logGuardamos los cambios y estando en la carpeta raíz ejecutamos:
docker-compose up --buildNota: esto ejecutará la creación de imágenes, los servicios quedarán arriba, para frenarlos únicamente utilizar CTRL + C.
Una vez creados los contenedores podemos nuevamente levantar nuestro sistema con el siguiente comando:
docker-compose up -dTambién podemos verificar los servicios levantados con:
docker-compose psIncluso podemos abrir otra consola para monitorear los logs de nuestra aplicación:
docker-compose logs -f ingest-service routing-servicePodemos detener los servicios en cualquier momento con:
docker-compose downCuando ejecutemos en modo Docker, los puertos son los mismos, por lo que NO necesitas cambiar tu configuración de Postman. Las variables del environment siguen siendo:
- host = 127.0.0.1
- ingest_port = 8001
- route_port = 8002
Esto es así porque Docker mapea los puertos internos a los mismos puertos externos para mantener consistencia entre ambos modos de ejecución.
