- Mariana Luna Rocha, estudiante de la Licenciatura en Ciencia de Datos en el ITAM.
- Carlos Elías Rivera Mercado, estudiante de la Licenciatura en Ciencia de Datos en el ITAM.
- Mauricio Vázquez Moran, estudiante de la Licenciatura en Ciencia de Datos y Licenciatura en Actuaría en el ITAM.
Muestrar el entendimiento y capacidad de manejo de las diferentes bases de datos que fueron vistas en el semestre, así como los conceptos relacionados con API’s, ETL’s, etc.
Mediante alguna API, de interes para los integrantes del equipo, conectarla, através de python, con una base de datos en MongoDB. Posteriormente, se tiene que hacer un ETL que cargue la base de datos procesada una base de datos estilo grafo, es decir, en Neo4j. Evidentemente, las transformaciones y los subconjuntos de datos ocupados serán diferentes para cada base de datos ya que tienen fines diferentes cada una.
El proyecto debe ser lo más reproducible posible. Por lo cual, se debe de entregar un repositorio completo en github, con los scripts de carga y un Readme.md a manera de instructivo de cómo usar las utilerías implementadas. Además, se requieren al menos 3 queries interesantes, con respecto a cada base de datos (6 en total), que expliquen un poco más el fenómeno del cual la base de datos, está representando.
Para la inserción de todos los personajes del mundo de Harry Potter, conectamos con la API PotterDB a través del script de python 'PotterScript'. Por medio de la libreria 'requests', hacemos llamados a la API, antes mencionada, y absorvemos la informacion localmente. Una vez que hemos logrado obtener todos los documentos de tipo 'json' de la PotterDB API, son mandados a una base de datos no relacional a MongoDB bajo el nombre de 'characters'.
Para la extraccion, transformacion y carga de los datos obtenidos de la API, se siguieron los siguientes pasos en la limpieza de datos:
- Se extraen los datos apoyandonos en la libreria 'request'. Por medio de sencillas iteraciones, iteramos sobre las diferentes paginas de la API extrayendo los documentos tipos 'json'. Obtenemos como total 4066 documentos, correspondientes a los personajes de la saga Harry Potter.
- Hacemos una primera importacion a MongoDB, bajo el nombre de la coleccion 'characters' en la base de datos 'potter'.
- Apoyandonos de un pipeline desde python hacia MongoDB, limpiamos los id de los personajes para no tener problemas en la posterioridad del ETL.
- Habiendo mandado los documentos a MongoDB, absorbemos los archivos 'json' en python y verificamos que esten correctos los id.
- Por medio de la libreria 'pandas', mandamos los documentos a un dataframe para simplificar y agilizar su transformacion.
- Revisamos las columnas del dataframe y soltamos las columnas que no nos son de utilidad. En otras palabras, dropeamos los metadatos que venian con los documentos desde la API.
- Limpiamos los nombres de nuestras variables, es decir, los nombres de nuestras columnas. En este mismo paso, revisamos los tipos de datos que tenemos en las diferentes variables para su transformacion en el correcto data type.
- Revisamos los na's que contiene el dataframe. Utilizamos la estrategia de sustituir los na's por el valor de 'missing'. Bajo este mismo paso y con miras de hacer una base de tipo grafo en Neo4j, sustituimos los na's, en algunas variables, por valores provenientes de otros caracteres y, de esta manera, poder crear los grafos para su posterior carga en Neo4j.
- Con la utilizacion de una funcion auxiliar, retiramos los caracteres no desados de las cadenas de texto. Asimismo, normalizamos las cadenas de string para que en la posteriedad el analisis de esta base de datos sea con mayor facilidad.
- Se instancian las casas, generos y blood status de los personajes faltantes. Esto con el fin de poder visualizar y poder especializar los queries en Neo4j y MongoDB. En este mismo paso
- Se instancian los csv para su posterior insercion en Neo4j.
Correr los siguientes comandos en la terminal de Neo4j para la insercion de los documentos:
Carga de house csv:
load csv with headers from "https://raw.githubusercontent.com/MauricioVazquezM/NoSQL_Spring2023_Final_Project/main/DATA/houses_ids.csv" as row
fieldterminator '\t'
create (n: Houses)
set n = row
Carga de genero csv:
load csv with headers from "https://raw.githubusercontent.com/MauricioVazquezM/NoSQL_Spring2023_Final_Project/main/DATA/gender_ids.csv" as row
fieldterminator '\t'
create (n: Genres)
set n = row
Carga de especie csv:
load csv with headers from "https://raw.githubusercontent.com/MauricioVazquezM/NoSQL_Spring2023_Final_Project/main/DATA/species_ids.csv" as row
fieldterminator "\t"
create (n: Species)
set n = row
Carga de blood status csv:
load csv with headers from "https://raw.githubusercontent.com/MauricioVazquezM/NoSQL_Spring2023_Final_Project/main/DATA/bs_ids.csv" as row
fieldterminator "\t"
create (n: Blood_status)
set n = row
Carga de characters csv:
load csv with headers from "https://raw.githubusercontent.com/MauricioVazquezM/NoSQL_Spring2023_Final_Project/main/DATA/characters.csv" as row
fieldterminator "\t"
create (c:Characters)
set n = row
Correr los siguientes comandos en la terminal de Neo4j para el establecimiento de las relaciones del grafo:
Insercion de la relacion de characters con sus respectivas casas:
match (c:Characters), (h: Houses)
where c.idhouses = h.idcasas
create (c)-[:BELONGS_TO]->(h)
Insercion de la relacion de characters con su blood status:
match (c:Characters), (b: Blood_status)
where c.idsangre = b.idsangre
create (c)-[:HAS_BLOOD_STATUS_OF]->(b)
Insercion de la relacion de characters con su genero:
match (c:Characters), (g:Genres)
where c.idgender = g.idgen
create (c)-[:IS]->(g)
Insercion de la relacion de characters con su especie:
match (c:Characters), (s:Species)
where c.idspecies=s.idsp
create (c)-[:IS_A]->(s)
Query que obtiene las alturas de todos los personajes que sean hombres humanos o las mujeres elfas. Ademas, ordena descendientemente:
db.char.aggregate([
{
$match: {
$or: [
{ "attributes.species": "Human", "attributes.gender": "Male" },
{ "attributes.species": "Elf", "attributes.gender": "Female" }
],
"attributes.height": { $exists: true }
}
},
{
$project: {
_id: 0,
name: "$attributes.name",
species: "$attributes.species",
gender: "$attributes.gender",
height: "$attributes.height"
}
},
{
$sort: { height: -1 }
}
])
Query para obtener cuantos elfos de casa hay por nacionalidad:
db.char.aggregate([
{
$match: {
"attributes.nationality": { $exists: true, $ne: "" },
"attributes.species": { $ne: "House-elf" }
}
},
{
$group: {
_id: "$attributes.nationality",
characterCount: { $sum: 1 }
}
},
{
$sort: { characterCount: -1 }
}
])
Query que cuenta los humanos que asistieron a Howarts y luego por su color de ojos los agrupa con su correspodiente contador:
db.char.aggregate([
{
$match: {
"attributes.eye_color": { $exists: true, $ne: "" },
"attributes.species": "Human",
"attributes.house": { $in: ["Ravenclaw", "Slytherin", "Hufflepuff", "Gryffindor"] }
}
},
{
$group: {
_id: "$attributes.eye_color",
characterCount: { $sum: 1 }
}
},
{
$sort: { characterCount: -1 }
}
])
Query que cuenta por casas cuantos miembros tiene cada casa:
match (c:Characters)-[:BELONGS_TO]->(h:Houses)
return c.house as house, count(c.house) as house_count
order by house;
Query que cuenta, por cada casa, los humanos que tiene ojos azules:
match (c: Characters)-[:BELONGS_TO]->(h:Houses), (c)-[:IS_A]->(s:Species)
where c.eye_color = "blue" and s.especie = "human"
return c.name as charactername, c.eye_color as eyeColor, h.casas as houseName, s.especie as speciesName
Query que cuenta por casa los humanos que siguen vivos y los ordena de manera ascendente:
match (c:Characters)-[:BELONGS_TO]->(h:Houses), (c:Characters)-[:IS_A]->(s:Species)
where c.died <> "missing" and s.especie = "human"
return c.house as casa, count(c.house) as house_count
order by house_count
Para la ejecucion del proyecto se tiene que seguir las siguientes instrucciones:
- Correr el script 'PotterScript' para la extraccion, transformacion y carga de los datos en MongoDB.
- Abrir terminal de Neo4j y correr los comandos de insercion en Neo4j de los csv Carga de los csv. Posteriormente, insertar las relaciones del grafo de la seccion Haciendo las relaciones.
- Si se quiere, correr los queries propuestos en Queries para mas informacion sobre la API. Se tiene 3 queries para MongoDB y 3 queries para Neo4j.