凝胶向量存储
Gel 是一个开源的 PostgreSQL 数据层,专为从开发到生产周期的快速迭代而优化。它提供高级严格类型的类图数据模型、可组合的层次化查询语言、完整的 SQL 支持、数据迁移、认证和 AI 模块。
如果您在 Colab 上打开这个笔记本,您可能需要安装 LlamaIndex 🦙。
! pip install gel llama-index-vector-stores-gel! pip install llama-index# import logging# import sys
# Uncomment to see debug logs# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)# logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
from llama_index.core import SimpleDirectoryReader, StorageContextfrom llama_index.core import VectorStoreIndexfrom llama_index.vector_stores.gel import GelVectorStoreimport textwrapimport openai设置OpenAI
Section titled “Setup OpenAI”第一步是配置 OpenAI 密钥。它将用于为加载到索引中的文档创建嵌入向量
import os
os.environ["OPENAI_API_KEY"] = "<your key>"openai.api_key = os.environ["OPENAI_API_KEY"]下载数据
!mkdir -p 'data/paul_graham/'!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/paul_graham/paul_graham_essay.txt' -O 'data/paul_graham/paul_graham_essay.txt'Load the documents stored in the data/paul_graham/ using the SimpleDirectoryReader
documents = SimpleDirectoryReader("./data/paul_graham").load_data()print("Document ID:", documents[0].doc_id)为了将 Gel 用作向量存储的后端,您需要一个可运行的 Gel 实例。 幸运的是,除非您需要,否则不必涉及 Docker 容器或任何复杂设置。
要设置本地实例,请运行:
! gel project init --non-interactive如果您正在使用 Gel Cloud(推荐使用!),请在该命令中添加一个参数:
gel project init --server-instance <org-name>/<instance-name>有关运行 Gel 的完整方法列表,请查阅参考文档中的运行 Gel章节。
Gel 模式是对应用程序数据模型的显式高层描述。除了能让您精确定义数据的布局方式外,它还驱动着 Gel 的诸多强大功能,例如链接、访问策略、函数、触发器、约束、索引等。
LlamaIndex 的 GelVectorStore 期望以下架构布局:
schema_content = """using extension pgvector;
module default { scalar type EmbeddingVector extending ext::pgvector::vector<1536>;
type Record { required collection: str; text: str; embedding: EmbeddingVector; external_id: str { constraint exclusive; }; metadata: json;
index ext::pgvector::hnsw_cosine(m := 16, ef_construction := 128) on (.embedding) }}""".strip()
with open("dbschema/default.gel", "w") as f: f.write(schema_content)为了将模式变更应用到数据库,请使用 Gel 的迁移工具运行迁移:
! gel migration create --non-interactive! gel migrate从此刻起,GelVectorStore 可以作为 LlamaIndex 中任何其他向量存储的直接替代品使用。
vector_store = GelVectorStore()
storage_context = StorageContext.from_defaults(vector_store=vector_store)index = VectorStoreIndex.from_documents( documents, storage_context=storage_context, show_progress=True)query_engine = index.as_query_engine()我们现在可以使用我们的索引来提问了。
response = query_engine.query("What did the author do?")print(textwrap.fill(str(response), 100))response = query_engine.query("What happened in the mid 1980s?")print(textwrap.fill(str(response), 100))GelVectorStore 支持在节点中存储元数据,并在检索步骤中基于该元数据进行过滤。
!mkdir -p 'data/git_commits/'!wget 'https://raw.githubusercontent.com/run-llama/llama_index/main/docs/examples/data/csv/commit_history.csv' -O 'data/git_commits/commit_history.csv'import csv
with open("data/git_commits/commit_history.csv", "r") as f: commits = list(csv.DictReader(f))
print(commits[0])print(len(commits))添加带有自定义元数据的节点
Section titled “Add nodes with custom metadata”# Create TextNode for each of the first 100 commitsfrom llama_index.core.schema import TextNodefrom datetime import datetimeimport re
nodes = []dates = set()authors = set()for commit in commits[:100]: author_email = commit["author"].split("<")[1][:-1] commit_date = datetime.strptime( commit["date"], "%a %b %d %H:%M:%S %Y %z" ).strftime("%Y-%m-%d") commit_text = commit["change summary"] if commit["change details"]: commit_text += "\n\n" + commit["change details"] fixes = re.findall(r"#(\d+)", commit_text, re.IGNORECASE) nodes.append( TextNode( text=commit_text, metadata={ "commit_date": commit_date, "author": author_email, "fixes": fixes, }, ) ) dates.add(commit_date) authors.add(author_email)
print(nodes[0])print(min(dates), "to", max(dates))print(authors)vector_store = GelVectorStore()
index = VectorStoreIndex.from_vector_store(vector_store=vector_store)index.insert_nodes(nodes)print(index.as_query_engine().query("How did Lakshmi fix the segfault?"))现在我们可以在检索节点时按提交作者或日期进行筛选。
from llama_index.core.vector_stores.types import ( MetadataFilter, MetadataFilters,)
filters = MetadataFilters( filters=[ MetadataFilter(key="author", value="mats@timescale.com"), MetadataFilter(key="author", value="sven@timescale.com"), ], condition="or",)
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("What is this software project about?")
for node in retrieved_nodes: print(node.node.metadata)filters = MetadataFilters( filters=[ MetadataFilter(key="commit_date", value="2023-08-15", operator=">="), MetadataFilter(key="commit_date", value="2023-08-25", operator="<="), ], condition="and",)
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("What is this software project about?")
for node in retrieved_nodes: print(node.node.metadata)在上述示例中,我们使用 AND 或 OR 组合了多个过滤器。我们还可以组合多组过滤器。
filters = MetadataFilters( filters=[ MetadataFilters( filters=[ MetadataFilter( key="commit_date", value="2023-08-01", operator=">=" ), MetadataFilter( key="commit_date", value="2023-08-15", operator="<=" ), ], condition="and", ), MetadataFilters( filters=[ MetadataFilter(key="author", value="mats@timescale.com"), MetadataFilter(key="author", value="sven@timescale.com"), ], condition="or", ), ], condition="and",)
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("What is this software project about?")
for node in retrieved_nodes: print(node.node.metadata)上述内容可以通过使用 IN 运算符来简化。GelVectorStore 支持 in、nin 和 contains 来比较元素与列表。
filters = MetadataFilters( filters=[ MetadataFilter(key="commit_date", value="2023-08-01", operator=">="), MetadataFilter(key="commit_date", value="2023-08-15", operator="<="), MetadataFilter( key="author", value=["mats@timescale.com", "sven@timescale.com"], operator="in", ), ], condition="and",)
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("What is this software project about?")
for node in retrieved_nodes: print(node.node.metadata)# Same thing, with NOT INfilters = MetadataFilters( filters=[ MetadataFilter(key="commit_date", value="2023-08-01", operator=">="), MetadataFilter(key="commit_date", value="2023-08-15", operator="<="), MetadataFilter( key="author", value=["mats@timescale.com", "sven@timescale.com"], operator="nin", ), ], condition="and",)
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("What is this software project about?")
for node in retrieved_nodes: print(node.node.metadata)# CONTAINSfilters = MetadataFilters( filters=[ MetadataFilter(key="fixes", value="5680", operator="contains"), ])
retriever = index.as_retriever( similarity_top_k=10, filters=filters,)
retrieved_nodes = retriever.retrieve("How did these commits fix the issue?")for node in retrieved_nodes: print(node.node.metadata)