a0c8464e58
Build Package / build (ubuntu-latest) (push) Failing after 1s
CodeQL / Analyze (python) (push) Failing after 1s
Core Typecheck / core-typecheck (push) Failing after 1s
Linting / lint (push) Failing after 1s
llama-dev tests / test-llama-dev (push) Failing after 1s
Publish Sub-Package to PyPI if Needed / publish_subpackage_if_needed (push) Has been skipped
Sync Docs to Developer Hub / sync-docs (push) Failing after 0s
Build Package / build (windows-latest) (push) Has been cancelled
939 lines
30 KiB
Plaintext
939 lines
30 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"https://colab.research.google.com/github/run-llama/llama_index/blob/main/docs/examples/vector_stores/VertexAIVectorSearchV2Demo.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Google Vertex AI Vector Search v2.0\n",
|
|
"\n",
|
|
"This notebook demonstrates how to use **Vertex AI Vector Search v2.0** with LlamaIndex.\n",
|
|
"\n",
|
|
"> [Vertex AI Vector Search v2.0](https://cloud.google.com/vertex-ai/docs/vector-search/overview) introduces a simplified **collection-based architecture** that eliminates the need for separate index creation and endpoint deployment.\n",
|
|
"\n",
|
|
"## v2.0 vs v1.0\n",
|
|
"\n",
|
|
"| Feature | v1.0 | v2.0 |\n",
|
|
"|---------|------|------|\n",
|
|
"| Architecture | Index + Endpoint | Collection |\n",
|
|
"| Setup Steps | Create index → Deploy to endpoint | Create collection |\n",
|
|
"| GCS Bucket | Required for batch updates | Not needed |\n",
|
|
"| Hybrid Search | Not supported | Supported |\n",
|
|
"\n",
|
|
"**Note**: For v1.0 usage, see [VertexAIVectorSearchDemo.ipynb](./VertexAIVectorSearchDemo.ipynb)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Install Dependencies\n",
|
|
"\n",
|
|
"Install LlamaIndex with v2 support:\n",
|
|
"\n",
|
|
"> **Note**: V2 support requires `llama-index-vector-stores-vertexaivectorsearch` version that supports Vertex AI Vector Search v2.0 API."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Install with v2 support (the [v2] extra installs google-cloud-vectorsearch)\n",
|
|
"# !pip install 'llama-index-vector-stores-vertexaivectorsearch[v2]' llama-index-embeddings-vertex llama-index-llms-vertex"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Authentication (if using Colab):"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Colab authentication.\n",
|
|
"import sys\n",
|
|
"\n",
|
|
"if \"google.colab\" in sys.modules:\n",
|
|
" from google.colab import auth\n",
|
|
"\n",
|
|
" auth.authenticate_user()\n",
|
|
" print(\"Authenticated\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Configuration\n",
|
|
"\n",
|
|
"Set your Google Cloud project details:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Google Cloud Configuration\n",
|
|
"PROJECT_ID = \"your-project-id\" # @param {type:\"string\"}\n",
|
|
"REGION = \"us-central1\" # @param {type:\"string\"}\n",
|
|
"COLLECTION_ID = \"llamaindex-demo-collection\" # @param {type:\"string\"}\n",
|
|
"\n",
|
|
"# Embedding dimensions (768 for text-embedding-004)\n",
|
|
"EMBEDDING_DIMENSION = 768"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Create a v2 Collection\n",
|
|
"\n",
|
|
"Unlike v1.0 which requires creating an index and deploying it to an endpoint, v2.0 only requires creating a collection.\n",
|
|
"\n",
|
|
"**Important for Hybrid Search:** The collection schema below is configured to support all hybrid search features:\n",
|
|
"\n",
|
|
"- **Text Search**: String fields (`text`, `category`, `color`) can be searched with keywords\n",
|
|
"- **Semantic Search**: The `vertex_embedding_config` enables auto-embeddings for `SEMANTIC_HYBRID` mode\n",
|
|
"- **Filtering**: Numeric (`price`) and string fields support metadata filtering"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from google.cloud import vectorsearch_v1beta\n",
|
|
"\n",
|
|
"# Initialize the client\n",
|
|
"client = vectorsearch_v1beta.VectorSearchServiceClient()\n",
|
|
"\n",
|
|
"# Check if collection already exists\n",
|
|
"parent = f\"projects/{PROJECT_ID}/locations/{REGION}\"\n",
|
|
"collection_name = f\"{parent}/collections/{COLLECTION_ID}\"\n",
|
|
"\n",
|
|
"# Collection schema that supports:\n",
|
|
"# - Dense vector search (embedding field)\n",
|
|
"# - Text search on text, category, color fields (for HYBRID mode)\n",
|
|
"# - Semantic search with auto-embeddings (for SEMANTIC_HYBRID mode)\n",
|
|
"# - Filtering on price, category, color fields\n",
|
|
"collection_config = {\n",
|
|
" \"data_schema\": {\n",
|
|
" \"type\": \"object\",\n",
|
|
" \"properties\": {\n",
|
|
" \"text\": {\"type\": \"string\"}, # Main text content (searchable)\n",
|
|
" \"ref_doc_id\": {\"type\": \"string\"}, # Document reference\n",
|
|
" \"price\": {\"type\": \"number\"}, # Filterable numeric field\n",
|
|
" \"color\": {\"type\": \"string\"}, # Filterable/searchable string\n",
|
|
" \"category\": {\"type\": \"string\"}, # Filterable/searchable string\n",
|
|
" },\n",
|
|
" },\n",
|
|
" \"vector_schema\": {\n",
|
|
" \"embedding\": {\n",
|
|
" \"dense_vector\": {\n",
|
|
" \"dimensions\": EMBEDDING_DIMENSION,\n",
|
|
" # Auto-embedding config enables SEMANTIC_HYBRID mode\n",
|
|
" # Vertex AI will auto-generate embeddings for semantic search\n",
|
|
" \"vertex_embedding_config\": {\n",
|
|
" \"model_id\": \"text-embedding-004\",\n",
|
|
" \"text_template\": \"{text}\",\n",
|
|
" \"task_type\": \"RETRIEVAL_DOCUMENT\",\n",
|
|
" },\n",
|
|
" }\n",
|
|
" },\n",
|
|
" },\n",
|
|
"}\n",
|
|
"\n",
|
|
"try:\n",
|
|
" request = vectorsearch_v1beta.GetCollectionRequest(name=collection_name)\n",
|
|
" collection = client.get_collection(request=request)\n",
|
|
" print(f\"Collection already exists: {collection.name}\")\n",
|
|
" print(\n",
|
|
" \"Note: If you need hybrid search features, delete and recreate with the schema above.\"\n",
|
|
" )\n",
|
|
"except Exception as e:\n",
|
|
" if \"404\" in str(e) or \"NotFound\" in str(e):\n",
|
|
" print(f\"Creating collection: {COLLECTION_ID}\")\n",
|
|
" print(\n",
|
|
" \"Schema includes: text search fields, auto-embedding config for semantic search\"\n",
|
|
" )\n",
|
|
"\n",
|
|
" request = vectorsearch_v1beta.CreateCollectionRequest(\n",
|
|
" parent=parent,\n",
|
|
" collection_id=COLLECTION_ID,\n",
|
|
" collection=collection_config,\n",
|
|
" )\n",
|
|
" operation = client.create_collection(request=request)\n",
|
|
" collection = operation.result()\n",
|
|
" print(f\"Collection created: {collection.name}\")\n",
|
|
" else:\n",
|
|
" raise e"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Set Up LlamaIndex Components"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Imports\n",
|
|
"from llama_index.core import Settings, StorageContext, VectorStoreIndex\n",
|
|
"from llama_index.core.schema import TextNode\n",
|
|
"from llama_index.core.vector_stores.types import (\n",
|
|
" MetadataFilters,\n",
|
|
" MetadataFilter,\n",
|
|
" FilterOperator,\n",
|
|
")\n",
|
|
"from llama_index.embeddings.vertex import VertexTextEmbedding\n",
|
|
"from llama_index.llms.vertex import Vertex\n",
|
|
"from llama_index.vector_stores.vertexaivectorsearch import VertexAIVectorStore\n",
|
|
"\n",
|
|
"# Authentication - get default credentials\n",
|
|
"import google.auth\n",
|
|
"\n",
|
|
"credentials, project = google.auth.default()\n",
|
|
"print(f\"Authenticated with project: {project}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Configure embedding model\n",
|
|
"embed_model = VertexTextEmbedding(\n",
|
|
" model_name=\"text-embedding-004\",\n",
|
|
" project=PROJECT_ID,\n",
|
|
" location=REGION,\n",
|
|
" credentials=credentials,\n",
|
|
")\n",
|
|
"\n",
|
|
"# Configure LLM\n",
|
|
"llm = Vertex(\n",
|
|
" model=\"gemini-2.0-flash\",\n",
|
|
" project=PROJECT_ID,\n",
|
|
" location=REGION,\n",
|
|
" credentials=credentials,\n",
|
|
")\n",
|
|
"\n",
|
|
"# Set as defaults\n",
|
|
"Settings.embed_model = embed_model\n",
|
|
"Settings.llm = llm\n",
|
|
"\n",
|
|
"print(\"Embedding model and LLM configured successfully!\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Create v2 Vector Store\n",
|
|
"\n",
|
|
"Creating a v2 vector store is simple - just specify `api_version=\"v2\"` and your `collection_id`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create v2 vector store\n",
|
|
"vector_store = VertexAIVectorStore(\n",
|
|
" api_version=\"v2\", # Use v2 API\n",
|
|
" project_id=PROJECT_ID,\n",
|
|
" region=REGION,\n",
|
|
" collection_id=COLLECTION_ID,\n",
|
|
" # No index_id, endpoint_id, or gcs_bucket_name needed!\n",
|
|
")\n",
|
|
"\n",
|
|
"print(f\"Vector store created with api_version={vector_store.api_version}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Add Documents\n",
|
|
"\n",
|
|
"### Simple Text Nodes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create some sample text nodes\n",
|
|
"texts = [\n",
|
|
" \"LlamaIndex is a data framework for LLM applications.\",\n",
|
|
" \"Vertex AI Vector Search provides scalable vector similarity search.\",\n",
|
|
" \"RAG combines retrieval with generation for better AI responses.\",\n",
|
|
" \"Embeddings convert text into numerical vectors for similarity matching.\",\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Create nodes with embeddings\n",
|
|
"nodes = [\n",
|
|
" TextNode(text=text, embedding=embed_model.get_text_embedding(text))\n",
|
|
" for text in texts\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Add to vector store\n",
|
|
"ids = vector_store.add(nodes)\n",
|
|
"print(f\"Added {len(ids)} nodes to vector store\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Nodes with Metadata\n",
|
|
"\n",
|
|
"Add nodes with metadata for filtering and hybrid search:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Sample product data with metadata\n",
|
|
"products = [\n",
|
|
" {\n",
|
|
" \"text\": \"Comfortable blue cotton t-shirt, perfect for casual wear\",\n",
|
|
" \"color\": \"blue\",\n",
|
|
" \"category\": \"tops\",\n",
|
|
" \"price\": 29.99,\n",
|
|
" },\n",
|
|
" {\n",
|
|
" \"text\": \"Professional black dress pants for office meetings\",\n",
|
|
" \"color\": \"black\",\n",
|
|
" \"category\": \"bottoms\",\n",
|
|
" \"price\": 79.99,\n",
|
|
" },\n",
|
|
" {\n",
|
|
" \"text\": \"Warm green wool sweater for cold winter days\",\n",
|
|
" \"color\": \"green\",\n",
|
|
" \"category\": \"tops\",\n",
|
|
" \"price\": 59.99,\n",
|
|
" },\n",
|
|
" {\n",
|
|
" \"text\": \"Lightweight blue running shorts with pockets\",\n",
|
|
" \"color\": \"blue\",\n",
|
|
" \"category\": \"bottoms\",\n",
|
|
" \"price\": 34.99,\n",
|
|
" },\n",
|
|
" {\n",
|
|
" \"text\": \"Elegant red silk blouse for formal occasions\",\n",
|
|
" \"color\": \"red\",\n",
|
|
" \"category\": \"tops\",\n",
|
|
" \"price\": 89.99,\n",
|
|
" },\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Create nodes with metadata\n",
|
|
"# Note: Include \"text\" in metadata for TEXT_SEARCH to work on the text field\n",
|
|
"product_nodes = [\n",
|
|
" TextNode(\n",
|
|
" text=p[\"text\"],\n",
|
|
" embedding=embed_model.get_text_embedding(p[\"text\"]),\n",
|
|
" metadata={\n",
|
|
" \"text\": p[\"text\"],\n",
|
|
" \"color\": p[\"color\"],\n",
|
|
" \"category\": p[\"category\"],\n",
|
|
" \"price\": p[\"price\"],\n",
|
|
" },\n",
|
|
" )\n",
|
|
" for p in products\n",
|
|
"]\n",
|
|
"\n",
|
|
"# Add to vector store\n",
|
|
"product_ids = vector_store.add(product_nodes)\n",
|
|
"print(f\"Added {len(product_ids)} product nodes with metadata\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Query the Vector Store\n",
|
|
"\n",
|
|
"### Simple Similarity Search"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create index from vector store\n",
|
|
"storage_context = StorageContext.from_defaults(vector_store=vector_store)\n",
|
|
"index = VectorStoreIndex.from_vector_store(\n",
|
|
" vector_store=vector_store, embed_model=embed_model\n",
|
|
")\n",
|
|
"\n",
|
|
"# Create retriever\n",
|
|
"retriever = index.as_retriever(similarity_top_k=3)\n",
|
|
"\n",
|
|
"# Query\n",
|
|
"results = retriever.retrieve(\"comfortable clothing for everyday wear\")\n",
|
|
"\n",
|
|
"print(\"Search Results:\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"for result in results:\n",
|
|
" print(f\"Score: {result.get_score():.3f}\")\n",
|
|
" print(f\"Text: {result.get_text()[:100]}...\")\n",
|
|
" print(f\"Metadata: {result.metadata}\")\n",
|
|
" print(\"-\" * 60)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Search with Metadata Filters"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Filter by color\n",
|
|
"filters = MetadataFilters(filters=[MetadataFilter(key=\"color\", value=\"blue\")])\n",
|
|
"\n",
|
|
"retriever = index.as_retriever(filters=filters, similarity_top_k=3)\n",
|
|
"results = retriever.retrieve(\"casual clothing\")\n",
|
|
"\n",
|
|
"print(\"Blue items only:\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"for result in results:\n",
|
|
" print(\n",
|
|
" f\"Score: {result.get_score():.3f} | Color: {result.metadata.get('color')}\"\n",
|
|
" )\n",
|
|
" print(f\"Text: {result.get_text()[:80]}...\")\n",
|
|
" print(\"-\" * 60)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Filter by price range\n",
|
|
"filters = MetadataFilters(\n",
|
|
" filters=[\n",
|
|
" MetadataFilter(key=\"price\", operator=FilterOperator.LT, value=50.0),\n",
|
|
" ]\n",
|
|
")\n",
|
|
"\n",
|
|
"retriever = index.as_retriever(filters=filters, similarity_top_k=3)\n",
|
|
"results = retriever.retrieve(\"clothing\")\n",
|
|
"\n",
|
|
"print(\"Items under $50:\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"for result in results:\n",
|
|
" print(\n",
|
|
" f\"Score: {result.get_score():.3f} | Price: ${result.metadata.get('price')}\"\n",
|
|
" )\n",
|
|
" print(f\"Text: {result.get_text()[:80]}...\")\n",
|
|
" print(\"-\" * 60)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## RAG Query with LLM\n",
|
|
"\n",
|
|
"Use the vector store with an LLM for retrieval-augmented generation:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create query engine\n",
|
|
"query_engine = index.as_query_engine(similarity_top_k=3)\n",
|
|
"\n",
|
|
"# Ask a question\n",
|
|
"response = query_engine.query(\n",
|
|
" \"What blue clothing items do you have and what are their prices?\"\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\n",
|
|
" \"Question: What blue clothing items do you have and what are their prices?\"\n",
|
|
")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"print(f\"Answer: {response.response}\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"print(\"Sources:\")\n",
|
|
"for node in response.source_nodes:\n",
|
|
" print(f\" - {node.text[:60]}... (score: {node.score:.3f})\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## v2-Only Features\n",
|
|
"\n",
|
|
"### Delete Specific Nodes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Delete specific nodes by ID\n",
|
|
"# vector_store.delete_nodes(node_ids=[\"node_id_1\", \"node_id_2\"])\n",
|
|
"print(\"delete_nodes() - Delete specific nodes by their IDs\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Clear All Data (v2 only)\n",
|
|
"\n",
|
|
"v2 supports clearing all data from a collection - this is NOT available in v1:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Clear all data from the collection\n",
|
|
"# WARNING: This deletes ALL data in the collection!\n",
|
|
"# vector_store.clear()\n",
|
|
"print(\"clear() - Clears all data from collection (v2 only!)\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Hybrid Search (v2 Only)\n",
|
|
"\n",
|
|
"v2 supports **hybrid search**, combining vector similarity with text-based search for improved retrieval quality. This is particularly useful when you want to leverage both semantic understanding (vectors) and exact keyword matching (text search).\n",
|
|
"\n",
|
|
"### Supported Query Modes\n",
|
|
"\n",
|
|
"| Mode | Description | Use Case |\n",
|
|
"|------|-------------|----------|\n",
|
|
"| `DEFAULT` | Dense vector similarity search | Standard semantic search |\n",
|
|
"| `TEXT_SEARCH` | Full-text keyword search | Exact keyword matching |\n",
|
|
"| `HYBRID` | Vector + Text with RRF fusion | Best of both worlds |\n",
|
|
"| `SEMANTIC_HYBRID` | Vector + Semantic search | Auto-embedding semantic search |\n",
|
|
"\n",
|
|
"### Ranker Options\n",
|
|
"\n",
|
|
"| Ranker | Description |\n",
|
|
"|--------|-------------|\n",
|
|
"| `rrf` (default) | Reciprocal Rank Fusion with alpha weighting |\n",
|
|
"| `vertex` | AI-powered semantic ranking via Vertex AI |"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Create Hybrid-Enabled Vector Store\n",
|
|
"\n",
|
|
"To enable hybrid search, set `enable_hybrid=True` and specify which fields to use for text search:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create hybrid-enabled vector store\n",
|
|
"hybrid_vector_store = VertexAIVectorStore(\n",
|
|
" api_version=\"v2\",\n",
|
|
" project_id=PROJECT_ID,\n",
|
|
" region=REGION,\n",
|
|
" collection_id=COLLECTION_ID,\n",
|
|
" enable_hybrid=True,\n",
|
|
" text_search_fields=[\"text\", \"category\", \"color\"], # Fields for text search\n",
|
|
" default_hybrid_alpha=0.5, # Balance between vector and text (0=text only, 1=vector only)\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\n",
|
|
" f\"Hybrid vector store created with enable_hybrid={hybrid_vector_store.enable_hybrid}\"\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### TEXT_SEARCH Mode - Keyword Search\n",
|
|
"\n",
|
|
"Use `TEXT_SEARCH` mode for full-text keyword matching. This is useful when you want exact keyword matches rather than semantic similarity:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from llama_index.core.vector_stores.types import (\n",
|
|
" VectorStoreQuery,\n",
|
|
" VectorStoreQueryMode,\n",
|
|
")\n",
|
|
"\n",
|
|
"# TEXT_SEARCH: Full-text keyword search only\n",
|
|
"text_query = VectorStoreQuery(\n",
|
|
" query_str=\"blue cotton\", # Keywords to search for\n",
|
|
" mode=VectorStoreQueryMode.TEXT_SEARCH,\n",
|
|
" similarity_top_k=3,\n",
|
|
")\n",
|
|
"\n",
|
|
"results = hybrid_vector_store.query(text_query)\n",
|
|
"\n",
|
|
"print(\"TEXT_SEARCH Results (keyword matching):\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"for i, node in enumerate(results.nodes):\n",
|
|
" print(f\"{i+1}. {node.text[:80]}...\")\n",
|
|
" print(f\" Metadata: {node.metadata}\")\n",
|
|
" print()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### HYBRID Mode - Vector + Text Search\n",
|
|
"\n",
|
|
"Use `HYBRID` mode to combine vector similarity with text search. The `alpha` parameter controls the balance:\n",
|
|
"- `alpha=1.0` - Pure vector search\n",
|
|
"- `alpha=0.5` - Balanced\n",
|
|
"- `alpha=0.0` - Pure text search"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Compare different alpha values\n",
|
|
"print(\"Comparing alpha values:\")\n",
|
|
"print(\"=\" * 60)\n",
|
|
"\n",
|
|
"for alpha in [1.0, 0.5, 0.0]:\n",
|
|
" query = VectorStoreQuery(\n",
|
|
" query_embedding=embed_model.get_query_embedding(\n",
|
|
" \"warm winter clothing\"\n",
|
|
" ),\n",
|
|
" query_str=\"sweater green\", # Keywords favor green sweater\n",
|
|
" mode=VectorStoreQueryMode.HYBRID,\n",
|
|
" alpha=alpha,\n",
|
|
" similarity_top_k=2,\n",
|
|
" )\n",
|
|
" results = hybrid_vector_store.query(query)\n",
|
|
"\n",
|
|
" label = (\n",
|
|
" \"vector only\"\n",
|
|
" if alpha == 1.0\n",
|
|
" else \"text only\"\n",
|
|
" if alpha == 0.0\n",
|
|
" else \"balanced\"\n",
|
|
" )\n",
|
|
" print(f\"\\nalpha={alpha} ({label}):\")\n",
|
|
" for node in results.nodes:\n",
|
|
" print(f\" - {node.text[:60]}... | color={node.metadata.get('color')}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### SEMANTIC_HYBRID Mode\n",
|
|
"\n",
|
|
"`SEMANTIC_HYBRID` combines your dense vector search with Vertex AI's built-in semantic search. This requires the collection to have `vertex_embedding_config` configured for auto-embeddings."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# SEMANTIC_HYBRID: Vector + Vertex AI's semantic search\n",
|
|
"# Note: Requires collection with vertex_embedding_config\n",
|
|
"\n",
|
|
"semantic_query = VectorStoreQuery(\n",
|
|
" query_embedding=embed_model.get_query_embedding(\n",
|
|
" \"professional work attire\"\n",
|
|
" ),\n",
|
|
" query_str=\"formal office clothing\", # Semantic search text\n",
|
|
" mode=VectorStoreQueryMode.SEMANTIC_HYBRID,\n",
|
|
" similarity_top_k=3,\n",
|
|
")\n",
|
|
"\n",
|
|
"try:\n",
|
|
" results = hybrid_vector_store.query(semantic_query)\n",
|
|
" print(\"SEMANTIC_HYBRID Results:\")\n",
|
|
" print(\"-\" * 60)\n",
|
|
" for i, node in enumerate(results.nodes):\n",
|
|
" print(f\"{i+1}. {node.text[:80]}...\")\n",
|
|
"except Exception as e:\n",
|
|
" print(\n",
|
|
" f\"SEMANTIC_HYBRID requires collection with vertex_embedding_config: {e}\"\n",
|
|
" )"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Using VertexRanker\n",
|
|
"\n",
|
|
"Instead of RRF, you can use Vertex AI's semantic ranker for AI-powered result ranking:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create vector store with VertexRanker\n",
|
|
"vertex_ranker_store = VertexAIVectorStore(\n",
|
|
" api_version=\"v2\",\n",
|
|
" project_id=PROJECT_ID,\n",
|
|
" region=REGION,\n",
|
|
" collection_id=COLLECTION_ID,\n",
|
|
" enable_hybrid=True,\n",
|
|
" text_search_fields=[\"text\", \"category\"],\n",
|
|
" hybrid_ranker=\"vertex\", # Use Vertex AI's semantic ranker\n",
|
|
" vertex_ranker_model=\"semantic-ranker-default@latest\",\n",
|
|
" vertex_ranker_title_field=\"category\", # Field to use as title\n",
|
|
" vertex_ranker_content_field=\"text\", # Field to use as content\n",
|
|
")\n",
|
|
"\n",
|
|
"# Query with VertexRanker\n",
|
|
"query = VectorStoreQuery(\n",
|
|
" query_embedding=embed_model.get_query_embedding(\"casual everyday wear\"),\n",
|
|
" query_str=\"comfortable shirt\",\n",
|
|
" mode=VectorStoreQueryMode.HYBRID,\n",
|
|
" similarity_top_k=3,\n",
|
|
")\n",
|
|
"\n",
|
|
"results = vertex_ranker_store.query(query)\n",
|
|
"\n",
|
|
"print(\"HYBRID with VertexRanker Results:\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"for i, node in enumerate(results.nodes):\n",
|
|
" print(f\"{i+1}. {node.text[:80]}...\")\n",
|
|
" print(f\" Category: {node.metadata.get('category')}\")\n",
|
|
" print()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Hybrid Search with Query Engine (RAG)\n",
|
|
"\n",
|
|
"You can also use hybrid search with the standard LlamaIndex query engine for RAG applications:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Create index with hybrid-enabled vector store\n",
|
|
"hybrid_storage_context = StorageContext.from_defaults(\n",
|
|
" vector_store=hybrid_vector_store\n",
|
|
")\n",
|
|
"hybrid_index = VectorStoreIndex.from_vector_store(\n",
|
|
" vector_store=hybrid_vector_store,\n",
|
|
" embed_model=embed_model,\n",
|
|
")\n",
|
|
"\n",
|
|
"# Create query engine with hybrid mode\n",
|
|
"hybrid_query_engine = hybrid_index.as_query_engine(\n",
|
|
" vector_store_query_mode=VectorStoreQueryMode.HYBRID,\n",
|
|
" similarity_top_k=3,\n",
|
|
" alpha=0.7, # Favor vector search slightly\n",
|
|
")\n",
|
|
"\n",
|
|
"# Ask a question using RAG with hybrid retrieval\n",
|
|
"response = hybrid_query_engine.query(\n",
|
|
" \"What comfortable blue clothing options are available?\"\n",
|
|
")\n",
|
|
"\n",
|
|
"print(\"Question: What comfortable blue clothing options are available?\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"print(f\"Answer: {response.response}\")\n",
|
|
"print(\"-\" * 60)\n",
|
|
"print(\"Sources:\")\n",
|
|
"for node in response.source_nodes:\n",
|
|
" print(f\" - {node.text[:60]}... (score: {node.score:.3f})\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Hybrid Search Parameters Reference\n",
|
|
"\n",
|
|
"| Parameter | Type | Default | Description |\n",
|
|
"|-----------|------|---------|-------------|\n",
|
|
"| `enable_hybrid` | `bool` | `False` | Enable hybrid search modes |\n",
|
|
"| `text_search_fields` | `List[str]` | `None` | Data fields for text search |\n",
|
|
"| `embedding_field` | `str` | `\"embedding\"` | Vector field name |\n",
|
|
"| `default_hybrid_alpha` | `float` | `0.5` | Default RRF weight (0=text, 1=vector) |\n",
|
|
"| `hybrid_ranker` | `str` | `\"rrf\"` | Ranker: \"rrf\" or \"vertex\" |\n",
|
|
"| `semantic_task_type` | `str` | `\"RETRIEVAL_QUERY\"` | Task type for SemanticSearch |\n",
|
|
"| `vertex_ranker_model` | `str` | `\"semantic-ranker-default@latest\"` | VertexRanker model |\n",
|
|
"| `vertex_ranker_title_field` | `str` | `None` | Title field for VertexRanker |\n",
|
|
"| `vertex_ranker_content_field` | `str` | `None` | Content field for VertexRanker |"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Clean Up\n",
|
|
"\n",
|
|
"Delete the collection when done to avoid charges:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"CLEANUP = False # Set to True to delete the collection\n",
|
|
"\n",
|
|
"if CLEANUP:\n",
|
|
" from google.cloud import vectorsearch_v1beta\n",
|
|
"\n",
|
|
" client = vectorsearch_v1beta.VectorSearchServiceClient()\n",
|
|
" collection_name = (\n",
|
|
" f\"projects/{PROJECT_ID}/locations/{REGION}/collections/{COLLECTION_ID}\"\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(f\"Deleting collection: {collection_name}\")\n",
|
|
" client.delete_collection(name=collection_name)\n",
|
|
" print(\"Collection deleted.\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Summary\n",
|
|
"\n",
|
|
"This notebook demonstrated:\n",
|
|
"\n",
|
|
"1. **Simple Setup**: v2 only requires a collection - no index/endpoint deployment\n",
|
|
"2. **Easy Integration**: Just add `api_version=\"v2\"` to use the new API\n",
|
|
"3. **Same Interface**: All LlamaIndex operations (add, query, delete) work the same\n",
|
|
"4. **New Features**: v2 adds `clear()` method not available in v1\n",
|
|
"5. **Hybrid Search**: Combine vector and text search for better retrieval:\n",
|
|
" - `TEXT_SEARCH` - Full-text keyword search\n",
|
|
" - `HYBRID` - Vector + text with RRF fusion\n",
|
|
" - `SEMANTIC_HYBRID` - Vector + semantic search\n",
|
|
" - VertexRanker for AI-powered ranking\n",
|
|
"\n",
|
|
"### Migration from v1\n",
|
|
"\n",
|
|
"```python\n",
|
|
"# v1 (old)\n",
|
|
"vector_store = VertexAIVectorStore(\n",
|
|
" project_id=\"...\",\n",
|
|
" region=\"...\",\n",
|
|
" index_id=\"projects/.../indexes/123\",\n",
|
|
" endpoint_id=\"projects/.../indexEndpoints/456\",\n",
|
|
" gcs_bucket_name=\"my-bucket\"\n",
|
|
")\n",
|
|
"\n",
|
|
"# v2 (new)\n",
|
|
"vector_store = VertexAIVectorStore(\n",
|
|
" api_version=\"v2\",\n",
|
|
" project_id=\"...\",\n",
|
|
" region=\"...\",\n",
|
|
" collection_id=\"my-collection\"\n",
|
|
")\n",
|
|
"\n",
|
|
"# v2 with hybrid search\n",
|
|
"vector_store = VertexAIVectorStore(\n",
|
|
" api_version=\"v2\",\n",
|
|
" project_id=\"...\",\n",
|
|
" region=\"...\",\n",
|
|
" collection_id=\"my-collection\",\n",
|
|
" enable_hybrid=True,\n",
|
|
" text_search_fields=[\"text\", \"title\"],\n",
|
|
")\n",
|
|
"```\n",
|
|
"\n",
|
|
"For detailed migration instructions, see [V2_MIGRATION.md](https://github.com/run-llama/llama_index/blob/main/llama-index-integrations/vector_stores/llama-index-vector-stores-vertexaivectorsearch/V2_MIGRATION.md)"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|