Vespa向量存储演示¶
如果您在colab上打开这个笔记本,您可能需要安装LlamaIndex 🦙。
In [ ]:
Copied!
%pip install llama-index-vector-stores-vespa llama-index pyvespa
%pip install llama-index-vector-stores-vespa llama-index pyvespa
设置API密钥¶
In [ ]:
Copied!
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 [ ]:
Copied!
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 [ ]:
Copied!
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="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,
},
),
]
初始化VespaVectorStore¶
为了让开始变得非常简单,我们提供了一个模板Vespa应用程序,该应用程序在初始化向量存储时将被部署。
这是一个巨大的抽象,有无尽的机会来定制和自定义Vespa应用程序以满足您的需求。但现在,让我们保持简单,使用默认模板进行初始化。
In [ ]:
Copied!
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 [ ]:
Copied!
node_to_delete = nodes[0].node_id
node_to_delete
node_to_delete = nodes[0].node_id
node_to_delete
In [ ]:
Copied!
vector_store.delete(ref_doc_id=node_to_delete)
vector_store.delete(ref_doc_id=node_to_delete)
查询¶
In [ ]:
Copied!
from llama_index.core.vector_stores.types import (
VectorStoreQuery,
VectorStoreQueryMode,
)
from llama_index.core.vector_stores.types import (
VectorStoreQuery,
VectorStoreQueryMode,
)
In [ ]:
Copied!
query = VectorStoreQuery(
query_str="Great Gatsby",
mode=VectorStoreQueryMode.TEXT_SEARCH,
similarity_top_k=1,
)
result = vector_store.query(query)
query = VectorStoreQuery(
query_str="Great Gatsby",
mode=VectorStoreQueryMode.TEXT_SEARCH,
similarity_top_k=1,
)
result = vector_store.query(query)
In [ ]:
Copied!
result
result
作为检索器¶
默认查询模式(文本搜索)¶
In [ ]:
Copied!
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("Who directed inception?")
display(Markdown(f"**Retrieved nodes:**\n {results}"))
In [ ]:
Copied!
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("Who wrote Harry Potter?")
display(Markdown(f"**Retrieved nodes:**\n {results}"))
作为查询引擎¶
In [ ]:
Copied!
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("Who directed inception?")
display(Markdown(f"**Response:** {response}"))
In [ ]:
Copied!
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(
"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}"))
In [ ]:
Copied!
from llama_index.core.vector_stores import (
FilterOperator, # 过滤操作符
FilterCondition, # 过滤条件
MetadataFilter, # 元数据过滤器
MetadataFilters, # 元数据过滤器集合
)
# 定义一个过滤器,只允许具有主题“小说”或在1997年后发布的节点
filters = MetadataFilters(
filters=[
MetadataFilter(key="theme", value="Fiction"), # 主题为“小说”
MetadataFilter(key="year", value=1997, operator=FilterOperator.GT), # 年份大于1997
],
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, # 元数据过滤器集合
)
# 定义一个过滤器,只允许具有主题“小说”或在1997年后发布的节点
filters = MetadataFilters(
filters=[
MetadataFilter(key="theme", value="Fiction"), # 主题为“小说”
MetadataFilter(key="year", value=1997, operator=FilterOperator.GT), # 年份大于1997
],
condition=FilterCondition.OR, # 条件为“或”
)
retriever = index.as_retriever(filters=filters)
result = retriever.retrieve("Harry Potter")
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
对于集成工作是必需的。
模式名称必须是 doc
,排名配置文件必须命名为 bm25
、semantic
和 fusion
。
除此之外,您可以根据需要自由修改,例如切换嵌入模型、添加更多字段或更改排名表达式。
有关更多详细信息,请查看hybrid search的 Pyvespa 示例笔记本。