> ## Documentation Index
> Fetch the complete documentation index at: https://langchain-docs-zh.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Neo4j 向量索引集成

> 使用 LangChain Python 集成 Neo4j vector index 向量存储。

> [Neo4j](https://neo4j.com/) 是一个集成向量相似性搜索支持的开源图数据库

它支持：

* 近似最近邻搜索
* 欧氏距离相似性和余弦相似性
* 向量和关键词混合搜索

该笔记本展示了如何使用Neo4j向量索引（`Neo4jVector`）。

See the [installation instruction](https://neo4j.com/docs/operations-manual/current/installation/).

```python theme={null}
# Pip install necessary package
pip install -qU  neo4j
pip install -qU  langchain-openai langchain-neo4j
pip install -qU  tiktoken
```

我们想使用 `OpenAIEmbeddings`，因此需要获取OpenAI API Key。

```python theme={null}
import getpass
import os

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
```

```text theme={null}
OpenAI API Key: ········
```

> [!WARNING]
>
> `langchain-community`包已不再维护。从`langchain_community`导入的示例可能过时或无法使用。请谨慎使用。

```python theme={null}
from langchain_community.document_loaders import TextLoader
from langchain_core.documents import Document
from langchain_neo4j import Neo4jVector
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
```

```python theme={null}
loader = TextLoader("../../how_to/state_of_the_union.txt")

documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
```

```python theme={null}
# Neo4jVector requires the Neo4j database credentials

url = "bolt://localhost:7687"
username = "neo4j"
password = "password"

# You can also use environment variables instead of directly passing named parameters
# os.environ["NEO4J_URI"] = "bolt://localhost:7687"
# os.environ["NEO4J_USERNAME"] = "neo4j"
# os.environ["NEO4J_PASSWORD"] = "pleaseletmein"
```

## 使用余弦距离的相似性搜索（默认）

```python theme={null}
# The Neo4jVector Module will connect to Neo4j and create a vector index if needed.

db = Neo4jVector.from_documents(
    docs, OpenAIEmbeddings(), url=url, username=username, password=password
)
```

```python theme={null}
query = "What did the president say about Ketanji Brown Jackson"
docs_with_score = db.similarity_search_with_score(query, k=2)
```

```python theme={null}
for doc, score in docs_with_score:
    print("-" * 80)
    print("Score: ", score)
    print(doc.page_content)
    print("-" * 80)
```

```text theme={null}
--------------------------------------------------------------------------------
Score:  0.9076391458511353
Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections.

Tonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service.

One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court.

And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Score:  0.8912242650985718
A former top litigator in private practice. A former federal public defender. And from a family of public school educators and police officers. A consensus builder. Since she’s been nominated, she’s received a broad range of support—from the Fraternal Order of Police to former judges appointed by Democrats and Republicans.

And if we are to advance liberty and justice, we need to secure the Border and fix the immigration system.

We can do both. At our border, we’ve installed new technology like cutting-edge scanners to better detect drug smuggling.

We’ve set up joint patrols with Mexico and Guatemala to catch more human traffickers.

We’re putting in place dedicated immigration judges so families fleeing persecution and violence can have their cases heard faster.

We’re securing commitments and supporting partners in South and Central America to host more refugees and secure their own borders.
--------------------------------------------------------------------------------
```

## 与向量存储的工作

上述示例是从零构建向量存储。但实际场景中，我们更常需要与现有向量存储工作。为此，可以直接初始化向量存储。

```python theme={null}
index_name = "vector"  # default index name

store = Neo4jVector.from_existing_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name=index_name,
)
```

我们也可以通过 `from_existing_graph` 方法从现有图数据库初始化向量存储。该方法会从数据库拉取相关文本信息，并重新计算存储文本嵌入。

```python theme={null}
# First we create sample data in graph
store.query(
    "CREATE (p:Person {name: 'Tomaz', location:'Slovenia', hobby:'Bicycle', age: 33})"
)
```

```text theme={null}
[]
```

```python theme={null}
# Now we initialize from existing graph
existing_graph = Neo4jVector.from_existing_graph(
    embedding=OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name="person_index",
    node_label="Person",
    text_node_properties=["name", "location"],
    embedding_node_property="embedding",
)
result = existing_graph.similarity_search("Slovenia", k=1)
```

```python theme={null}
result[0]
```

```python theme={null}
Document(page_content='\nname: Tomaz\nlocation: Slovenia', metadata={'age': 33, 'hobby': 'Bicycle'})
```

Neo4j还支持关系向量索引，将嵌入存储为关系属性并建立索引。但关系向量索引无法通过LangChain填充，但可以连接现有关系向量索引。

```python theme={null}
# First we create sample data and index in graph
store.query(
    "MERGE (p:Person {name: 'Tomaz'}) "
    "MERGE (p1:Person {name:'Leann'}) "
    "MERGE (p1)-[:FRIEND {text:'example text', embedding:$embedding}]->(p2)",
    params={"embedding": OpenAIEmbeddings().embed_query("example text")},
)
# Create a vector index
relationship_index = "relationship_vector"
store.query(
    """
CREATE VECTOR INDEX $relationship_index
IF NOT EXISTS
FOR ()-[r:FRIEND]-() ON (r.embedding)
OPTIONS {indexConfig: {
 `vector.dimensions`: 1536,
 `vector.similarity_function`: 'cosine'
}}
""",
    params={"relationship_index": relationship_index},
)
```

```text theme={null}
[]
```

```python theme={null}
relationship_vector = Neo4jVector.from_existing_relationship_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name=relationship_index,
    text_node_property="text",
)
relationship_vector.similarity_search("Example")
```

```python theme={null}
[Document(page_content='example text')]
```

### 元数据过滤

Neo4j向量存储支持通过并行运行时和精确最近邻搜索实现元数据过滤
*需Neo4j 5.18或更高版本*

等值过滤语法如下：

```python theme={null}
existing_graph.similarity_search(
    "Slovenia",
    filter={"hobby": "Bicycle", "name": "Tomaz"},
)
```

```python theme={null}
[Document(page_content='\nname: Tomaz\nlocation: Slovenia', metadata={'age': 33, 'hobby': 'Bicycle'})]
```

元数据过滤还支持以下运算符：

* `$eq: Equal`
* `$ne: Not Equal`
* `$lt: Less than`
* `$lte: Less than or equal`
* `$gt: Greater than`
* `$gte: Greater than or equal`
* `$in: In a list of values`
* `$nin: Not in a list of values`
* `$between: Between two values`
* `$like: Text contains value`
* `$ilike: lowered text contains value`

```python theme={null}
existing_graph.similarity_search(
    "Slovenia",
    filter={"hobby": {"$eq": "Bicycle"}, "age": {"$gt": 15}},
)
```

```python theme={null}
[Document(page_content='\nname: Tomaz\nlocation: Slovenia', metadata={'age': 33, 'hobby': 'Bicycle'})]
```

您也可以使用 `OR` 运算符组合过滤条件

```python theme={null}
existing_graph.similarity_search(
    "Slovenia",
    filter={"$or": [{"hobby": {"$eq": "Bicycle"}}, {"age": {"$gt": 15}}]},
)
```

```python theme={null}
[Document(page_content='\nname: Tomaz\nlocation: Slovenia', metadata={'age': 33, 'hobby': 'Bicycle'})]
```

### 添加文档

我们可以向现有向量存储添加文档。

```python theme={null}
store.add_documents([Document(page_content="foo")])
```

```python theme={null}
['acbd18db4cc2f85cedef654fccc4a4d8']
```

```python theme={null}
docs_with_score = store.similarity_search_with_score("foo")
```

```python theme={null}
docs_with_score[0]
```

```text theme={null}
(Document(page_content='foo'), 0.9999997615814209)
```

## 使用检索查询定制响应

您可以通过自定义Cypher片段从图数据库获取其他信息来定制响应。最终生成的Cypher语句如下：

```
read_query = (
  "CALL db.index.vector.queryNodes($index, $k, $embedding) "
  "YIELD node, score "
) + retrieval_query
```

检索查询必须返回以下三个列：

* `text`: Union\[str, Dict] = 用于填充文档 `page_content` 的值
* `score`: Float = 相似度得分
* `metadata`: Dict = 文档额外元数据

更多细节请参考此 [博客文章](https://medium.com/neo4j/implementing-rag-how-to-write-a-graph-retrieval-query-in-langchain-74abf13044f2)。

```python theme={null}
retrieval_query = """
RETURN "Name:" + node.name AS text, score, {foo:"bar"} AS metadata
"""
retrieval_example = Neo4jVector.from_existing_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name="person_index",
    retrieval_query=retrieval_query,
)
retrieval_example.similarity_search("Foo", k=1)
```

```python theme={null}
[Document(page_content='Name:Tomaz', metadata={'foo': 'bar'})]
```

以下示例将节点所有属性（除 `embedding` 外）作为字典传递给 `text` 列：

```python theme={null}
retrieval_query = """
RETURN node {.name, .age, .hobby} AS text, score, {foo:"bar"} AS metadata
"""
retrieval_example = Neo4jVector.from_existing_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name="person_index",
    retrieval_query=retrieval_query,
)
retrieval_example.similarity_search("Foo", k=1)
```

```python theme={null}
[Document(page_content='name: Tomaz\nage: 33\nhobby: Bicycle\n', metadata={'foo': 'bar'})]
```

您也可以向检索查询传递Cypher参数。参数可用于额外过滤、遍历等操作...

```python theme={null}
retrieval_query = """
RETURN node {.*, embedding:Null, extra: $extra} AS text, score, {foo:"bar"} AS metadata
"""
retrieval_example = Neo4jVector.from_existing_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name="person_index",
    retrieval_query=retrieval_query,
)
retrieval_example.similarity_search("Foo", k=1, params={"extra": "ParamInfo"})
```

```python theme={null}
[Document(page_content='location: Slovenia\nextra: ParamInfo\nname: Tomaz\nage: 33\nhobby: Bicycle\nembedding: None\n', metadata={'foo': 'bar'})]
```

## 混合搜索（向量 + 关键词）

Neo4j集成了向量索引和关键词索引，支持混合搜索方式

```python theme={null}
# The Neo4jVector Module will connect to Neo4j and create a vector and keyword indices if needed.
hybrid_db = Neo4jVector.from_documents(
    docs,
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    search_type="hybrid",
)
```

要加载混合搜索，需同时提供向量索引和关键词索引

```python theme={null}
index_name = "vector"  # default index name
keyword_index_name = "keyword"  # default keyword index name

store = Neo4jVector.from_existing_index(
    OpenAIEmbeddings(),
    url=url,
    username=username,
    password=password,
    index_name=index_name,
    keyword_index_name=keyword_index_name,
    search_type="hybrid",
)
```

## 检索器选项

本节演示如何使用 `Neo4jVector` 作为检索器。

```python theme={null}
retriever = store.as_retriever()
retriever.invoke(query)[0]
```

```python theme={null}
Document(page_content='Tonight. I call on the Senate to: Pass the Freedom to Vote Act. Pass the John Lewis Voting Rights Act. And while you’re at it, pass the Disclose Act so Americans can know who is funding our elections. \n\nTonight, I’d like to honor someone who has dedicated his life to serve this country: Justice Stephen Breyer—an Army veteran, Constitutional scholar, and retiring Justice of the United States Supreme Court. Justice Breyer, thank you for your service. \n\nOne of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n\nAnd I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.', metadata={'source': '../../how_to/state_of_the_union.txt'})
```

## 带来源的问答

本节介绍如何通过 `RetrievalQAWithSourcesChain` 实现带来源的问答。该组件会从索引中查找文档。

```python theme={null}
from langchain_classic.chains import RetrievalQAWithSourcesChain
from langchain_openai import ChatOpenAI
```

```python theme={null}
chain = RetrievalQAWithSourcesChain.from_chain_type(
    ChatOpenAI(temperature=0), chain_type="stuff", retriever=retriever
)
```

```python theme={null}
chain.invoke(
    {"question": "What did the president say about Justice Breyer"},
    return_only_outputs=True,
)
```

```text theme={null}
{'answer': 'The president honored Justice Stephen Breyer for his service to the country and mentioned his retirement from the United States Supreme Court.\n',
 'sources': '../../how_to/state_of_the_union.txt'}
```

```python theme={null}
```

***

> 官方原文：[src/oss/python/integrations/vectorstores/neo4jvector.mdx](https://github.com/langchain-ai/docs/blob/main/src/oss/python/integrations/vectorstores/neo4jvector.mdx) · 非官方翻译，译文由 AI 生成，以英文原文为准。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.