Capítulo 4. Carga de datos del grafo de conocimiento
Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com
En el Capítulo 3 te familiarizaste con las bases de datos de grafos y los lenguajes de consulta, e incluso aprendiste un poco sobre el funcionamiento interno de las bases de datos. También viste cómo consultar y actualizar grafos de conocimiento. Pero hay un caso especial de actualización que merece una mayor profundización: las importaciones masivas, que son útiles a lo largo de todo el ciclo de vida de un grafo de conocimiento.
Consejo
Para cada una de las técnicas de este capítulo, tiene sentido empezar poco a poco. Toma una pequeña porción representativa de tus datos e impórtala en la base de datos. Comprueba que el modelo funciona según lo previsto antes de ejecutar el trabajo de importación completo. Una comprobación rápida puede ahorrarte minutos u horas de frustración.
En este capítulo, aprenderás tres formas de cargar datos en bloque en un gráfico de conocimiento. Aprenderás cómo cargar datos en bloque de forma incremental en un gráfico de conocimiento activo y cómo arrancar un gráfico de conocimiento con grandes cantidades de datos. Pero primero aprenderás a utilizar una herramienta gráfica para definir la estructura de un gráfico de conocimiento y asignar datos a esa estructura para importaciones en bloque.
Cargar datos con el importador de datos Neo4j
Deberías empezar por la más sencilla de las tres herramientas populares para la carga masiva de datos de Neo4j. El Importador de datos de Neo4j es una herramienta visual que te permite dibujar tu modelo de dominio como un gráfico y luego superponer datos sobre ese gráfico, con archivos de valores separados por comas (CSV) que contienen los datos de tus nodos y relaciones.
El Importador de Datos simplifica enormemente la creación de tu gráfico de conocimiento, especialmente para los principiantes. Sin embargo, sigue requiriendo que tengas tus datos en archivos CSV listos para usar.
Para que los ejemplos sean breves, utilizarán los datos de las redes sociales que viste en los Capítulos 1 y 3. Ten en cuenta que este sencillo ejemplo funciona, ¡pero las importaciones reales suelen utilizar archivos mucho más grandes!
En primer lugar, dibuja la red social. El diagrama de la Figura 4-1 muestra el modelo de dominio, formado por los nodos Person
y Place
y las relaciones FRIEND
y LIVES_IN
.
En primer lugar, añade tus archivos CSV como los que se muestran en los Ejemplos 4-1, 4-2, 4-3 y 4-4, buscándolos en el panel izquierdo de la herramienta. Dibuja los nodos y las relaciones que constituyen el modelo de dominio utilizando las sencillas herramientas de dibujo, y anota cada uno de ellos utilizando el panel de detalles de mapeo de la derecha.
Ejemplo 4-1. people.csv
datos para los nodos Person
en el Importador de datos Neo4j
:ID(Person),name 23,Rosa 42,Karl 55,Fred
En el Ejemplo 4-1, el ID del nodo y su etiqueta se especifican como :ID(Person)
con una única propiedad name
. En las filas siguientes, puedes ver datos que coinciden con ese patrón, como 23,Rosa
. Ten en cuenta que la columna ID
se utiliza posteriormente para unir el grafo; no forma parte (necesariamente) del modelo de dominio y puede eliminarse del modelo más adelante.
Ejemplo 4-2. friends.csv
para relaciones FRIEND
entre nodos Person
en el Importador de Datos Neo4j
:START_ID(Person),:END_ID(Person) 23,42 42,23 42,55 55,42
En el Ejemplo 4-2, los ID inicial y final de los nodos Person
se especifican con :START_ID(Person),:END_ID(Person)
. Tienes una relación que va de un nodo Person
representado como un ID a otro. En cada fila puedes ver los ID correspondientes de los nodos inicial y final de una relación FRIEND
, que coincide con los datos del Ejemplo 4-1.
El Ejemplo 4-3 sigue el mismo patrón que el Ejemplo 4-1, pero para los nodos Place
en lugar de los nodos Person
. La cabecera especifica que habrá un ID
para los nodos Place
, seguido de las propiedades city
y country
que se escribirán en cada uno de esos nodos.
Ejemplo 4-3. places.csv
datos para los nodos Place
en el Importador de Datos Neo4j
:ID(Place),city,country 143,Berlin,Germany 244,London,UK
Por último, el Ejemplo 4-4 declara las relaciones LIVES_IN
entre los nodos Person
y Place
. La cabecera especifica el ID de los nodos Person
como inicio de la relación, el ID de los nodos Place
como final de la relación, y una propiedad opcional since
sobre la relación. A continuación, los datos CSV siguen ese patrón.
Ejemplo 4-4. lives_in.csv
para LIVES_IN
relaciones entre los nodos Person
y Place
en el Importador de Datos Neo4j
:START_ID(Person),:END_ID(Place),since 23,143,2020 55,244 42,244,1980
Con estos archivos CSV, ya puedes ejecutar el Importador de datos de Neo4j. Se ejecuta contra una base de datos activa, por lo que necesita un punto final y credenciales para funcionar. Una vez que el Importador de datos se haya ejecutado correctamente, recibirás un informe de importación como el que se muestra en la Figura 4-2.
En la Figura 4-2, puedes ver algunos de los scripts de Cypher que se han ejecutado contra la base de datos junto con las estadísticas de la importación. Un puñado de modismos comunes de Cypher destacan del informe: CREATE CONSTRAINT
, UNWIND
, y MERGE
. Aquí debes utilizar UNWIND
para introducir filas de datos CSV en una operación MERGE
que crea un nodo Person
con una propiedad ID
. A continuación, escribe una propiedad since
en ese nodo utilizando SET
. Si no hay ninguna propiedad since
para ninguna fila, eso no es un problema porque SET
tolera la ausencia de datos para esas relaciones.
Consejo
UNWIND
es una cláusula Cypher que toma una lista de valores y los transforma en filas que se introducen en sentencias posteriores. Es una forma muy común de manejar datos de entrada, y la verás con frecuencia en este capítulo. Su forma habitual es
UNWIND [1, 2, 3, null] AS x RETURN x
donde los valores 1
, 2
, 3
, y null
se devolverán como filas individuales a la persona que llama.
UNWIND
se utiliza de nuevo para introducir los datos de relación del Ejemplo 4-4 en el gráfico, como se muestra en la Figura 4-3.
También en la Figura 4-3, puedes ver cómo se utiliza una combinación de MERGE
y MATCH
. Recuerda que en el Capítulo 3 utilizaste MERGE
cuando no estaba claro si existía o no un nodo o una relación, ya que MERGE
actúa como MATCH
cuando existe un registro y como CREATE
cuando no.
Aquí no necesitas MERGE
para los nodos Person
y Place
porque está garantizada su existencia en el archivo CSV de entrada. En su lugar, sólo necesitas MERGE
la relación LIVES_IN
entre esos nodos existentes, donde MERGE
garantizará que no haya relaciones duplicadas.
Por supuesto, podrías escribir el Cypher equivalente a mano y ejecutarlo como un conjunto de scripts, y tendría el mismo efecto (como en la sección siguiente, "Carga masiva de datos en línea con LOAD CSV"). También podrías tomar este Cypher y tratarlo como una fuente generada automáticamente, que podría modificarse y alojarse en el control de fuentes para que pueda evolucionar a medida que el grafo de conocimiento crece con el tiempo.
El Importador de datos de Neo4j te da una ventaja no sólo con el código Cypher para la ingestión, sino también visualizando, verificando y depurando el modelo y los datos que fluirán en él antes de iniciar la importación. Como tal, es valioso para los desarrolladores experimentados de Neo4j , así como para la gente que es nueva en las bases de datos gráficas.
Carga masiva de datos en línea con CARGAR CSV
En el Capítulo 3 viste cómo crear (y actualizar) registros en la base de datos utilizando los comandos Cypher CREATE
y MERGE
. En "Cargar datos con el importador de datos Neo4j", aprendiste cómo una herramienta visual genera código Cypher que luego carga datos CSV en una base de datos activa.
Pero hay otra forma de programar importaciones de CSV: utilizando el comando LOAD CSV
de Cypher.LOAD CSV
te permite importar datos CSV a un gráfico en línea desde diversos lugares. Puedes cargar datos CSV a través de direcciones web (como cubos de Amazon S3 o Google Sheets) y sistemas de archivos, y las importaciones de LOAD CSV
se producen mientras la base de datos está activa y sirviendo otras consultas. Afortunadamente, los archivos CSV también se pueden comprimir, lo que ayuda al transferir grandes cantidades de datos.
LOAD CSV
se explica de forma más sencilla con un ejemplo. Primero carga todos los nodos Place
de la red social utilizando LOAD CSV
. El archivo CSV utilizado está en el Ejemplo 4-5.
Ejemplo 4-5. Datos CSV de los nodos Place
city,country Berlin,Germany London,UK
Como los datos de lugar son uniformes, puedes utilizar un patrón sencillo de LOAD CSV
para insertar los nodos en el grafo de conocimiento, como se muestra en el Ejemplo 4-6.
Ejemplo 4-6. Sencillo LOAD CSV
para nodos Place
LOAD CSV WITH HEADERS FROM 'places.csv' AS line MERGE (:Place {country: line.country, city: line.city})
Aunque el Ejemplo 4-6 no es una solución completa para cargar el grafo de conocimiento (ya que sólo carga lugares), ejemplifica el patrón básico para utilizar LOAD CSV
. La primera línea se descompone como sigue:
-
LOAD CSV
es el comando Cypher que quieres ejecutar. -
WITH HEADERS
indica al comando que espere definiciones de cabecera en la primera línea del archivo CSV. Aunque las cabeceras son opcionales, suele ser una buena idea utilizarlas. Las cabeceras te permiten referirte a las columnas con un nombre amigable (en lugar de sólo con un índice numérico), como se muestra en la sentenciaMERGE
del Ejemplo 4-6. -
FROM 'places.csv'
indica al comando dónde encontrar los datos CSV. Ten en cuenta que puede ser necesario modificar los permisos de seguridad de Neo4j si quieres importar desde ubicaciones no predeterminadas del sistema de archivos o desde servidores remotos. -
AS line
vincula cada fila del archivo CSV a una variable en Cypher llamadaline
a la que se puede acceder posteriormente en la consulta.
Los datos sobre personas son mucho menos regulares. Lo único que se sabe de todas las personas es su nombre. De algunas personas, también puedes saber su sexo o su edad, como se muestra en el Ejemplo 4-7.
Ejemplo 4-7. Datos CSV de los nodos Person
name,gender,age Rosa,f, Karl,,64 Fred,,
Tener datos irregulares (como en el mundo real) significa que tienes que adoptar un enfoque ligeramente más sofisticado LOAD CSV
. Tendrás que cambiar el script para que sea como en el Ejemplo 4-8. Aquí puedes utilizar SET
para evitar escribir cualquier propiedad nula en el nodo, lo que provocaría el fallo de la operación. Si intentas utilizar el enfoque más sencillo del Ejemplo 4-6, la consulta fallará, quejándose de los valores de propiedad null
.
Ejemplo 4-8. LOAD CSV
más sofisticado para nodos irregulares Person
LOAD CSV WITH HEADERS FROM 'people.csv' AS line MERGE (p:Person {name: line.name}) SET p.age = line.age SET p.gender = line.gender
Por último, puedes añadir las relaciones LIVES_IN
y FRIEND
para vincular los nuevos nodos a un grafo de conocimiento (o vincularlos a nodos existentes si ya tienes un grafo de conocimiento). En el Ejemplo 4-9, las relaciones FRIEND
están codificadas en CSV de forma que, por ejemplo, hay una relación FRIEND
de Rosa
a Karl
y otra de Karl
a Fred
.
Ejemplo 4-9. FRIEND
relaciones en formato CSV
from,to Rosa,Karl Karl,Rosa Karl,Fred Fred,Karl
Consejo
Se trata de un ejemplo pequeño, por lo que los nombres de las personas son lo suficientemente únicos como para actuar como ID. Para una importación real, es poco probable que esto se mantenga, por lo que es sensato introducir ID numéricos únicos para los nodos. En términos prácticos, esto significaría añadir un ID entero incremental para cada fila de los archivos CSV de personas y lugares.
Puedes utilizar esos datos para crear relaciones FRIEND
(si no existen ya), como se muestra en el Ejemplo 4-10. Ten en cuenta que, como sabes que los nodos Person
ya han sido rellenados en el Ejemplo 4-9, puedes simplemente MATCH
y rellenar cualquier relación entre ellos utilizando MERGE
en el Ejemplo 4-10.
Ejemplo 4-10. Carga de relaciones FRIEND
LOAD CSV WITH HEADERS FROM "friend_rels.csv" AS line MATCH (p1:Person {name:line.from}), (p2:Person {name:line.to}) MERGE (p1)-[:FRIEND]->(p2)
Las relaciones LIVES_IN
son un poco más complicadas, ya que opcionalmente tienen propiedades since
. En el Ejemplo 4-11, la línea Fred,London,,
tiene una doble coma al final, lo que indica que no hay ningún valor en el campo since
. Hay que tener cuidado al manejar esta situación.
Ejemplo 4-11. LIVES_IN
relaciones en formato CSV
from,to,since Rosa,Berlin,2020 Fred,London,, Karl,London,1980
Para cargar los datos del Ejemplo 4-11, utiliza el código Cypher del Ejemplo 4-12. Observa que no estás utilizando MERGE (person)-[:LIVES_IN {since:line.since}]->(place)
para establecer el valor de la propiedad since
porque fallaría en las filas en las que se omitiera la propiedad. Una vez más, debes utilizar SET
después de crear el registro de la relación para añadir la propiedad. Esto está perfectamente bien porque la sentencia se ejecuta transaccionalmente, por lo que la relación y su propiedad se escribirán atómicamente a pesar de estar separadas sintácticamente.
Ejemplo 4-12. Carga de relaciones FRIEND
con datos de propiedades
LOAD CSV WITH HEADERS FROM "friend_rels.csv" AS line MATCH (person:Person {name:line.from}), (place:Place {city:line.to}) MERGE (person)-[r:LIVES_IN]->(place) SET r.since=line.since
En el caso de importaciones de datos muy grandes, por ejemplo de un millón de registros o más, suele ser conveniente dividir la operación en lotes más pequeños, para que la base de datos no se sature con grandes inserciones y las demás consultas del grafo de conocimiento funcionen sin problemas. Antes de Neo4j 4.4, utilizabas la función de la biblioteca APOC.4, utilizabas la función apoc.periodic.iterate
de la biblioteca APOC para este fin. A partir de Neo4j 4.4, una función similar está disponible directamente en Cypher mediante CALL {...} IN TRANSACTIONS OF ... ROWS
. Con este método puedes cambiar la carga de los nodos Person
en lotes más pequeños, como se muestra en el Ejemplo 4-13. En un sistema real, el número de filas y el número de lotes serían, por supuesto, mucho mayores.
Ejemplo 4-13. Carga de nodos People
por lotes (prefijo con :auto
si se ejecuta desde el Navegador Neo4j)
LOAD CSV WITH HEADERS FROM 'people.csv' AS line CALL { WITH line MERGE (p:Person {name: line.name}) SET p.age = line.age SET p.gender = line.gender } IN TRANSACTIONS OF 1 ROWS
Una de las cosas buenas de utilizar LOAD CSV
es que es Cypher normal, por lo que todo lo que has aprendido sobre Cypher se puede poner en práctica, incluyendo EXPLAIN
y PROFILE
para analizar, depurar y afinar la ingestión masiva. Por ejemplo, el plan de consulta simple para cargar relaciones FRIEND
se muestra en la Figura 4-4.
La Figura 4-4 tiene buen aspecto en general. Incluso el operador producto cartesiano (sobre el que te advertirá el Navegador Neo4j) no es un problema porque se alimenta de un filtro que reduce sus entradas a sólo dos nodos coincidentes y la línea CSV correspondiente. Por supuesto, puede que no siempre sea así, y utilizar EXPLAIN
o PROFILE
en una pequeña cantidad de datos de entrada representativos puede ayudar a resolver cualquier problema de rendimiento antes de que empiece.
Consejo
Además de los productos cartesianos, busca cualquier operador eager
en el plan o perfil de consulta. Los operadores ansiosos extraen todos los datos inmediatamente y a menudo crean un punto de estrangulamiento. Mark Needham tiene una excelente entrada en su blog sobre estrategias para eliminar los operadores ansiosos.
LOAD CSV
es rápido y puede utilizarse en cualquier momento del ciclo de vida de tu grafo de conocimiento. La base de datos permanece en línea durante las actualizaciones para poder procesar otras consultas. Sin embargo, puede requerir cierto ajuste para conseguir un buen rendimiento sin dominar las operaciones normales de la base de datos. Pero LOAD CSV
no es la última opción para inserciones masivas: tienes una más que añadir a tu conjunto de herramientas.
Carga masiva inicial
A menudo hay una importación inicial que arranca el grafo de conocimiento con cantidades potencialmente grandes de datos. Es factible utilizar el Importador de datos de Neo4j o LOAD CSV
para hacerlo, pero hay una forma más rápida, aunque de bajo nivel.
En realidad, la herramienta de línea de comandos de Neo4j neo4j-admin
tiene incorporado un importador offline. El comando neo4j-admin import
construye una nueva base de datos Neo4j a partir de un conjunto de archivos CSV. (Para profundizar más, hay un tutorial completo en neo4j-admin import
.)
La herramienta neo4j-admin
ingiere datos muy rápidamente, con un rendimiento sostenido de alrededor de un millón de registros por segundo, y cuenta con optimizaciones para dispositivos de alto rendimiento, como unidades SSD y redes de área de almacenamiento (SAN). Es un método de alto rendimiento para crear tus importaciones masivas a tu gráfico de conocimiento, con la salvedad de que la base de datos debe estar desconectada cada vez que se ejecuta.1
Advertencia
La salvedad de neo4j-admin import
es que es un importador fuera de línea, por eso es tan rápido. La base de datos estará lista para servir consultas del grafo de conocimiento en cuanto termine la importación, pero no estará disponible durante la construcción.
Para utilizar neo4j-admin import
, primero tienes que reunir tus datos en archivos CSV y colocarlos en un sistema de archivos al que pueda acceder el importador. El sistema de archivos no tiene por qué ser necesariamente local, puede ser un montaje de red. Sí tiene que ser un sistema de archivos, ya que neo4j-admin import
no leerá datos de, por ejemplo, buckets de S3 u otros almacenes de datos que no sean sistemas de archivos. Como los volúmenes de datos pueden ser grandes, la herramienta también admite archivos CSV comprimidos (gzipped).
Como mínimo, el importador espera que los archivos CSV se presenten como archivos separados para nodos y relaciones. Sin embargo, es una buena práctica tener archivos CSV separados para distintos tipos de nodos y relaciones, por ejemplo, dividiendo los nodos Person
y Place
y las relaciones FRIEND
y LIVES_IN
.
Los archivos muy grandes deben dividirse en varios archivos CSV más pequeños, con la propia cabecera CSV en un archivo aparte. Esto hace que la edición de texto de archivos grandes sea mucho menos dolorosa, ya que los archivos más pequeños son más cómodos para la edición de texto.
Consejo
No tienes que asegurarte de que los archivos CSV son perfectos, sólo de que están en buenas condiciones. El importador tolerará diferentes caracteres separadores, ignorará columnas adicionales, omitirá duplicados y relaciones erróneas, e incluso recortará cadenas por ti. Sin embargo, tendrás que asegurarte de que no haya caracteres especiales, comillas que falten, marcas de orden de bytes que no se vean y cosas por el estilo que puedan afectar al importador.
Empieza por preparar tus archivos CSV.El ejemplo 4-14 es un típico archivo CSV autocontenido. Tiene una fila de cabecera que define los nombres de las columnas y, a continuación, las filas de datos. La cabecera :ID(Person)
dice que la columna representa el ID de un nodo, y el nodo tiene la etiqueta Person
. Como ocurre con el Importador de datos de Neo4j, el ID no forma parte necesariamente del modelo de dominio, sino que la herramienta lo utiliza para enlazar nodos. La cabecera name
declara que la segunda columna es una propiedad llamada name
que se escribirá en el nodo actual.
Ejemplo 4-14. people.csv
contiene identificadores únicos para los nodos Person
y una propiedad name
para cada uno.
:ID(Person),name 23,Rosa 42,Karl 55,Fred
Aunque el Ejemplo 4-14 es autocontenido, para importaciones más grandes es más conveniente separar las cosas. Por ejemplo, para las relaciones FRIEND
entre nodos Person
, puedes dividir los archivos CSV en un archivo de cabecera que describa los datos y varios archivos de datos (normalmente grandes), como se muestra en los Ejemplos 4-15, 4-16 y 4-17. Esta separación facilita mucho la gestión de los datos, ¡ya que los cambios en la cabecera no implican abrir un archivo realmente grande en un editor de texto!
Ejemplo 4-15. friends_header.csv
contiene la firma de los datos de relación del patrón (:Person)-[:FRIEND]→(:Person)
:START_ID(Person),:END_ID(Person)
Ejemplo 4-16. friends1.csv
contiene el primer conjunto de datos de relación para los patrones (:Person)-[:FRIEND]->(:Person)
23,42 42,23
Ejemplo 4-17. friends2.csv
contiene el segundo conjunto de datos de relación para el patrón (:Person)-[:FRIEND]→(:Person)
42,55 55,42
El importador trata los Ejemplos 4-15, 4-16 y 4-17 lógicamente como una sola unidad, sin importar cuántos archivos haya en última instancia. Puedes utilizar la misma separación de intereses tanto para los nodos como para las relaciones.El Ejemplo 4-18 declara una cabecera CSV para los nodos Place
que tienen una etiqueta Place
y propiedades ID
, city
y country
. Los Ejemplos 4-19 y 4-20 contienen los datos formateados según la cabecera.
Ejemplo 4-18. places_header.csv
contiene la firma de los nodos Place
:ID(Place), city, country
Ejemplo 4-19. places1.csv
contiene datos de los nodos Place
143,Berlin,Germany
Ejemplo 4-20. places2.csv
contiene datos de los nodos Place
244,London,UK
Para conectar personas y lugares, necesitas tener algo como el Ejemplo 4-21, que contiene relaciones que empiezan con nodos Person
y terminan con nodos Place
. Algunas de esas relaciones, aunque no todas, también tienen propiedades since
que representan la fecha en que la persona empezó a vivir en el lugar. La propiedad since
, si está presente, procederá de la tercera columna del archivo CSV.
Ejemplo 4-21. people_places.csv
contiene datos para las relaciones LIVES_IN
y una propiedad opcional since
:START_ID(Person),:END_ID(Place),since 23,143,2020 55,244 42,244,1980
Suponiendo que los datos CSV sean suficientemente correctos, sin caracteres superfluos ni relaciones colgantes, puedes ejecutar el importador sobre los datos para arrancar el gráfico de conocimiento.El Ejemplo 4-22 muestra un ejemplo de línea de comandos que insertará los datos de los archivos CSV en un gráfico de conocimiento. Ten en cuenta que es un comando multilínea, así que ten cuidado de incluir esos caracteres \
al final de cada línea.
Ejemplo 4-22. Ejecutar neo4j-admin import
bin/neo4j-admin import --nodes=Person=import/people.csv \ --relationships=FRIEND=import/friends_header.csv,import/friends1.csv,\ import/friends2.csv \ --nodes=Place=import/places_header.csv,import/places1.csv,import/places2.csv \ --relationships=LIVES_IN=import/people_places.csv
La herramienta neo4j-admin import
es muy rápida y adecuada para conjuntos de datos muy grandes (que contengan muchos miles de millones de registros), con un rendimiento sostenido de aproximadamente un millón de registros por segundo. Ten en cuenta que las importaciones grandes necesitan grandes cantidades de RAM y pueden tardar horas en ejecutarse. La herramienta no es reanudable, así que ten cuidado de no escribir Ctrl-c
en la ventana del terminal mientras se esté ejecutando; de lo contrario, tendrás que para volver a iniciar la importación, lo cual es doloroso para las tareas de larga duración.
Resumen
Llegados a este punto, deberías sentirte cómodo con los conceptos de importaciones masivas en línea y fuera de línea. Habrás visto cómo funciona cada una de estas técnicas y habrás considerado sus pros y sus contras. También deberías ser capaz de tomar decisiones sensatas sobre cuál de estos métodos sería apropiado para el grafo de conocimiento que estás construyendo, incluida la posibilidad de utilizar varias herramientas a lo largo del ciclo de vida del grafo de conocimiento.
A partir de aquí vas a avanzar más en la pila y explorar cómo se pueden introducir datos en el grafo de conocimiento para mantenerlos continuamente actualizados y desencadenar un procesamiento posterior.
1 Antes de Neo4j 5, neo4j-admin import
sólo podía utilizarse para crear un grafo de conocimiento inicial para el sistema. Esa restricción se ha relajado posteriormente para permitir múltiples importaciones fuera de línea a lo largo del ciclo de vida del sistema.
Get Construir grafos de conocimiento now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.