Vespa 向量存储示例¶
如果您在 Colab 上打开此 Notebook,您可能需要安装 LlamaIndex 🦙。
In [ ]
已复制!
%pip install llama-index-vector-stores-vespa llama-index pyvespa
%pip install llama-index-vector-stores-vespa llama-index pyvespa
设置 API 密钥¶
In [ ]
已复制!
import os
import openai
os.environ["OPENAI_API_KEY"] = "sk-..."
openai.api_key = os.environ["OPENAI_API_KEY"]
import os import openai os.environ["OPENAI_API_KEY"] = "sk-..." openai.api_key = os.environ["OPENAI_API_KEY"]
加载文档,构建 VectorStoreIndex¶
In [ ]
已复制!
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.vespa import VespaVectorStore
from IPython.display import Markdown, display
from llama_index.core import VectorStoreIndex from llama_index.vector_stores.vespa import VespaVectorStore from IPython.display import Markdown, display
定义一些示例数据¶
让我们插入一些文档。
In [ ]
已复制!
from llama_index.core.schema import TextNode
nodes = [
TextNode(
text="The Shawshank Redemption",
metadata={
"author": "Stephen King",
"theme": "Friendship",
"year": 1994,
},
),
TextNode(
text="The Godfather",
metadata={
"director": "Francis Ford Coppola",
"theme": "Mafia",
"year": 1972,
},
),
TextNode(
text="Inception",
metadata={
"director": "Christopher Nolan",
"theme": "Fiction",
"year": 2010,
},
),
TextNode(
text="To Kill a Mockingbird",
metadata={
"author": "Harper Lee",
"theme": "Mafia",
"year": 1960,
},
),
TextNode(
text="1984",
metadata={
"author": "George Orwell",
"theme": "Totalitarianism",
"year": 1949,
},
),
TextNode(
text="The Great Gatsby",
metadata={
"author": "F. Scott Fitzgerald",
"theme": "The American Dream",
"year": 1925,
},
),
TextNode(
text="Harry Potter and the Sorcerer's Stone",
metadata={
"author": "J.K. Rowling",
"theme": "Fiction",
"year": 1997,
},
),
]
from llama_index.core.schema import TextNode nodes = [ TextNode( text="肖申克的救赎", metadata={ "author": "斯蒂芬·金", "theme": "友谊", "year": 1994, }, ), TextNode( text="教父", metadata={ "director": "弗朗西斯·福特·科波拉", "theme": "黑手党", "year": 1972, }, ), TextNode( text="盗梦空间", metadata={ "director": "克里斯托弗·诺兰", "theme": "小说", "year": 2010, }, ), TextNode( text="杀死一只知更鸟", metadata={ "author": "哈珀·李", "theme": "黑手党", "year": 1960, }, ), TextNode( text="1984", metadata={ "author": "乔治·奥威尔", "theme": "极权主义", "year": 1949, }, ), TextNode( text="了不起的盖茨比", metadata={ "author": "F. 斯科特·菲茨杰拉德", "theme": "美国梦", "year": 1925, }, ), TextNode( text="哈利·波特与魔法石", metadata={ "author": "J.K. 罗琳", "theme": "小说", "year": 1997, }, ), ]
初始化 VespaVectorStore¶
为了让入门变得非常简单,我们提供了一个 Vespa 应用模板,它将在初始化向量存储时部署。
这是一个巨大的抽象,根据您的需求定制和自定义 Vespa 应用有无限的可能性。但目前,让我们保持简单,使用默认模板进行初始化。
In [ ]
已复制!
from llama_index.core import StorageContext
vector_store = VespaVectorStore()
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex(nodes, storage_context=storage_context)
from llama_index.core import StorageContext vector_store = VespaVectorStore() storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex(nodes, storage_context=storage_context)
删除文档¶
In [ ]
已复制!
node_to_delete = nodes[0].node_id
node_to_delete
node_to_delete = nodes[0].node_id node_to_delete
In [ ]
已复制!
vector_store.delete(ref_doc_id=node_to_delete)
vector_store.delete(ref_doc_id=node_to_delete)
查询¶
In [ ]
已复制!
from llama_index.core.vector_stores.types import (
VectorStoreQuery,
VectorStoreQueryMode,
)
from llama_index.core.vector_stores.types import ( VectorStoreQuery, VectorStoreQueryMode, )
In [ ]
已复制!
query = VectorStoreQuery(
query_str="Great Gatsby",
mode=VectorStoreQueryMode.TEXT_SEARCH,
similarity_top_k=1,
)
result = vector_store.query(query)
query = VectorStoreQuery( query_str="了不起的盖茨比", mode=VectorStoreQueryMode.TEXT_SEARCH, similarity_top_k=1, ) result = vector_store.query(query)
In [ ]
已复制!
result
result
作为检索器¶
默认查询模式 (文本搜索)¶
In [ ]
已复制!
retriever = index.as_retriever(vector_store_query_mode="default")
results = retriever.retrieve("Who directed inception?")
display(Markdown(f"**Retrieved nodes:**\n {results}"))
retriever = index.as_retriever(vector_store_query_mode="default") results = retriever.retrieve("《盗梦空间》是谁导演的?") display(Markdown(f"**Retrieved nodes:**\n {results}"))
In [ ]
已复制!
retriever = index.as_retriever(vector_store_query_mode="semantic_hybrid")
results = retriever.retrieve("Who wrote Harry Potter?")
display(Markdown(f"**Retrieved nodes:**\n {results}"))
retriever = index.as_retriever(vector_store_query_mode="semantic_hybrid") results = retriever.retrieve("《哈利·波特》是谁写的?") display(Markdown(f"**Retrieved nodes:**\n {results}"))
作为查询引擎¶
In [ ]
已复制!
query_engine = index.as_query_engine()
response = query_engine.query("Who directed inception?")
display(Markdown(f"**Response:** {response}"))
query_engine = index.as_query_engine() response = query_engine.query("《盗梦空间》是谁导演的?") display(Markdown(f"**Response:** {response}"))
In [ ]
已复制!
query_engine = index.as_query_engine(
vector_store_query_mode="semantic_hybrid", verbose=True
)
response = query_engine.query(
"When was the book about the wizard boy published and what was it called?"
)
display(Markdown(f"**Response:** {response}"))
display(Markdown(f"**Sources:** {response.source_nodes}"))
query_engine = index.as_query_engine( vector_store_query_mode="semantic_hybrid", verbose=True ) response = query_engine.query( "那本关于巫师男孩的书是什么时候出版的,叫什么名字?" ) display(Markdown(f"**Response:** {response}")) display(Markdown(f"**Sources:** {response.source_nodes}"))
In [ ]
已复制!
from llama_index.core.vector_stores import (
FilterOperator,
FilterCondition,
MetadataFilter,
MetadataFilters,
)
# Let's define a filter that will only allow nodes that has the theme "Fiction" OR is published after 1997
filters = MetadataFilters(
filters=[
MetadataFilter(key="theme", value="Fiction"),
MetadataFilter(key="year", value=1997, operator=FilterOperator.GT),
],
condition=FilterCondition.OR,
)
retriever = index.as_retriever(filters=filters)
result = retriever.retrieve("Harry Potter")
display(Markdown(f"**Result:** {result}"))
from llama_index.core.vector_stores import ( FilterOperator, FilterCondition, MetadataFilter, MetadataFilters, ) # Let's define a filter that will only allow nodes that has the theme "Fiction" OR is published after 1997 filters = MetadataFilters( filters=[ MetadataFilter(key="theme", value="Fiction"), MetadataFilter(key="year", value=1997, operator=FilterOperator.GT), ], condition=FilterCondition.OR, ) retriever = index.as_retriever(filters=filters) result = retriever.retrieve("哈利·波特") display(Markdown(f"**Result:** {result}"))
此集成的抽象级别¶
为了让入门变得非常简单,我们提供了一个 Vespa 应用模板,它将在初始化向量存储时部署。这消除了初次设置 Vespa 的一些复杂性,但对于严肃的用例,我们强烈建议您阅读 Vespa 文档 并根据您的需求定制应用。
模板¶
提供的 Vespa 应用模板如下所示
from vespa.package import (
ApplicationPackage,
Field,
Schema,
Document,
HNSW,
RankProfile,
Component,
Parameter,
FieldSet,
GlobalPhaseRanking,
Function,
)
hybrid_template = ApplicationPackage(
name="hybridsearch",
schema=[
Schema(
name="doc",
document=Document(
fields=[
Field(name="id", type="string", indexing=["summary"]),
Field(name="metadata", type="string", indexing=["summary"]),
Field(
name="text",
type="string",
indexing=["index", "summary"],
index="enable-bm25",
bolding=True,
),
Field(
name="embedding",
type="tensor<float>(x[384])",
indexing=[
"input text",
"embed",
"index",
"attribute",
],
ann=HNSW(distance_metric="angular"),
is_document_field=False,
),
]
),
fieldsets=[FieldSet(name="default", fields=["text", "metadata"])],
rank_profiles=[
RankProfile(
name="bm25",
inputs=[("query(q)", "tensor<float>(x[384])")],
functions=[Function(name="bm25sum", expression="bm25(text)")],
first_phase="bm25sum",
),
RankProfile(
name="semantic",
inputs=[("query(q)", "tensor<float>(x[384])")],
first_phase="closeness(field, embedding)",
),
RankProfile(
name="fusion",
inherits="bm25",
inputs=[("query(q)", "tensor<float>(x[384])")],
first_phase="closeness(field, embedding)",
global_phase=GlobalPhaseRanking(
expression="reciprocal_rank_fusion(bm25sum, closeness(field, embedding))",
rerank_count=1000,
),
),
],
)
],
components=[
Component(
id="e5",
type="hugging-face-embedder",
parameters=[
Parameter(
"transformer-model",
{
"url": "https://github.com/vespa-engine/sample-apps/raw/master/simple-semantic-search/model/e5-small-v2-int8.onnx"
},
),
Parameter(
"tokenizer-model",
{
"url": "https://raw.githubusercontent.com/vespa-engine/sample-apps/master/simple-semantic-search/model/tokenizer.json"
},
),
],
)
],
)
请注意,字段 id
、metadata
、text
和 embedding
是集成正常工作所必需的。schema 名称必须是 doc
,并且 rank profiles 必须命名为 bm25
、semantic
和 fusion
。
除此之外,您可以根据需要自由修改,例如更换嵌入模型、添加更多字段或更改排序表达式。
有关更多详细信息,请查看此 Pyvespa 示例 Notebook 关于混合搜索的内容。