Combining lexical graphs with vector search

Graph RAG with LangChain and Neo4j

Adam Cowley

Manager, Developer Education at Neo4j

Using relationships in semantic search

What is it like to work at Neo4j?

A graph diagram with a Review node and the text property "Neo4j is a great place to work"

Graph RAG with LangChain and Neo4j

Using relationships in semantic search

What is it like to work at Neo4j?

The review is posted by a Person with the screen name @emileifrem

Graph RAG with LangChain and Neo4j

Using relationships in semantic search

What is it like to work at Neo4j?

Emil Eifrem has a WORKS_AT relationship to a Company node with the name Neo4j

Graph RAG with LangChain and Neo4j

Text properties to embeddings

 

  • Create node embeddings from text property

a scene with HAS_CHUNK relationships to Chunk nodes with a string property

Graph RAG with LangChain and Neo4j

Text properties to embeddings

 

  • Create node embeddings from text property
  • Vector search on embeddings
  • Use relationships for context

The text properties on the nodes are used to create an embedding

Graph RAG with LangChain and Neo4j

Neo4j as a vector store

from langchain_neo4j import Neo4jVector

 

  • Neo4jVector.from_documents(): Create nodes and underlying index from Documents
  • Neo4jVector.from_existing_graph(): Create index on existing label and property combinations
Graph RAG with LangChain and Neo4j

Chunking existing node properties

A knowledge graph diagram highlighting the HAS_SCENE relationship from the Act node to the Scene node

res = graph.query("""

MATCH (s:Scene)
WHERE NOT {(s)-[:HAS_LINE]->()}
RETURN s.id AS id, s.text AS text
""")
for scene in res: # Create chunks from scene['text']
Graph RAG with LangChain and Neo4j

Chunking existing node properties

  • Split text by "\n\n"
  • Stage directions have one line
  • Spoken lines start with character name
    • Following lines contain the spoken words
 Enter Sampson and Gregory armed with swords..

SAMPSON.
Gregory, on my word...
GREGORY. No, for then we should...
SAMPSON. I mean, if we be in choler, we'll draw...
Graph RAG with LangChain and Neo4j

Chunking existing node properties

# Split text into lines
lines = [
    line.strip() for line in text.split("\n\n")

if "\n" in line
]
for line in lines: parts = line.split("\n")
character = parts[0]
text = "\n".join(parts[1:])
Graph RAG with LangChain and Neo4j

Chunking existing node properties

# ...Continuing loop over scenes

line_node = Node(type="Line", id=f"{scene.id}-line-{i}", properties={})
character_node = Node(type="Character", id=character, properties={})


# (:Scene)-[:HAS_LINE]->(:Line) graph_document.relationships.append( Relationship(source=scene, target=line_node, type="HAS_LINE"))
# (:Line)-[:SPOKEN_BY]->(:Character) graph_document.relationships.append(Relationship( source=line_node, target=characters[character], type="SPOKEN_BY"))
Graph RAG with LangChain and Neo4j

Creating a vector index on an existing graph

from langchain_openai import OpenAIEmbeddings
store = Neo4jVector.from_existing_graph(

OpenAIEmbeddings(model="text-embedding-3-small"),
url=NEO4J_URI, username=NEO4J_USERNAME, password=NEO4J_PASSWORD,
node_label="Line",
text_node_properties=["text"],
embedding_node_property="embedding",
index_name="lines",
)
Graph RAG with LangChain and Neo4j

Vector retrieval with LCEL

# Create retriever
retriever = store.as_retriever()

# Invoke manually retriever.invoke("What does Romeo think of Juliet?") # [ Document, Document, ... ]
Graph RAG with LangChain and Neo4j

Let's practice!

Graph RAG with LangChain and Neo4j

Preparing Video For Download...