@@ -22,6 +22,7 @@ This repository hosts the code of LightRAG. The structure of this code is based
2222</div >
2323
2424## 🎉 News
25+ - [x] [ 2024.10.20] 🎯🎯📢📢We add two methods to visualize the graph.
2526- [x] [ 2024.10.18] 🎯🎯📢📢We’ve added a link to a [ LightRAG Introduction Video] ( https://youtu.be/oageL-1I0GE ) . Thanks to the author!
2627- [x] [ 2024.10.17] 🎯🎯📢📢We have created a [ Discord channel] ( https://discord.gg/mvsfu2Tg ) ! Welcome to join for sharing and discussions! 🎉🎉
2728- [x] [ 2024.10.16] 🎯🎯📢📢LightRAG now supports [ Ollama models] ( https://github.com/HKUDS/LightRAG?tab=readme-ov-file#quick-start ) !
@@ -221,7 +222,11 @@ with open("./newText.txt") as f:
221222
222223### Graph Visualization
223224
224- * Generate html file
225+ <details >
226+ <summary > Graph visualization with html </summary >
227+
228+ * The following code can be found in ` examples/graph_visual_with_html.py `
229+
225230``` python
226231import networkx as nx
227232from pyvis.network import Network
@@ -238,6 +243,137 @@ net.from_nx(G)
238243# Save and display the network
239244net.show(' knowledge_graph.html' )
240245```
246+
247+ </details >
248+
249+ <details >
250+ <summary > Graph visualization with Neo4j </summary >
251+
252+ * The following code can be found in ` examples/graph_visual_with_neo4j.py `
253+
254+ ``` python
255+ import os
256+ import json
257+ from lightrag.utils import xml_to_json
258+ from neo4j import GraphDatabase
259+
260+ # Constants
261+ WORKING_DIR = " ./dickens"
262+ BATCH_SIZE_NODES = 500
263+ BATCH_SIZE_EDGES = 100
264+
265+ # Neo4j connection credentials
266+ NEO4J_URI = " bolt://localhost:7687"
267+ NEO4J_USERNAME = " neo4j"
268+ NEO4J_PASSWORD = " your_password"
269+
270+ def convert_xml_to_json (xml_path , output_path ):
271+ """ Converts XML file to JSON and saves the output."""
272+ if not os.path.exists(xml_path):
273+ print (f " Error: File not found - { xml_path} " )
274+ return None
275+
276+ json_data = xml_to_json(xml_path)
277+ if json_data:
278+ with open (output_path, ' w' , encoding = ' utf-8' ) as f:
279+ json.dump(json_data, f, ensure_ascii = False , indent = 2 )
280+ print (f " JSON file created: { output_path} " )
281+ return json_data
282+ else :
283+ print (" Failed to create JSON data" )
284+ return None
285+
286+ def process_in_batches (tx , query , data , batch_size ):
287+ """ Process data in batches and execute the given query."""
288+ for i in range (0 , len (data), batch_size):
289+ batch = data[i:i + batch_size]
290+ tx.run(query, {" nodes" : batch} if " nodes" in query else {" edges" : batch})
291+
292+ def main ():
293+ # Paths
294+ xml_file = os.path.join(WORKING_DIR , ' graph_chunk_entity_relation.graphml' )
295+ json_file = os.path.join(WORKING_DIR , ' graph_data.json' )
296+
297+ # Convert XML to JSON
298+ json_data = convert_xml_to_json(xml_file, json_file)
299+ if json_data is None :
300+ return
301+
302+ # Load nodes and edges
303+ nodes = json_data.get(' nodes' , [])
304+ edges = json_data.get(' edges' , [])
305+
306+ # Neo4j queries
307+ create_nodes_query = """
308+ UNWIND $nodes AS node
309+ MERGE (e:Entity {id: node.id} )
310+ SET e.entity_type = node.entity_type,
311+ e.description = node.description,
312+ e.source_id = node.source_id,
313+ e.displayName = node.id
314+ REMOVE e:Entity
315+ WITH e, node
316+ CALL apoc.create.addLabels(e, [node.entity_type]) YIELD node AS labeledNode
317+ RETURN count(*)
318+ """
319+
320+ create_edges_query = """
321+ UNWIND $edges AS edge
322+ MATCH (source {id: edge.source} )
323+ MATCH (target {id: edge.target} )
324+ WITH source, target, edge,
325+ CASE
326+ WHEN edge.keywords CONTAINS 'lead' THEN 'lead'
327+ WHEN edge.keywords CONTAINS 'participate' THEN 'participate'
328+ WHEN edge.keywords CONTAINS 'uses' THEN 'uses'
329+ WHEN edge.keywords CONTAINS 'located' THEN 'located'
330+ WHEN edge.keywords CONTAINS 'occurs' THEN 'occurs'
331+ ELSE REPLACE(SPLIT(edge.keywords, ',')[0], '\" ', '')
332+ END AS relType
333+ CALL apoc.create.relationship(source, relType, {
334+ weight: edge.weight,
335+ description: edge.description,
336+ keywords: edge.keywords,
337+ source_id: edge.source_id
338+ }, target) YIELD rel
339+ RETURN count(*)
340+ """
341+
342+ set_displayname_and_labels_query = """
343+ MATCH (n)
344+ SET n.displayName = n.id
345+ WITH n
346+ CALL apoc.create.setLabels(n, [n.entity_type]) YIELD node
347+ RETURN count(*)
348+ """
349+
350+ # Create a Neo4j driver
351+ driver = GraphDatabase.driver(NEO4J_URI , auth = (NEO4J_USERNAME , NEO4J_PASSWORD ))
352+
353+ try :
354+ # Execute queries in batches
355+ with driver.session() as session:
356+ # Insert nodes in batches
357+ session.execute_write(process_in_batches, create_nodes_query, nodes, BATCH_SIZE_NODES )
358+
359+ # Insert edges in batches
360+ session.execute_write(process_in_batches, create_edges_query, edges, BATCH_SIZE_EDGES )
361+
362+ # Set displayName and labels
363+ session.run(set_displayname_and_labels_query)
364+
365+ except Exception as e:
366+ print (f " Error occurred: { e} " )
367+
368+ finally :
369+ driver.close()
370+
371+ if __name__ == " __main__" :
372+ main()
373+ ```
374+
375+ </details >
376+
241377## Evaluation
242378### Dataset
243379The dataset used in LightRAG can be downloaded from [ TommyChien/UltraDomain] ( https://huggingface.co/datasets/TommyChien/UltraDomain ) .
@@ -484,8 +620,9 @@ def extract_queries(file_path):
484620.
485621├── examples
486622│ ├── batch_eval.py
623+ │ ├── graph_visual_with_html.py
624+ │ ├── graph_visual_with_neo4j.py
487625│ ├── generate_query.py
488- │ ├── graph_visual.py
489626│ ├── lightrag_azure_openai_demo.py
490627│ ├── lightrag_bedrock_demo.py
491628│ ├── lightrag_hf_demo.py
0 commit comments