From eab70326f14e1047f044af2000310adcf033de0a Mon Sep 17 00:00:00 2001 From: Vishal Bala Date: Tue, 9 Dec 2025 18:05:45 +0100 Subject: [PATCH 1/6] Install latest version of Redis for notebook --- .../vector-search/02_hybrid_search.ipynb | 38 +- .../06_hnsw_to_svs_vamana_migration.ipynb | 723 +++++++++++------- .../07_flat_to_svs_vamana_migration.ipynb | 620 ++++++++------- 3 files changed, 811 insertions(+), 570 deletions(-) diff --git a/python-recipes/vector-search/02_hybrid_search.ipynb b/python-recipes/vector-search/02_hybrid_search.ipynb index b96aae93..5eaaec99 100644 --- a/python-recipes/vector-search/02_hybrid_search.ipynb +++ b/python-recipes/vector-search/02_hybrid_search.ipynb @@ -62,10 +62,10 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": null, "source": [ "# NBVAL_SKIP\n", "!git clone https://github.com/redis-developer/redis-ai-resources.git temp_repo\n", @@ -74,49 +74,51 @@ ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "### Install Redis Stack\n", + "### Install Redis\n", "\n", - "Later in this tutorial, Redis will be used to store, index, and query vector\n", - "embeddings and full text fields. **We need to have a Redis\n", - "instance available.**\n", + "For this tutorial you will need a running instance of Redis if you don't already have one.\n", "\n", "#### Local Redis\n", - "Use the shell script below to download, extract, and install [Redis Stack](https://redis.io/docs/getting-started/install-stack/) directly from the Redis package archive." + "Use the shell script below to download, extract, and install [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/apt/) directly from the Redis package archive for a Linux environment." ] }, { - "cell_type": "code", - "execution_count": null, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": 20, "source": [ "# NBVAL_SKIP\n", "%%sh\n", + "sudo apt-get install lsb-release curl gpg\n", "curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\n", + "sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg\n", "echo \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\n", - "sudo apt-get update > /dev/null 2>&1\n", - "sudo apt-get install redis-stack-server > /dev/null 2>&1\n", - "redis-stack-server --daemonize yes" + "sudo apt-get update\n", + "sudo apt-get install redis\n", + "\n", + "redis-server --version\n", + "redis-server --daemonize yes --loadmodule /usr/lib/redis/modules/redisearch.so" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "#### Alternative Redis Access (Cloud, Docker, other)\n", "There are many ways to get the necessary redis-stack instance running\n", "1. On cloud, deploy a [FREE instance of Redis in the cloud](https://redis.com/try-free/). Or, if you have your\n", "own version of Redis Enterprise running, that works too!\n", "2. Per OS, [see the docs](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)\n", - "3. With docker: `docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest`" + "3. With docker: `docker run -d --name redis -p 6379:6379 redis:latest`" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "### Define the Redis Connection URL\n", "\n", @@ -124,10 +126,10 @@ ] }, { - "cell_type": "code", - "execution_count": 1, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": null, "source": [ "import os\n", "import warnings\n", diff --git a/python-recipes/vector-search/06_hnsw_to_svs_vamana_migration.ipynb b/python-recipes/vector-search/06_hnsw_to_svs_vamana_migration.ipynb index 8b2cee73..22acb656 100644 --- a/python-recipes/vector-search/06_hnsw_to_svs_vamana_migration.ipynb +++ b/python-recipes/vector-search/06_hnsw_to_svs_vamana_migration.ipynb @@ -8,7 +8,7 @@ "# Migrating from HNSW to SVS-VAMANA\n", "\n", "## Let's Begin!\n", - "\"Open\n", + "\"Open\n", "\n", "This notebook demonstrates how to migrate existing HNSW vector indices to SVS-VAMANA for improved memory efficiency while maintaining search quality.\n", "\n", @@ -23,7 +23,7 @@ "\n", "## Prerequisites\n", "\n", - "- Redis Stack 8.2.0+ with RediSearch 2.8.10+\n", + "- Redis 8.2.0+ (with the search module active)\n", "- Existing HNSW index with substantial data (1000+ documents recommended)\n", "- High-dimensional vectors (768+ dimensions for best compression benefits)\n", "\n", @@ -90,7 +90,7 @@ "This notebook uses **RedisVL vectorizers** for generating embeddings and **Redis Stack** for vector search.\n", "\n", "**Requirements:**\n", - "- Redis Stack 8.2.0+ with RediSearch 2.8.10+ (for SVS-VAMANA support)\n", + "- Redis 8.2.0+ (with the search module active, for SVS-VAMANA support)\n", "- redisvl>=0.11.0 (required for SVS-VAMANA migration features and vectorizers)\n", "- redis-py>=6.4.0 (required for compatibility with RedisVL 0.11.0+)\n", "- numpy (for vector operations)\n", @@ -119,22 +119,57 @@ ] } ], + "source": "%pip install \"redisvl>=0.11.0\" \"redis>=6.4.0\" \"numpy>=1.21.0\" \"sentence-transformers>=2.2.0\"" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "### Download Sample Data" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:18.087794Z", + "start_time": "2025-12-09T15:18:14.222219Z" + } + }, + "cell_type": "code", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Cloning into 'temp_repo'...\r\n", + "remote: Enumerating objects: 2879, done.\u001B[K\r\n", + "remote: Counting objects: 100% (1068/1068), done.\u001B[K\r\n", + "remote: Compressing objects: 100% (492/492), done.\u001B[K\r\n", + "remote: Total 2879 (delta 784), reused 733 (delta 574), pack-reused 1811 (from 2)\u001B[K\r\n", + "Receiving objects: 100% (2879/2879), 68.57 MiB | 34.97 MiB/s, done.\r\n", + "Resolving deltas: 100% (1649/1649), done.\r\n", + "mv: rename temp_repo/python-recipes/vector-search/resources to ./resources: Directory not empty\r\n" + ] + } + ], + "execution_count": 3, "source": [ - "%pip install git+https://github.com/redis/redis-vl-python.git \"redis>=6.4.0\" \"numpy>=1.21.0\" \"sentence-transformers>=2.2.0\"" + "# NBVAL_SKIP\n", + "!git clone https://github.com/redis-developer/redis-ai-resources.git temp_repo\n", + "!mv temp_repo/python-recipes/vector-search/resources .\n", + "!rm -rf temp_repo" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### Install Redis Stack\n", + "### Install Redis\n", "\n", "Later in this tutorial, Redis will be used to store, index, and query vector\n", "embeddings and full text fields. **We need to have a Redis\n", "instance available.**\n", "\n", "#### Local Redis\n", - "Use the shell script below to download, extract, and install [Redis Stack](https://redis.io/docs/getting-started/install-stack/) directly from the Redis package archive." + "Use the shell script below to download, extract, and install [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/apt/) directly from the Redis package archive for a Linux environment." ] }, { @@ -145,11 +180,15 @@ "source": [ "# NBVAL_SKIP\n", "%%sh\n", + "sudo apt-get install lsb-release curl gpg\n", "curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\n", + "sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg\n", "echo \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\n", - "sudo apt-get update > /dev/null 2>&1\n", - "sudo apt-get install redis-stack-server > /dev/null 2>&1\n", - "redis-stack-server --daemonize yes" + "sudo apt-get update\n", + "sudo apt-get install redis\n", + "\n", + "redis-server --version\n", + "redis-server --daemonize yes --loadmodule /usr/lib/redis/modules/redisearch.so" ] }, { @@ -161,7 +200,7 @@ "1. On cloud, deploy a [FREE instance of Redis in the cloud](https://redis.com/try-free/). Or, if you have your\n", "own version of Redis Enterprise running, that works too!\n", "2. Per OS, [see the docs](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)\n", - "3. With docker: `docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest`" + "3. With docker: `docker run -d --name redis -p 6379:6379 redis:latest`" ] }, { @@ -175,23 +214,17 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“š Libraries imported successfully!\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:10.599659Z", + "start_time": "2025-12-09T15:18:10.050008Z" } - ], + }, "source": [ "import os\n", "import json\n", "import numpy as np\n", "import time\n", - "from typing import List, Dict, Any\n", "\n", "# Redis and RedisVL imports\n", "import redis\n", @@ -213,7 +246,17 @@ "REDIS_URL = f\"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}\"\n", "\n", "print(\"๐Ÿ“š Libraries imported successfully!\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“š Libraries imported successfully!\n" + ] + } + ], + "execution_count": 1 }, { "cell_type": "markdown", @@ -226,19 +269,12 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "โœ… Redis connection successful\n", - "๐Ÿ“Š Redis version: 8.2.2\n", - "โœ… SVS-VAMANA supported\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:12.750534Z", + "start_time": "2025-12-09T15:18:12.741314Z" } - ], + }, "source": [ "# Test Redis connection and SVS support\n", "try:\n", @@ -261,7 +297,19 @@ "except Exception as e:\n", " print(f\"โŒ Redis connection failed: {e}\")\n", " print(\"Please ensure Redis Stack is running on localhost:6379\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Redis connection successful\n", + "๐Ÿ“Š Redis version: 8.4.0\n", + "โœ… SVS-VAMANA supported\n" + ] + } + ], + "execution_count": 2 }, { "cell_type": "markdown", @@ -274,24 +322,12 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“ฝ๏ธ Loaded 20 movie records\n", - "Sample movie: Explosive Pursuit\n", - "Genres available: {'comedy', 'action'}\n", - "\n", - "๐Ÿ”ง Configuration:\n", - "Vector dimensions: 768\n", - "Dataset size: 20 movie documents\n", - "Vectorizer: RedisVL HFTextVectorizer\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:24.996005Z", + "start_time": "2025-12-09T15:18:24.992212Z" } - ], + }, "source": [ "# Load the movies dataset\n", "with open('resources/movies.json', 'r') as f:\n", @@ -315,7 +351,24 @@ " f\"Vectorizer: RedisVL HFTextVectorizer\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“ฝ๏ธ Loaded 20 movie records\n", + "Sample movie: Explosive Pursuit\n", + "Genres available: {'action', 'comedy'}\n", + "\n", + "๐Ÿ”ง Configuration:\n", + "Vector dimensions: 768\n", + "Dataset size: 20 movie documents\n", + "Vectorizer: RedisVL HFTextVectorizer\n" + ] + } + ], + "execution_count": 4 }, { "cell_type": "markdown", @@ -328,25 +381,12 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Creating HNSW index with optimized settings...\n", - "โœ… Created HNSW index: hnsw_demo_index\n", - "\n", - "๐Ÿ”ง HNSW Configuration:\n", - "M (connections per node): 16\n", - "EF Construction: 200\n", - "EF Runtime: 10\n", - "Distance metric: cosine\n", - "Data type: float32\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:27.075125Z", + "start_time": "2025-12-09T15:18:27.065560Z" } - ], + }, "source": [ "# Create HNSW schema with production-like settings\n", "hnsw_schema = {\n", @@ -391,7 +431,25 @@ " f\"Data type: float32\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating HNSW index with optimized settings...\n", + "โœ… Created HNSW index: hnsw_demo_index\n", + "\n", + "๐Ÿ”ง HNSW Configuration:\n", + "M (connections per node): 16\n", + "EF Construction: 200\n", + "EF Runtime: 10\n", + "Distance metric: cosine\n", + "Data type: float32\n" + ] + } + ], + "execution_count": 5 }, { "cell_type": "markdown", @@ -404,22 +462,12 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ”„ Generating embeddings for movie descriptions...\n", - "๐Ÿš€ Using RedisVL HFTextVectorizer...\n", - "12:13:05 sentence_transformers.SentenceTransformer INFO Use pytorch device_name: mps\n", - "12:13:05 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-mpnet-base-v2\n", - "โœ… Generated 20 real embeddings using RedisVL HFTextVectorizer\n", - "๐Ÿ“Š Embedding shape: (20, 768)\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:38.464659Z", + "start_time": "2025-12-09T15:18:28.435730Z" } - ], + }, "source": [ "# Generate embeddings using RedisVL vectorizers\n", "print(\"๐Ÿ”„ Generating embeddings for movie descriptions...\")\n", @@ -438,21 +486,45 @@ "\n", "print(f\"โœ… Generated {len(embeddings)} real embeddings using RedisVL HFTextVectorizer\")\n", "print(f\"๐Ÿ“Š Embedding shape: {embeddings.shape}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“ฆ Prepared 20 documents for indexing\n" + "๐Ÿ”„ Generating embeddings for movie descriptions...\n", + "๐Ÿš€ Using RedisVL HFTextVectorizer...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/vishal.bala/PycharmProjects/redis-ai-resources/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16:18:34 sentence_transformers.SentenceTransformer INFO Use pytorch device_name: mps\n", + "16:18:34 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-mpnet-base-v2\n", + "โœ… Generated 20 real embeddings using RedisVL HFTextVectorizer\n", + "๐Ÿ“Š Embedding shape: (20, 768)\n" ] } ], + "execution_count": 6 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:40.269494Z", + "start_time": "2025-12-09T15:18:40.266771Z" + } + }, "source": [ "# Prepare data for loading into HNSW index\n", "sample_data = []\n", @@ -467,27 +539,26 @@ " })\n", "\n", "print(f\"๐Ÿ“ฆ Prepared {len(sample_data)} documents for indexing\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“ฅ Loading data into HNSW index...\n", - " Loaded 20/20 documents\n", - "โณ Waiting for HNSW indexing to complete...\n", - "\n", - "โœ… HNSW index loaded with 20 documents\n", - "Index size: 3.2259750366210938 MB\n", - "Indexing time: ~5 seconds (HNSW graph construction)\n" + "๐Ÿ“ฆ Prepared 20 documents for indexing\n" ] } ], + "execution_count": 7 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:46.060722Z", + "start_time": "2025-12-09T15:18:41.031015Z" + } + }, "source": [ "# Load data into HNSW index\n", "print(\"๐Ÿ“ฅ Loading data into HNSW index...\")\n", @@ -509,7 +580,23 @@ " f\"Indexing time: ~5 seconds (HNSW graph construction)\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“ฅ Loading data into HNSW index...\n", + " Loaded 20/20 documents\n", + "โณ Waiting for HNSW indexing to complete...\n", + "\n", + "โœ… HNSW index loaded with 20 documents\n", + "Index size: 3.2259750366210938 MB\n", + "Indexing time: ~5 seconds (HNSW graph construction)\n" + ] + } + ], + "execution_count": 8 }, { "cell_type": "markdown", @@ -522,41 +609,12 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ” Analyzing data for optimal compression settings...\n", - "\n", - "๐Ÿ“Š Compression Recommendations:\n", - "\n", - "๐Ÿ—œ๏ธ Memory Priority:\n", - " Algorithm: svs-vamana\n", - " Compression: LVQ4\n", - " Datatype: float32\n", - " Dimensions: 768 โ†’ None\n", - "\n", - "โš–๏ธ Balanced Priority:\n", - " Algorithm: svs-vamana\n", - " Compression: LVQ4x4\n", - " Datatype: float32\n", - " Dimensions: 768 โ†’ None\n", - "\n", - "โšก Performance Priority:\n", - " Algorithm: svs-vamana\n", - " Compression: LVQ4x4\n", - " Datatype: float32\n", - " Dimensions: 768 โ†’ None\n", - "\n", - "โœ… Selected configuration: Memory Priority\n", - "Expected memory reduction: ~0.0% from dimension reduction\n", - "Additional savings from float32 compression\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:47.623552Z", + "start_time": "2025-12-09T15:18:47.619953Z" } - ], + }, "source": [ "# Get compression recommendation\n", "print(\"๐Ÿ” Analyzing data for optimal compression settings...\")\n", @@ -601,7 +659,41 @@ " f\"Additional savings from {selected_config.datatype} compression\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ” Analyzing data for optimal compression settings...\n", + "\n", + "๐Ÿ“Š Compression Recommendations:\n", + "\n", + "๐Ÿ—œ๏ธ Memory Priority:\n", + " Algorithm: svs-vamana\n", + " Compression: LVQ4\n", + " Datatype: float32\n", + " Dimensions: 768 โ†’ None\n", + "\n", + "โš–๏ธ Balanced Priority:\n", + " Algorithm: svs-vamana\n", + " Compression: LVQ4x4\n", + " Datatype: float32\n", + " Dimensions: 768 โ†’ None\n", + "\n", + "โšก Performance Priority:\n", + " Algorithm: svs-vamana\n", + " Compression: LVQ4x4\n", + " Datatype: float32\n", + " Dimensions: 768 โ†’ None\n", + "\n", + "โœ… Selected configuration: Memory Priority\n", + "Expected memory reduction: ~0.0% from dimension reduction\n", + "Additional savings from float32 compression\n" + ] + } + ], + "execution_count": 9 }, { "cell_type": "markdown", @@ -614,21 +706,12 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Creating SVS-VAMANA index with compression...\n", - "โœ… Created SVS-VAMANA index: svs_demo_index\n", - "Compression: LVQ4\n", - "Datatype: float32\n", - "Dimensions: 768 โ†’ 768\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:49.967891Z", + "start_time": "2025-12-09T15:18:49.957951Z" } - ], + }, "source": [ "# Create SVS-VAMANA schema with compression\n", "svs_schema = {\n", @@ -666,7 +749,21 @@ " f\"Dimensions: {dims} โ†’ {target_dims}\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating SVS-VAMANA index with compression...\n", + "โœ… Created SVS-VAMANA index: svs_demo_index\n", + "Compression: LVQ4\n", + "Datatype: float32\n", + "Dimensions: 768 โ†’ 768\n" + ] + } + ], + "execution_count": 10 }, { "cell_type": "markdown", @@ -679,19 +776,12 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ”„ Extracting data from HNSW index...\n", - "Found 20 documents to migrate\n", - "Prepared 20 documents for migration\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:51.877234Z", + "start_time": "2025-12-09T15:18:51.862453Z" } - ], + }, "source": [ "# Extract data from HNSW index\n", "print(\"๐Ÿ”„ Extracting data from HNSW index...\")\n", @@ -730,26 +820,28 @@ " })\n", "\n", "print(f\"Prepared {len(svs_data)} documents for migration\")" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“ฅ Loading data into SVS-VAMANA index...\n", - " Migrated 20/20 documents\n", - "โณ Waiting for SVS-VAMANA indexing to complete...\n", - "\n", - "โœ… Migration complete! SVS index has 20 documents\n", - "Index size: 3.017791748046875 MB\n" + "๐Ÿ”„ Extracting data from HNSW index...\n", + "Found 20 documents to migrate\n", + "Prepared 20 documents for migration\n" ] } ], + "execution_count": 11 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:57.887145Z", + "start_time": "2025-12-09T15:18:52.866035Z" + } + }, "source": [ "# Load data into SVS index\n", "print(\"๐Ÿ“ฅ Loading data into SVS-VAMANA index...\")\n", @@ -775,7 +867,22 @@ " print(\"โš ๏ธ No data to migrate. Make sure the HNSW index was populated first.\")\n", " print(\" Run the previous cells to load data into the HNSW index.\")\n", " svs_info = svs_index.info()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“ฅ Loading data into SVS-VAMANA index...\n", + " Migrated 20/20 documents\n", + "โณ Waiting for SVS-VAMANA indexing to complete...\n", + "\n", + "โœ… Migration complete! SVS index has 20 documents\n", + "Index size: 3.0177383422851563 MB\n" + ] + } + ], + "execution_count": 12 }, { "cell_type": "markdown", @@ -788,23 +895,12 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“Š Memory Usage Comparison\n", - "========================================\n", - "Original HNSW index: 3.23 MB\n", - "SVS-VAMANA index: 3.02 MB\n", - "\n", - "๐Ÿ’ฐ Memory savings: 6.5%\n", - "Absolute reduction: 0.21 MB\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:18:59.379258Z", + "start_time": "2025-12-09T15:18:59.376792Z" } - ], + }, "source": [ "# Helper function to extract memory info\n", "def get_memory_mb(index_info):\n", @@ -842,7 +938,23 @@ " print(\"โณ SVS index still indexing - memory comparison pending\")\n", "else:\n", " print(\"โš ๏ธ Memory information not available\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“Š Memory Usage Comparison\n", + "========================================\n", + "Original HNSW index: 3.23 MB\n", + "SVS-VAMANA index: 3.02 MB\n", + "\n", + "๐Ÿ’ฐ Memory savings: 6.5%\n", + "Absolute reduction: 0.21 MB\n" + ] + } + ], + "execution_count": 13 }, { "cell_type": "markdown", @@ -855,18 +967,12 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ” Generating test queries for quality validation...\n", - "Generated 10 test queries\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:03.384495Z", + "start_time": "2025-12-09T15:19:03.379214Z" } - ], + }, "source": [ "# Generate test queries\n", "print(\"๐Ÿ” Generating test queries for quality validation...\")\n", @@ -882,22 +988,27 @@ " test_queries.append(query_vec)\n", "\n", "print(f\"Generated {len(test_queries)} test queries\")" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ” Testing HNSW search quality...\n", - "HNSW search completed in 0.010 seconds\n" + "๐Ÿ” Generating test queries for quality validation...\n", + "Generated 10 test queries\n" ] } ], + "execution_count": 14 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:04.652101Z", + "start_time": "2025-12-09T15:19:04.641255Z" + } + }, "source": [ "# Test HNSW search quality\n", "print(\"๐Ÿ” Testing HNSW search quality...\")\n", @@ -918,22 +1029,27 @@ "\n", "hnsw_time = time.time() - hnsw_start\n", "print(f\"HNSW search completed in {hnsw_time:.3f} seconds\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ” Testing SVS-VAMANA search quality...\n", - "SVS-VAMANA search completed in 0.009 seconds\n" + "๐Ÿ” Testing HNSW search quality...\n", + "HNSW search completed in 0.008 seconds\n" ] } ], + "execution_count": 15 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:05.586458Z", + "start_time": "2025-12-09T15:19:05.574807Z" + } + }, "source": [ "# Test SVS-VAMANA search quality\n", "print(\"๐Ÿ” Testing SVS-VAMANA search quality...\")\n", @@ -963,32 +1079,27 @@ "\n", "svs_time = time.time() - svs_start\n", "print(f\"SVS-VAMANA search completed in {svs_time:.3f} seconds\")" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“Š Search Quality Comparison\n", - "========================================\n", - "HNSW (baseline): 100% recall (exact graph-based search)\n", - "SVS-VAMANA Recall@5: 100.0% (vs HNSW baseline)\n", - "SVS-VAMANA Recall@10: 100.0% (vs HNSW baseline)\n", - "\n", - "โฑ๏ธ Performance Comparison:\n", - "HNSW query time: 0.010s (1.0ms per query)\n", - "SVS-VAMANA query time: 0.009s (0.9ms per query)\n", - "Speed difference: +5.9%\n", - "\n", - "๐ŸŽฏ Quality Assessment: ๐ŸŸข Excellent - Minimal quality loss\n" + "๐Ÿ” Testing SVS-VAMANA search quality...\n", + "SVS-VAMANA search completed in 0.009 seconds\n" ] } ], + "execution_count": 16 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:06.627904Z", + "start_time": "2025-12-09T15:19:06.623676Z" + } + }, "source": [ "# Calculate recall and performance metrics\n", "def calculate_recall(reference_results, test_results, k=10):\n", @@ -1035,7 +1146,28 @@ " quality_assessment = \"๐Ÿ”ด Poor - Migration not recommended\"\n", "\n", "print(f\"\\n๐ŸŽฏ Quality Assessment: {quality_assessment}\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“Š Search Quality Comparison\n", + "========================================\n", + "HNSW (baseline): 100% recall (exact graph-based search)\n", + "SVS-VAMANA Recall@5: 100.0% (vs HNSW baseline)\n", + "SVS-VAMANA Recall@10: 100.0% (vs HNSW baseline)\n", + "\n", + "โฑ๏ธ Performance Comparison:\n", + "HNSW query time: 0.008s (0.8ms per query)\n", + "SVS-VAMANA query time: 0.009s (0.9ms per query)\n", + "Speed difference: -10.7%\n", + "\n", + "๐ŸŽฏ Quality Assessment: ๐ŸŸข Excellent - Minimal quality loss\n" + ] + } + ], + "execution_count": 17 }, { "cell_type": "markdown", @@ -1048,25 +1180,12 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿค” Migration Decision Analysis\n", - "========================================\n", - "\n", - "๐Ÿ“Š Criteria Evaluation:\n", - "Memory savings: 6.5% โœ… (threshold: 5%)\n", - "Search quality: 1.000 โœ… (threshold: 0.85)\n", - "\n", - "๐ŸŽฏ Migration Recommendation: ๐ŸŸข RECOMMENDED\n", - "๐Ÿ’ญ Reasoning: Migration provides significant memory savings while maintaining good search quality.\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:19.464223Z", + "start_time": "2025-12-09T15:19:19.460488Z" } - ], + }, "source": [ "# Migration decision logic\n", "memory_savings_threshold = 5 # Minimum % memory savings\n", @@ -1105,7 +1224,25 @@ " f\"๐Ÿ’ญ Reasoning: {reasoning}\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿค” Migration Decision Analysis\n", + "========================================\n", + "\n", + "๐Ÿ“Š Criteria Evaluation:\n", + "Memory savings: 6.5% โœ… (threshold: 5%)\n", + "Search quality: 1.000 โœ… (threshold: 0.85)\n", + "\n", + "๐ŸŽฏ Migration Recommendation: ๐ŸŸข RECOMMENDED\n", + "๐Ÿ’ญ Reasoning: Migration provides significant memory savings while maintaining good search quality.\n" + ] + } + ], + "execution_count": 18 }, { "cell_type": "markdown", @@ -1118,28 +1255,12 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿงน Cleaning up demonstration indices...\n", - "โœ… Deleted HNSW demonstration index\n", - "โœ… Deleted SVS-VAMANA demonstration index\n", - "\n", - "๐ŸŽ‰ HNSW to SVS-VAMANA migration demonstration complete!\n", - "\n", - "Next steps:\n", - "1. Apply learnings to your production HNSW indices\n", - "2. Test with your actual query patterns and data\n", - "3. Monitor performance in your environment\n", - "4. Consider gradual rollout strategy\n", - "5. Evaluate impact on applications using HNSW-specific features\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:19:25.487110Z", + "start_time": "2025-12-09T15:19:25.480324Z" } - ], + }, "source": [ "print(\"๐Ÿงน Cleaning up demonstration indices...\")\n", "\n", @@ -1167,14 +1288,28 @@ " \"5. Evaluate impact on applications using HNSW-specific features\",\n", " sep=\"\\n\"\n", ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿงน Cleaning up demonstration indices...\n", + "โœ… Deleted HNSW demonstration index\n", + "โœ… Deleted SVS-VAMANA demonstration index\n", + "\n", + "๐ŸŽ‰ HNSW to SVS-VAMANA migration demonstration complete!\n", + "\n", + "Next steps:\n", + "1. Apply learnings to your production HNSW indices\n", + "2. Test with your actual query patterns and data\n", + "3. Monitor performance in your environment\n", + "4. Consider gradual rollout strategy\n", + "5. Evaluate impact on applications using HNSW-specific features\n" + ] + } + ], + "execution_count": 19 } ], "metadata": { diff --git a/python-recipes/vector-search/07_flat_to_svs_vamana_migration.ipynb b/python-recipes/vector-search/07_flat_to_svs_vamana_migration.ipynb index 6b7789f5..7807c8fa 100644 --- a/python-recipes/vector-search/07_flat_to_svs_vamana_migration.ipynb +++ b/python-recipes/vector-search/07_flat_to_svs_vamana_migration.ipynb @@ -8,7 +8,7 @@ "# Migrating from FLAT to SVS-VAMANA\n", "\n", "## Let's Begin!\n", - "\"Open\n", + "\"Open\n", "\n", "This notebook demonstrates how to migrate existing FLAT vector indices to SVS-VAMANA for improved memory efficiency and cost savings.\n", "\n", @@ -23,7 +23,7 @@ "\n", "## Prerequisites\n", "\n", - "- Redis Stack 8.2.0+ with RediSearch 2.8.10+\n", + "- Redis 8.2.0+ (with the search module active)\n", "- Existing vector index with substantial data (1000+ documents recommended)\n", "- Vector embeddings (768 dimensions using sentence-transformers/all-mpnet-base-v2)" ] @@ -76,7 +76,7 @@ "This notebook uses **RedisVL vectorizers** for generating embeddings and **Redis Stack** for vector search.\n", "\n", "**Requirements:**\n", - "- Redis Stack 8.2.0+ with RediSearch 2.8.10+ (for SVS-VAMANA support)\n", + "- Redis 8.2.0+ (with the search module active, for SVS-VAMANA support)\n", "- redisvl>=0.11.0 (required for SVS-VAMANA migration features and vectorizers)\n", "- redis-py>=6.4.0 (required for compatibility with RedisVL 0.11.0+)\n", "- numpy (for vector operations)\n", @@ -96,49 +96,68 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": "%pip install \"redisvl>=0.11.0\" \"redis>=6.4.0\" \"numpy>=1.21.0\" \"sentence-transformers>=2.2.0\"" + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "### Download Sample Data" + }, + { + "metadata": {}, + "cell_type": "code", + "outputs": [], + "execution_count": null, "source": [ - "%pip install git+https://github.com/redis/redis-vl-python.git \"redis>=6.4.0\" \"numpy>=1.21.0\" \"sentence-transformers>=2.2.0\"" + "# NBVAL_SKIP\n", + "!git clone https://github.com/redis-developer/redis-ai-resources.git temp_repo\n", + "!mv temp_repo/python-recipes/vector-search/resources .\n", + "!rm -rf temp_repo" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "### Install Redis Stack\n", + "### Install Redis\n", "\n", "Later in this tutorial, Redis will be used to store, index, and query vector\n", "embeddings and full text fields. **We need to have a Redis\n", "instance available.**\n", "\n", "#### Local Redis\n", - "Use the shell script below to download, extract, and install [Redis Stack](https://redis.io/docs/getting-started/install-stack/) directly from the Redis package archive." + "Use the shell script below to download, extract, and install [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/apt/) directly from the Redis package archive for a Linux environment." ] }, { - "cell_type": "code", - "execution_count": null, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": 20, "source": [ "# NBVAL_SKIP\n", "%%sh\n", + "sudo apt-get install lsb-release curl gpg\n", "curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\n", + "sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg\n", "echo \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\n", - "sudo apt-get update > /dev/null 2>&1\n", - "sudo apt-get install redis-stack-server > /dev/null 2>&1\n", - "redis-stack-server --daemonize yes" + "sudo apt-get update\n", + "sudo apt-get install redis\n", + "\n", + "redis-server --version\n", + "redis-server --daemonize yes --loadmodule /usr/lib/redis/modules/redisearch.so" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "#### Alternative Redis Access (Cloud, Docker, other)\n", "There are many ways to get the necessary redis-stack instance running\n", "1. On cloud, deploy a [FREE instance of Redis in the cloud](https://redis.com/try-free/). Or, if you have your\n", "own version of Redis Enterprise running, that works too!\n", "2. Per OS, [see the docs](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)\n", - "3. With docker: `docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest`" + "3. With docker: `docker run -d --name redis -p 6379:6379 redis:latest`" ] }, { @@ -152,13 +171,15 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:22:30.002812Z", + "start_time": "2025-12-09T15:22:29.999594Z" + } + }, "source": [ "import os\n", - "import sys\n", - "import subprocess\n", + "\n", "# Required imports from redis-vl\n", "import numpy as np\n", "import time\n", @@ -179,7 +200,9 @@ "\n", "# If SSL is enabled on the endpoint, use rediss:// as the URL prefix\n", "REDIS_URL = f\"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}\"" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", @@ -192,19 +215,12 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "โœ… Redis connection successful\n", - "โœ… SVS-VAMANA supported\n", - " Ready for migration!\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:22:30.963607Z", + "start_time": "2025-12-09T15:22:30.953423Z" } - ], + }, "source": [ "# Check Redis connection and SVS support\n", "REDIS_URL = \"redis://localhost:6379\"\n", @@ -225,7 +241,19 @@ "except Exception as e:\n", " print(f\"โŒ Redis connection failed: {e}\")\n", " print(\" Please ensure Redis is running and accessible\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "โœ… Redis connection successful\n", + "โœ… SVS-VAMANA supported\n", + " Ready for migration!\n" + ] + } + ], + "execution_count": 3 }, { "cell_type": "markdown", @@ -238,19 +266,12 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“ฅ Loading sample movie data...\n", - "Loaded 20 movie records\n", - "Sample movie: Explosive Pursuit - A daring cop chases a notorious criminal across the city in a high-stakes game of cat and mouse.\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:22:34.601711Z", + "start_time": "2025-12-09T15:22:34.597914Z" } - ], + }, "source": [ "# Download sample data from redis-ai-resources\n", "print(\"๐Ÿ“ฅ Loading sample movie data...\")\n", @@ -264,25 +285,28 @@ "\n", "print(f\"Loaded {len(movies_data)} movie records\")\n", "print(f\"Sample movie: {movies_data[0]['title']} - {movies_data[0]['description']}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“Š Migration Assessment\n", - "Vector dimensions: 768\n", - "Dataset size: 20 movie documents\n", - "Data includes: title, genre, rating, description\n", - "Vectorizer: RedisVL HFTextVectorizer\n" + "๐Ÿ“ฅ Loading sample movie data...\n", + "Loaded 20 movie records\n", + "Sample movie: Explosive Pursuit - A daring cop chases a notorious criminal across the city in a high-stakes game of cat and mouse.\n" ] } ], + "execution_count": 4 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:22:53.897543Z", + "start_time": "2025-12-09T15:22:53.894843Z" + } + }, "source": [ "# Configuration for demonstration \n", "dims = 768 # Using all-mpnet-base-v2 model (768 dimensions)\n", @@ -297,7 +321,21 @@ " f\"Vectorizer: RedisVL HFTextVectorizer\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“Š Migration Assessment\n", + "Vector dimensions: 768\n", + "Dataset size: 20 movie documents\n", + "Data includes: title, genre, rating, description\n", + "Vectorizer: RedisVL HFTextVectorizer\n" + ] + } + ], + "execution_count": 5 }, { "cell_type": "markdown", @@ -309,19 +347,12 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Creating sample FLAT index...\n", - "12:00:03 redisvl.index.index INFO Index already exists, overwriting.\n", - "โœ… Created FLAT index: migration_demo_flat\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:00.480896Z", + "start_time": "2025-12-09T15:23:00.471064Z" } - ], + }, "source": [ "flat_schema = {\n", " \"index\": {\n", @@ -352,7 +383,18 @@ "flat_index = SearchIndex.from_dict(flat_schema, redis_url=REDIS_URL)\n", "flat_index.create(overwrite=True)\n", "print(f\"โœ… Created FLAT index: {flat_index.name}\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating sample FLAT index...\n", + "โœ… Created FLAT index: migration_demo_flat\n" + ] + } + ], + "execution_count": 6 }, { "cell_type": "markdown", @@ -364,21 +406,12 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ”„ Generating embeddings for movie descriptions...\n", - "๐Ÿš€ Using RedisVL HFTextVectorizer...\n", - "12:00:07 sentence_transformers.SentenceTransformer INFO Use pytorch device_name: mps\n", - "12:00:07 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-mpnet-base-v2\n", - "โœ… Generated 20 real embeddings using RedisVL HFTextVectorizer\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:10.277500Z", + "start_time": "2025-12-09T15:23:01.825003Z" } - ], + }, "source": [ "# Generate embeddings using RedisVL vectorizers\n", "print(\"๐Ÿ”„ Generating embeddings for movie descriptions...\")\n", @@ -408,26 +441,44 @@ " 'description': movie['description'],\n", " 'embedding': array_to_buffer(embeddings[i].astype(np.float32), dtype='float32')\n", " })" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "๐Ÿ“ฅ Loading data into FLAT index...\n", - " Loaded 20/20 documents\n", - "Waiting for indexing to complete...\n", - "\n", - "โœ… FLAT index loaded with 40 documents\n", - "Index size: 3.0174942016601563 MB\n" + "๐Ÿ”„ Generating embeddings for movie descriptions...\n", + "๐Ÿš€ Using RedisVL HFTextVectorizer...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/vishal.bala/PycharmProjects/redis-ai-resources/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "16:23:06 sentence_transformers.SentenceTransformer INFO Use pytorch device_name: mps\n", + "16:23:06 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-mpnet-base-v2\n", + "โœ… Generated 20 real embeddings using RedisVL HFTextVectorizer\n" ] } ], + "execution_count": 7 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:14.840375Z", + "start_time": "2025-12-09T15:23:11.817076Z" + } + }, "source": [ "# Load data into FLAT index\n", "print(\"๐Ÿ“ฅ Loading data into FLAT index...\")\n", @@ -445,7 +496,22 @@ "flat_info = flat_index.info()\n", "print(f\"\\nโœ… FLAT index loaded with {flat_info['num_docs']} documents\")\n", "print(f\"Index size: {flat_info.get('vector_index_sz_mb', 'N/A')} MB\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“ฅ Loading data into FLAT index...\n", + " Loaded 20/20 documents\n", + "Waiting for indexing to complete...\n", + "\n", + "โœ… FLAT index loaded with 20 documents\n", + "Index size: 3.0168838500976563 MB\n" + ] + } + ], + "execution_count": 8 }, { "cell_type": "markdown", @@ -471,8 +537,38 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:17.484764Z", + "start_time": "2025-12-09T15:23:17.481838Z" + } + }, + "source": [ + "# Get compression recommendation\n", + "print(\"๐Ÿ” Analyzing compression options...\")\n", + "print()\n", + "\n", + "# Try different priorities to show options\n", + "priorities = [\"memory\", \"balanced\", \"performance\"]\n", + "configs = {}\n", + "\n", + "for priority in priorities:\n", + " config = CompressionAdvisor.recommend(dims=dims, priority=priority)\n", + " configs[priority] = config\n", + " print(f\"{priority.upper()} priority:\")\n", + " print(f\" Algorithm: {config.algorithm}\")\n", + " print(f\" Compression: {config.compression if hasattr(config, 'compression') else 'None'}\")\n", + " print(f\" Datatype: {config.datatype}\")\n", + " if hasattr(config, 'reduce') and config.reduce:\n", + " reduction = ((dims - config.reduce) / dims) * 100\n", + " print(f\" Dimensionality: {dims} โ†’ {config.reduce} ({reduction:.1f}% reduction)\")\n", + " print()\n", + "\n", + "# Select memory-optimized configuration for migration\n", + "selected_config = configs[\"memory\"]\n", + "print(f\"๐Ÿ“‹ Selected configuration: {selected_config.compression if hasattr(selected_config, 'compression') else 'None'} with {selected_config.datatype}\")\n", + "print(f\"Expected memory savings: Significant for {dims}-dimensional vectors\")" + ], "outputs": [ { "name": "stdout", @@ -500,32 +596,7 @@ ] } ], - "source": [ - "# Get compression recommendation\n", - "print(\"๐Ÿ” Analyzing compression options...\")\n", - "print()\n", - "\n", - "# Try different priorities to show options\n", - "priorities = [\"memory\", \"balanced\", \"performance\"]\n", - "configs = {}\n", - "\n", - "for priority in priorities:\n", - " config = CompressionAdvisor.recommend(dims=dims, priority=priority)\n", - " configs[priority] = config\n", - " print(f\"{priority.upper()} priority:\")\n", - " print(f\" Algorithm: {config.algorithm}\")\n", - " print(f\" Compression: {config.compression if hasattr(config, 'compression') else 'None'}\")\n", - " print(f\" Datatype: {config.datatype}\")\n", - " if hasattr(config, 'reduce') and config.reduce:\n", - " reduction = ((dims - config.reduce) / dims) * 100\n", - " print(f\" Dimensionality: {dims} โ†’ {config.reduce} ({reduction:.1f}% reduction)\")\n", - " print()\n", - "\n", - "# Select memory-optimized configuration for migration\n", - "selected_config = configs[\"memory\"]\n", - "print(f\"๐Ÿ“‹ Selected configuration: {selected_config.compression if hasattr(selected_config, 'compression') else 'None'} with {selected_config.datatype}\")\n", - "print(f\"Expected memory savings: Significant for {dims}-dimensional vectors\")" - ] + "execution_count": 9 }, { "cell_type": "markdown", @@ -538,21 +609,12 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Creating SVS-VAMANA index with compression...\n", - "12:01:03 redisvl.index.index INFO Index already exists, overwriting.\n", - "โœ… Created SVS-VAMANA index: migration_demo_svs\n", - "Compression: LVQ4\n", - "Datatype: float32\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:19.618376Z", + "start_time": "2025-12-09T15:23:19.608513Z" } - ], + }, "source": [ "# Fallback configuration if not defined (for CI/CD compatibility)\n", "if 'selected_config' not in locals():\n", @@ -591,7 +653,20 @@ "print(f\"โœ… Created SVS-VAMANA index: {svs_index.name}\")\n", "print(f\"Compression: {selected_config.compression if hasattr(selected_config, 'compression') else 'None'}\")\n", "print(f\"Datatype: {selected_config.datatype}\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Creating SVS-VAMANA index with compression...\n", + "โœ… Created SVS-VAMANA index: migration_demo_svs\n", + "Compression: LVQ4\n", + "Datatype: float32\n" + ] + } + ], + "execution_count": 10 }, { "cell_type": "markdown", @@ -604,19 +679,12 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ”„ Migrating data to SVS-VAMANA...\n", - "Target dimensions: 768 (from 768)\n", - "Target datatype: float32\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:21.292984Z", + "start_time": "2025-12-09T15:23:21.290954Z" } - ], + }, "source": [ "print(\"๐Ÿ”„ Migrating data to SVS-VAMANA...\")\n", "\n", @@ -632,23 +700,28 @@ "\n", "print(f\"Target dimensions: {target_dims} (from {dims})\")\n", "print(f\"Target datatype: {target_dtype}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Extracting data from original index...\n", - "Found 40 documents to migrate\n", - "Prepared 40 documents for migration\n" + "๐Ÿ”„ Migrating data to SVS-VAMANA...\n", + "Target dimensions: 768 (from 768)\n", + "Target datatype: float32\n" ] } ], + "execution_count": 11 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:22.893857Z", + "start_time": "2025-12-09T15:23:22.878963Z" + } + }, "source": [ "# Extract data from FLAT index\n", "print(\"Extracting data from original index...\")\n", @@ -687,25 +760,28 @@ " print(f\" Processed {i + 1}/{len(keys)} documents\")\n", "\n", "print(f\"Prepared {len(svs_data)} documents for migration\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Loading data into SVS-VAMANA index...\n", - " Migrated 40/40 documents\n", - "Waiting for indexing to complete...\n", - "\n", - "โœ… Migration complete! SVS index has 60 documents\n" + "Extracting data from original index...\n", + "Found 20 documents to migrate\n", + "Prepared 20 documents for migration\n" ] } ], + "execution_count": 12 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:28.514695Z", + "start_time": "2025-12-09T15:23:23.494711Z" + } + }, "source": [ "# Load data into SVS index\n", "print(\"Loading data into SVS-VAMANA index...\")\n", @@ -727,7 +803,21 @@ " print(\"โš ๏ธ No data to migrate. Make sure the FLAT index was populated first.\")\n", " print(\" Run the previous cells to load data into the FLAT index.\")\n", " svs_info = svs_index.info()" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading data into SVS-VAMANA index...\n", + " Migrated 20/20 documents\n", + "Waiting for indexing to complete...\n", + "\n", + "โœ… Migration complete! SVS index has 20 documents\n" + ] + } + ], + "execution_count": 13 }, { "cell_type": "markdown", @@ -740,23 +830,12 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“Š Memory Usage Comparison\n", - "========================================\n", - "Original FLAT index: 3.02 MB\n", - "SVS-VAMANA index: 3.02 MB\n", - "\n", - "๐Ÿ’ฐ Memory savings: -0.1%\n", - "Absolute reduction: -0.00 MB\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:28.554508Z", + "start_time": "2025-12-09T15:23:28.551629Z" } - ], + }, "source": [ "# Helper function to extract memory info\n", "def get_memory_mb(index_info):\n", @@ -794,7 +873,23 @@ " print(\"โณ SVS index still indexing - memory comparison pending\")\n", "else:\n", " print(\"โš ๏ธ Memory information not available\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“Š Memory Usage Comparison\n", + "========================================\n", + "Original FLAT index: 3.02 MB\n", + "SVS-VAMANA index: 3.02 MB\n", + "\n", + "๐Ÿ’ฐ Memory savings: -0.0%\n", + "Absolute reduction: -0.00 MB\n" + ] + } + ], + "execution_count": 14 }, { "cell_type": "markdown", @@ -807,27 +902,12 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿ“Š Search Quality Comparison\n", - "========================================\n", - "Recall@5: 0.667 (66.7%)\n", - "Recall@10: 0.800 (80.0%)\n", - "\n", - "โฑ๏ธ Performance Comparison:\n", - "FLAT query time: 0.018s (1.8ms per query)\n", - "SVS-VAMANA query time: 0.013s (1.3ms per query)\n", - "Speed difference: +28.3%\n", - "\n", - "๐ŸŽฏ Quality Assessment: ๐ŸŸ  Fair - Consider if quality requirements are flexible\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:28.585499Z", + "start_time": "2025-12-09T15:23:28.564735Z" } - ], + }, "source": [ "# Calculate recall and performance metrics\n", "def calculate_recall(reference_results, test_results, k=10):\n", @@ -926,7 +1006,28 @@ " quality_assessment = \"๐Ÿ”ด Poor - Migration not recommended\"\n", "\n", "print(f\"\\n๐ŸŽฏ Quality Assessment: {quality_assessment}\")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿ“Š Search Quality Comparison\n", + "========================================\n", + "FLAT (baseline): 100% recall (brute-force exact search)\n", + "SVS-VAMANA Recall@5: 100.0% (vs FLAT baseline)\n", + "SVS-VAMANA Recall@10: 100.0% (vs FLAT baseline)\n", + "\n", + "โฑ๏ธ Performance Comparison:\n", + "FLAT query time: 0.009s (0.9ms per query)\n", + "SVS-VAMANA query time: 0.007s (0.7ms per query)\n", + "Speed difference: +21.1%\n", + "\n", + "๐ŸŽฏ Quality Assessment: ๐ŸŸข Excellent - Minimal quality loss\n" + ] + } + ], + "execution_count": 15 }, { "cell_type": "markdown", @@ -939,25 +1040,12 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿค” Migration Decision Analysis\n", - "========================================\n", - "\n", - "๐Ÿ“Š Criteria Evaluation:\n", - "Memory savings: -0.1% โŒ (threshold: 5%)\n", - "Search quality: 0.800 โŒ (threshold: 0.85)\n", - "\n", - "๐ŸŽฏ Migration Recommendation: ๐Ÿ”ด NOT RECOMMENDED\n", - "๐Ÿ’ญ Reasoning: Insufficient memory savings and/or poor search quality. Consider alternative optimization strategies.\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:32.801584Z", + "start_time": "2025-12-09T15:23:32.798152Z" } - ], + }, "source": [ "# Migration decision logic\n", "memory_savings_threshold = 5 # Minimum % memory savings\n", @@ -996,7 +1084,25 @@ " f\"๐Ÿ’ญ Reasoning: {reasoning}\",\n", " sep=\"\\n\"\n", ")" - ] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿค” Migration Decision Analysis\n", + "========================================\n", + "\n", + "๐Ÿ“Š Criteria Evaluation:\n", + "Memory savings: -0.0% โŒ (threshold: 5%)\n", + "Search quality: 1.000 โœ… (threshold: 0.85)\n", + "\n", + "๐ŸŽฏ Migration Recommendation: ๐ŸŸ  LIMITED BENEFIT\n", + "๐Ÿ’ญ Reasoning: Search quality is maintained but memory savings are minimal. Migration may not be worth the effort.\n" + ] + } + ], + "execution_count": 16 }, { "cell_type": "markdown", @@ -1009,27 +1115,12 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "๐Ÿงน Cleaning up demonstration indices...\n", - "โœ… Deleted FLAT demonstration index\n", - "โœ… Deleted SVS-VAMANA demonstration index\n", - "\n", - "๐ŸŽ‰ Migration demonstration complete!\n", - "\n", - "Next steps:\n", - "1. Apply learnings to your production data\n", - "2. Test with your actual query patterns\n", - "3. Monitor performance in your environment\n", - "4. Consider gradual rollout strategy\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-09T15:23:38.291Z", + "start_time": "2025-12-09T15:23:38.285026Z" } - ], + }, "source": [ "print(\"๐Ÿงน Cleaning up demonstration indices...\")\n", "\n", @@ -1056,14 +1147,27 @@ " \"4. Consider gradual rollout strategy\",\n", " sep=\"\\n\"\n", ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "๐Ÿงน Cleaning up demonstration indices...\n", + "โœ… Deleted FLAT demonstration index\n", + "โœ… Deleted SVS-VAMANA demonstration index\n", + "\n", + "๐ŸŽ‰ Migration demonstration complete!\n", + "\n", + "Next steps:\n", + "1. Apply learnings to your production data\n", + "2. Test with your actual query patterns\n", + "3. Monitor performance in your environment\n", + "4. Consider gradual rollout strategy\n" + ] + } + ], + "execution_count": 17 } ], "metadata": { From a9ea365bfe9e734950bf89f91ad2ea1eccae1763 Mon Sep 17 00:00:00 2001 From: Vishal Bala Date: Tue, 9 Dec 2025 18:10:17 +0100 Subject: [PATCH 2/6] One more notebook to update --- .../vector-search/03_dtype_support.ipynb | 125 +++++------------- 1 file changed, 34 insertions(+), 91 deletions(-) diff --git a/python-recipes/vector-search/03_dtype_support.ipynb b/python-recipes/vector-search/03_dtype_support.ipynb index b19403e8..0f510280 100644 --- a/python-recipes/vector-search/03_dtype_support.ipynb +++ b/python-recipes/vector-search/03_dtype_support.ipynb @@ -87,8 +87,8 @@ "output_type": "stream", "text": [ "\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.0.1\u001b[0m\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m24.0\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m25.0.1\u001B[0m\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } @@ -98,76 +98,63 @@ ] }, { - "cell_type": "code", - "execution_count": 3, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": null, "source": [ "import redisvl\n", "assert redisvl.__version__ >= '0.3.4'" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## Run Redis Stack\n", + "### Install Redis\n", "\n", - "For this tutorial you will need a running instance of Redis if you don't already have one.\n", + "Later in this tutorial, Redis will be used to store, index, and query vector\n", + "embeddings and full text fields. **We need to have a Redis\n", + "instance available.**\n", "\n", - "#### For Colab\n", - "Use the shell script below to download, extract, and install [Redis Stack](https://redis.io/docs/getting-started/install-stack/) directly from the Redis package archive." + "#### Local Redis\n", + "Use the shell script below to download, extract, and install [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/apt/) directly from the Redis package archive for a Linux environment." ] }, { - "cell_type": "code", - "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\n# NBVAL_SKIP\\n%%sh\\ncurl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\\necho \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\\nsudo apt-get update > /dev/null 2>&1\\nsudo apt-get install redis-stack-server > /dev/null 2>&1\\nredis-stack-server --daemonize yes\\n'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "cell_type": "code", + "outputs": [], + "execution_count": 20, "source": [ "# NBVAL_SKIP\n", "%%sh\n", + "sudo apt-get install lsb-release curl gpg\n", "curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg\n", + "sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg\n", "echo \"deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main\" | sudo tee /etc/apt/sources.list.d/redis.list\n", - "sudo apt-get update > /dev/null 2>&1\n", - "sudo apt-get install redis-stack-server > /dev/null 2>&1\n", - "redis-stack-server --daemonize yes" + "sudo apt-get update\n", + "sudo apt-get install redis\n", + "\n", + "redis-server --version\n", + "redis-server --daemonize yes --loadmodule /usr/lib/redis/modules/redisearch.so" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "#### For Alternative Environments\n", + "#### Alternative Redis Access (Cloud, Docker, other)\n", "There are many ways to get the necessary redis-stack instance running\n", "1. On cloud, deploy a [FREE instance of Redis in the cloud](https://redis.com/try-free/). Or, if you have your\n", "own version of Redis Enterprise running, that works too!\n", "2. Per OS, [see the docs](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)\n", - "3. With docker: `docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest`" + "3. With docker: `docker run -d --name redis -p 6379:6379 redis:latest`" ] }, { - "attachments": { - "image-2.png": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAooAAAEDCAYAAACyIyUBAAABWmlDQ1BJQ0MgUHJvZmlsZQAAKJF1kD1LQnEUxn+WoYRQVENDg4M0hEaoVLSpgQUNphXW1PVqFvjy52pE0FhrCE1tYX2BlmrsAwQNQUNErS21RBJU3M7Vyl7owOH8eHg4PDzQ4tSUytmBfKFsxKNhd3J+we24w0UXTjx4Nb2kQrHYlFj4vD+ndonNuhc+69diIupWD6Xb58Mxc7v7fuCv/8e0pzMlXe6r7JCujDLYvMKxtbKyeEO4x5BQwhWLsw0+sDjV4JO6ZyYeET4T7tSXtbTwtbA39U3PfuN8blX/yGCld2UKswnrj2wfcyQJ4GeEYXxMM8H4P/5g3R+hiGIdgxWyLFPGTUgURY6M8CQFdAbxCvsZkg1aPf/ur6kVqzD6BK2VppbaheMt6L1qap496NiEo3OlGdpXq7aavbQU8DfYFYa2G9N87AfHDrxVTPOlappv+/JfOjotvAM3ImSkmH1osgAAAFZlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA5KGAAcAAAASAAAARKACAAQAAAABAAACiqADAAQAAAABAAABAwAAAABBU0NJSQAAAFNjcmVlbnNob3TjmMHYAAAB1mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4yNTk8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjUwPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CnRhDP0AAEAASURBVHgB7J0FeBTJFoUP7hLc3VncXYK7u+vi7s7izqKLu7u7Ptzd3d2Dw6tToYfOZDJxksAtvqGltP/uSZ++91ZPoAwZM3+HdXK9x7lEIOuCvrTtVv++1J00KwSEgBAQAkJACAgBIeCaQGDXu9QeW4LQ1j6blX1g56/syweGK00IASEgBISAEBACQuB3JGBbKP6ORyrHJASEgBAQAkJACAgBIeApAm4LRbNVz7zuqea9Udgv+vTGcKWqEBACQkAICAEhIAR+NwJuC8Xf7UjleISAEBACQkAICAEhIAQ8RUCEoqdwSWEhIASEgBAQAkJACPw5BEQo/jnnWo5UCAgBISAEhIAQEAKeIsBIQHkZjaeQSWEhIASEgBAQAkJACPwZBII6REvjqSN98/yCp8pLYSEgBISAEBACQkAICIGASUBczwHzvMmohYAQEAJCQAgIASHg6wREKPo6YulACAgBISAEhIAQEAIBk4AIxYB53mTUQkAICAEhIASEgBDwdQIiFH0dsXQgBISAEBACQkAICIGASUCEYsA8bzJqISAEhIAQEAJCQAj4OgERir6OWDoQAkJACAgBISAEhEDAJCBCMWCeNxm1EBACQkAICAEhIAR8nYAIRV9HLB0IASEgBISAEBACQiBgEhChGDDPm4xaCAgBISAEhIAQEAK+TkCEoq8jlg6EgBAQAkJACAgBIRAwCYhQDJjnTUYtBISAEBACQkAICAFfJyBC0dcRSwdCQAgIASEgBISAEAiYBEQoBszzJqMWAkJACAgBISAEhICvEwjq6z1IB0JACAgBOwS+f/9uJ1eyhIAQEAJCwKsEAgUK5NWqlnoiFC0oZEUICAGfJhAydDhEiZEAYcJFQuDAQXy6eWlPCAgBISAEvEDg27evePfmOZ4+vIkPTm/stiBC0S4eyRQCQsCrBCgS4yfNKALRqwClnhAQAkLAlwjwwT1chKj6If7WleN2xaLEKPrSSZBmhcCfToCWRLEi/ulXgRy/EBAC/pkA/0bzb7W9JELRHh3JEwJCwMsE6G6WJASEgBAQAv6bgHt/q0Uo+u/zJ6MTAgGWgFgTA+ypk4ELASHwBxFw72+1CMU/6GKQQxUCv4qAzGT+VaSlHyEgBISA9wnY+5stQtH7fKUFISAEhIAQEAJCQAj8lgREKP6Wp1UOSgj4HQF7T6Z+NyrpWQgIASEgBOwRcOtvtwhFe9QkTwgIASEgBISAEBACfzABEYp/8MmXQxcCPk3ArSdSn+5H2hMCQkAICAGfJ2Drb7i8cNvnOUuLQsBfEMiaLSdatOmox5IlWy7LmCb+O0Kvjx873LJPVoSAEBACQkAI2CIgQtEWFdknBAIwAUMgGuLwyKF9cP4cQJZsOdC8tbN45CH6lljkG/8lCQEhIASEQMAnIEIx4J9DOQIhYCFAkThrwUq9TcuhW0KwZZtOWjBSNNarUR6HD+23tOHdlTDhHBApWlzvNiP1hYAQEAJCwB8QCBIqTPS+nhnHp/dPPVPcdtlAgRAoUGD1CaTyv9su48N7cxbpjPhJ8uL2tf/5cMt/XnNJkibHoOH/4uPHj7h+7YqPAQgc2LgmbDdp5NuKoWANI99cm9cY91vXcWs/yxrJaI9lrT8sY7RhnWdsW/fJOkabtvJChAiBqNFi4N27tyzqpbR1z1FtPezRuQ1WLl/sZhsUhkfUJ3acuMo93Umv37t3x83yHsngMVEkRomRUC89UkfKCAEhIASEgN8TePLghotB8D5mpJ93RWPPL1jWarUZ3ca+Q9fRr9Fu8F3Uar0FmXI30eLRt7oPFyEWwkWM7VvN/1HtRojogLz5CyF23Hg+etzrt+7D2SsPsHbzHlftlixdXucxv2ChYq7y06bPiNOX7ukydRs0teT/O2mm3pci1V+WfVzp1usfvb9AoaJ6f5So0TBmwnS9b9zkWXrftj3H9Db7tP506dEfNWo3cLXfKPfP4FG6DfN/9Rs3t5RPlTqtJStu3PiYMnMhjp29iR3/O45DJ6+gdfuuCBIkiKWMR1ZoJWSaMHaEKwvh+WuPwA8tjkaiWGRZJiOW0cjzylJEoleoSR0hIASEgP8m4Geu593r+2Hf5iEIFSYyosdOg7TZauOvLDWwcGIpfProvkWlSKVRCBwkGDYtbuW/CXtjdBQKX79+9UYLAbNqosTJkDFzNhw/eshyABWr1LSsW6+QU59/huHB/XvaQmad79528pSpMUe5a1++fOGi6NBBfRA6VGiECx8eXXv+gzu3b2Ly+NG6zNWrl/Du7VvQcmekECFDonvvAXj//j1GDR9o7NbLGDFjo2XrTrh3946LMYYLFx6zF65C+AgRMGRAb9y+dQO58+bH3y3aIUqUaOjdvb2LdtzaMFzJdDfbcyNb53GbdeiCpoi0znerP+v9ocNGFEuiNRTZFgJCQAj8BgT8TCga7N6/e4abl3fpT/Xm61C4wgisX/i3zqa7OEve5kpMRsLdGwexdl5jvHp+C47lBiNdtjr0/SFxyiJYv6Cprh85ejIUrzoesRNkw4f3L7F/63Ac2TXe6Eovszu2Q/aC7RBIuRgvn16HrSs6WoSpvfrBQ4RFyeqTkDRNKd32/zYNwvH/TdVtUrAWKN0fqTJVQbBgoXHlLNvtjA9OzsIjd7HuyJq/pbIQBcfZo4uwaWkbfP/mvgBs1a4Lvnz5gmmT/8WHDx9cHIdHNlKmSoPO3fsidZp02p25bvVyjB05RLX5GaFDh9Hip2DhYggVMhROnTyG/r274OaNa7rpoEGD4e+W7VCqTAVEjRod58+dxqhhA3Di+BFL18FUmV79hqBw0ZJ6fMOUsNq2ZYMlv1yFqqB1L278BLh+9YoSTwNwcP9eS76tFQqliBEjoXK1WhahSPdothy5cfbMKfyljsU60bIXPUYsdWyD0G/gSOtsd7dDKoH3T99uuHblMpav3WYpv3nDGr0eNVp0zerZs6fKnbvIks8Vs+u9TftuILd/R/XBs6dPXJTr0WcgTp44qvlWr1XfkpcuQ2bEiBkLyxbPx7zZztfT3t3bUcCxGCpVrYmRw/rj1cuXlvLurbgVk5gqcXQ3q7IOhSKtiodrVHCznFsZAUkktm3ZEFUrlkIuxwr49s37YS+pUiRFlMgOePrsBc5fvOICUZLECRArRjS8fPUGp89ecJHHjUwZ0iBM6FC4ev0W7j94pPPz5sqKF69e48zZi5bybJ/9XL1+U5V7rPfHiB4VyZIkxKUr1/Hm7TtkVm3ZSuz75q07SJ82la1s3FB5d+4+cJFna1wsECtmdKT70c7Zcxdd1XPRiGwIASHw2xDwc6FoJnnl7HpkzNVY70qerhxyFemC5dOr4fWLuyhUbgiKVByBpVMr49jeyYgQKZ6K9wqKfVuG4fmTq7pOxQaL8ODOcWxY2BzR46RDhfrzcfvKHjy6d1rnp8xQAZfPrMfs0flB4Vei2kSUrTsLS6dUcrd+nuI9tPVz2pAsynKSEpUaLcYt1fazR5dQvMo4xIqfGRsXtoCTEr4sW6b2dCz5rwKSpCqm3eq0lDKGq1LDxciQoz6O75um+7T336xpk9C+cy+s2bQXwwf3xdbN6+0Vd5GXKElSLFy+Aa9fvcTShXORLEUqNGzSUgnZ4Mpy1Qs9+g4Chdz8OdPw+fMX1KzTEIOHj0P1SiV0O/8MGYWy5atg57bN2LNrG4qXLIf/lHu0bPF8ln7qNWqG+yqujZa//I5FMXjEOBzOs1/3WbVGXW3l27d3F1YsW4iSpStg6qxFqFi6EC5fcn3TNBpl3OOGdStRrmI1DOrfE29ev0L5StW1Je7YkYOuhGK06DG0m3bowN54/fq10YynlqdOHAM/1u5pzzSSMFESNGjSAhfOn8Gi+bNcVM1fsDDyFSiEciULoEatBi7y3r930tsUi0YKEiQoQoUO/WN/bA8JRQo9zmy2TrQSZs2ey7LbLSFpq66lkp0Vzm52iBonwMQkhggeHGHCOLO1c1gezmrSsAYK5suJFy9ewbFkDf1gZ1QePqg7EieMj6PHT6PB385hAUYehduMycN1nOvQkZMwf/EqHb86fvQ/OHDoOJq26mYURYb0f2Hk4J4YMHQclixfh9IlHNG9U0t9HD37jcDZc5fAerYS+x43aZbNfH7vK9b4GabB+rbGxf01q5VHh9aN1N8w4Nv3bwgWNKgK1ZiBWXOXMluSEBACvzEBP4lRdIvn65f3ECFyfJ396cMbrJnbENcvbMXThxdwbN9UxEqQVee9fHYL7948Ua6/p3hw+xg+vn+lrXXnTyzDtpVdtHC8cGK5FoixEmSxdPdBlaO18sXT6zpv1ezaSJamtJqhmdTd+pGiJsG1C1t025fPrMW8cUW1JZKxj+lz1MPmpW1x9fwm3L91RFkTO+l2I6pjcYiWBA/vnFDjPK6XiyaXxd2bP12qlsHZWKErlK7Hzu2aoVnL9pg2ewkSJU5qo6TrXa3bdVXWraCoX6sihg/ph8b1quLs6ZMoVqKMvjm9UaKKLkeKMYpQTmz4K216BFc30qTJUmiRuGHdKrRoWkeX6d2jA0KECIn8BYtYOrtz6yYqly2Cti0bYemiuerGFRbJkqfUNzxa1+7cvoWmDapj7qypaNO8gY5BNccPWhqyWqGwpJWvdNmKuq0KSiiuWbVUWYC+WZWEsvT1x41rV7Fi6UJXeb9yBy2r5E2rrDlcIGSoUOjRZ7BiME1bVa3HREvt0yePkT1nbjCGkVbgnkrER4oUWReNED6CdRU3t48cOuAqj1ZCikjj46qAaYfxOh3TLndXGZfIz5+eHBwiIH+ebBYMf6VOrkWiZYdphROaenRphf0Hj5n2emw1X+5s6NujPS5ccn44Zq2bt+8gZ8EK+rNspbNFv2aDNnq7RbteOHXmgiWf5Vp16KM7mz1vqbI23rV07Na44sWNhU5tmyir6EUlhqujQLFq2LnnANop6yytmpKEgBD4vQn4K4timHBR4aTEH9ONS9sRMXICZFEu2/AR4ygLYlyEDOX2TfPr10/a1Zw4VVHEjJsBIUM76E+IkD/r3Lm2z4XL98XTG3ijxGm0WH/h+eMrduufP75MWwnjJc6l3Nw7cfHkKrx5dV+7vr+rmdsZ8zRBxtzO1lCO/8vnD4gcLTmunduI/KX6oW67XVpoUmQ+vneGRTycTp86rqxyi9CpWx8ULV4ak8a7nihh3dhfadLjxvWruHb1siWrSvmilnWKw1x5CqBth+5wUKKE7l3G+lHssS6T2YJJy2K6FHH0/kxZsuvlrh1b9JL/nT/nfEwODpEQO3ZcRHRwgJPTO3AyiZE+KWthkqQp9OamHQeV8Ayh10cM6Y/1a1caxbSg5bgrV62lY/ZobVu9Ygmq1axnKcOV3HkLKB5lUK1icZsi0kVhqw3zjC6rLE9vcqJN9px5tPuYlklzYqwhj5Oi3FZ67+SETupBYOTY/9Cpq/MN/Mrli9i9c6uyQhbG8+fPbFWzuY/vSLROdX+4kmcvWKHeofjTsmhdjiLTXr51+V+xnfavlGivrFgpkidW1uK3WL5qI6bMWKAt8/Hjxkb3zi2VKzSltohv3rpbzcSfoK8DWg3/blwLxYvkh0PECDij3KRDR03Glas3LMMukDenLhNbuVM3qbr/DPnXMjO+YrniqFW9vHIbR8dlVWfk2Ck4efq8pa71yqPHT3Xd8mWKYdtOZ6tuudJFtSs6aWLXQqp65TIIHy4shqsx5cqR2bo5u9uPnz5D1TotkDJFEmTOmFb95fmuXehvlfuZiVZCJqd3TjD2cdtY58NM25YNtKubE6jMya1xpU6VXD+wrd2wTcXxOlvtl65YD8f8ueBYILdmZG5H1oWAEPi9CPgri2L0OOnx7LGzsEmdqSoadNqP0GGiaOvfw7un7JIPFjyMFmOMaXz7+iHuXNuvYwnNlSjeXCW+PkXFGLpX/9yxxZg+PAce3z+r3ONN0KLvJR0LGSxEGHz98hE3Lm7T4pYCl5+Ni1voY3n+5Bom9U8NWjgTJMuPxl2OIFvBNq6G4dYOWvkWr9yEEqXLoUq5Ih4SiWwrbNhw2nJoq12KpAlT5ugP4xc/fHiPT58+6aLMC6PqMgVW6/bSh48/eX4zTboJHSaMrvbq1Qsdk8e4R34WzJthEZ+HD+7HwQP/05/Hj53js8x90arISSadu/fTru07t2+as7X46tl3sHL5PUfFyjXQd8BwVK2u4lZVKqLEdOO/W+v1Vz8mqIRXk0bMKYKKg2R6ruIOvZPImWN8+eKFiuF06f6j+7+BshIyXpEin2M03MBNW7TVsZ3s+5DiUDh/FtSuVla75ssrF3UoFUPK9OjhA7107z+vuo6Ndm2JTCPP3vLdmxfKuv/CXhEv5cWPFwfTJw/Tdfv8Mwrbd+3T1u0qKr6QaciArogdKwa69BiMpcody/3lSjlbu2mtq60EMsXMwGHjET1aFEweO1A/COnK6r96tStr4UlrW6XyJbT7mHkVlNjr070tdu7aj5bte+HZ8xeYOGaAitN1tvAa9c1LWpBXrtmkRV+0qFFAoVq8cD6sUMLWOjHesOXfdTHq36n48NH5O2ddxt72hYtXcfXaTXtF7ObVrVlRWzqHKZH64cNHS1l743r29LkuxzhJIyVV8ZdMsWNF10v5TwgIgd+XgL+xKIZ3iIv02etixYyamjbjE7cs66Amfzg/9VJkuUoMmPmREqUsrG6uDpg5Mrd6NaPz/iz5mhvZeknLoTlFippYWyufP7oM9+onSV1cu445W5ufyo2XInXmqnpCC0Xm/VtH8eTBT6tD1FiptXs8ZrxMyhX5CYd3qfg99aGFNL2KUTy0Y6x5KDbXGefH16SMGTFQW6tsvXvPZkW189q1y8iQMYuaKBEbDx/c08Vo3SqhrF+0YPH1NpxAYcyqnTx9vnYbs4/rqi5Tztz5sHH9ar3O2bkUrAvmzMCFC2f1Prf+oyg03K+0FhopTz5HbWXkttGvkWe9XLtqGdp36qEskMltls2cNYeekEOBarwuh7OOmeg6f/vmNaaqSUA3b1zX+zhpxJjRS8tperVNV/atH/m6kBf+a92+i3r3YXT0Ua5561nTjOukgIwcJapljGF/CNYsWXPi4vmzakz7MHTkBCWGD2PKJOdrInr0mMiUOSvOnT2FN+o4PJq8YxFkXbesnvb6f/PqiTrXn3URn3RB16hSFkGUi7ZtZyXClRVr87Y9akKWk8ViNlbFxz14+AR37z3AeeWGbVC3GpIlS4SIEcKjXOkimLdwJabPXqzHdfvOPRRT1sXIkRwshzJAWRA5EWTfgSNYv2IWkiVNqMVo7ZoVcOPmHaxcu1mXXbR0jRaRBfJkV7GGZxAvXmy9/4GafML6RlqxehOaNqyJsqUK444aU7BgwbBh80506eDyb1CHNk1w8fI1fTy0mP7KxMkoHOPefYexY7fLF6zbG9exk2dx7sJl0NIaTQlmJzWrP12aVHro/C5JEgJC4Pcm4OdCMWyEmIiTMAeKqtfdcDILXbNMdKmEjRBDrwcJGgKZ8jTV68Z/L5/dQNK/Sum4t+8quJriMGToiCpOLKRy+75XbWZXFr+sqr11RhW9nSZrLZw5PE+1HROcjcyYwod3TyrXdny79ROlKKTjDjljmX0FDRZKxx0yfvLGpR26rR2re+hZ2SnSV4Bj2UGYPDCdfndj3hK9MHdsIR1LGSJEOF3PMig7K3fv3ELpIrk95X40mps/e5oWisNHT8SMqRMQSr3mpdHfrXBg3x51s3W2ZESPEUPHPKZLn0m5cQvqqrQo0trHCSfFS5UDrX2czNKgcQvEjZdAz3pm3J29xAkpjFmkq7hj197YtH4NMmfNri1vXTu2BCeluJcYt7d3907t0t28wfmaMNfhJJm82dOYd6F0uUpadE1Qs3hnTZ+s8zhLuUnzNkpwd9ExmLTeFVATb+LEjYeVymppLe5cNOjOBuMJq6vJKTze2HHigXGZRrp86bx6R+Fw/TH2ccn3K/JVP43qVtEzybnv3bt3aNm2k35Fzm0V91mrbiNl/QqK6VMmMNtDie9DnLUgF/iaHLcmrLAh4z2KhmjmPuP9i1z3SnJ6+1LFETu7dX1KLCaIHwdPlCXLcHVyXOMnz7YMjxY+TuiIp1zQdKsGDhxIT7BgPabLV3+KOLqNrV3HV645j5d9MDE8gNc+Xdrf1Pd7waxxej//e/X6jbYolipeEI3qV9f7GQvYf/DPhz26nynA6HKmeN2yfQ/eKmFrTnQVlyxWEL3/Ganc6UkQP76z6KTFk9ZRznzmA1a4sM7WZKNuyBDB9epHL1ggjTa47NaphXrbQyAMGTnRvFu7sO2N6979h2jYrDPqKCttyuRJ9Xnp3X8kpk0aBh63JCEgBH5vAn4mFAuU/gcFSvVXs1of4Mn9c9i1rjdOHZxjob1Tia4ydWYic55mSpd9065bS6ZaOX9sKVJmqIQOQx/qySNnjizAnev71fYDPUuaLuz7aqKLOZ06NFe5f/OpmMG+KgA/uhaJK2Y4/+G/cm6D3fq0ABatPBqt/7mux3P76l41pmW6+VWz6qgZ1OPRrNdZfPzwSsU7XsW6BU20S/qKEqq0RjbtcVK5coNoq+OW5e3Nw3JznWLIq4kTUSKqeEFOYpgwZa62nu3Ytkm51Tpod+38OdOVyKmPdVsc9Wtn9uzariaqFNbd8fU5LdUklt79h6JJszZ6Is0TJRi7dmihrVxGjKK9sXECzdevX9RLqRtqkXn3zm09qYWWQo8mCjnGOXrGqmbdNt2+fzeoge7q9TSFipTQ7l62yeMfM2KQdXFPbffsN1i7M2lVISdzoiXWsMaa99taH61eG/RBzX4uU64y+OJvvg+SgnrTD2uurTrW+yj86H7m+T58cJ/Fempdjj/vx3LGa3AoHFmH1kR7AtO6HettnxaLj588RfasGbRAe/LEOU6TbuEgQYPg0JETGNinE1as3ojqdVvis3qF1OE9a/SQWI+J1rpVa7fodb5KhrN2aR20l2hNf6z6ev78JWrUdw5dYPlIDhHxXr2e6v37Dxj3Q6zasu5TPI4b1R9x48RE3Sauv+NtWjTQ3ffv1cHFMOgGj6smjLTr3B93lShLniyxFq58AGFKpGZOM925e18vvfIf4wk5EWbS1HmuXmvj3rgGDBmHYsqVvkO54ydPm6+7r1C2uF5eNE2q8cq4pI4QEAL+n0Agh2hpvntmmG+eX/BMcW+VDRQ4iHInR1ITXJ642U6IkOGVReeNxd3M7W/fvuDzJ5dP8+YGGJMYVFkpbb3Y2736QYOFVO1/xbcf7jZzu3xPYpCgwW22q8wV+h2Lnz85B52b6/n2eqTIUbQr1ohDNPrjuxSDKhcZX6HjVuIsaLpLvRrLx5mUESM6eMkq6taYvLqfM6kZf2n9jkOvtufT9WjRYsyjV4UxRZ8hBK1/ncWwJBpjprDkPs6KptvZ3nsWjTruLSmeaFH0iZ/wy5YlA6ZOGIKt2/eq2f6LlMszCoYP7I6pagLGkWOnMGfaaCV65mLRsrWgm5ouVcYkclLKrCkjkThRfB0HeOzEGbRt0RBZM6dH0TK1VHxgPSUay6kwl2Lqe6y8ECFDaJE5Y84SjBk/Hc2b1MHfjWpiyIiJemZvQSWwOrVtippKONL9ap3GDO+DFErYFStbR0/42Lxmrnq4eY+yVRrposf2rVezjs/r1+PQ9W121aZNkwKjhvTCRBUvvHDJGm25ZN8cw/6DR7Fm/TY4KJHKmMaHjx6jcs3mltfvlC5ZSIvlHv2GY60qZ6RuHVugepUyKF+1Ma7duK13h1bvaly9ZJpyvUfEiDFTXMRGHj56Ugtge+N6o14sv2z+ZD12Mqf1taOaBf3mzVuUrtTQEmZijEGWQkAIBDwC549vdzFo3o+M9Mstij3HO8czGQP4U5d8jc/B7aN+yeG7JfJoWXMvUVy6Vd+9usxnHKBnZu56pE2vluFLy73y4nKv9ufZehRaXhWJ7Ivir16N8los0g1tthKaXc0sa/ySC9dZx6cSJ7Y4W9sSeeu1ObQa0kVLa9dixwlaINFCOFO9t4/X1LYd/0OzxrXRRFmL127Yrh4WncMpeBydegxC766t9aQUPqjcUjGKbTr1xTsl4NxLU2cuUGEaIdXM4IbKqttcvz5m9LipNkWidVscF2MVndRMdluJE2PMie9eZHrz5p0WiVxnXGVoFdpRtVJp5MyeWYuwI8dOY6B6hyJfvu+VREZ0bzPxmMypc8/B2LRll3mXfickd5jH1XfgGDSuXw20hgZVVt0Tp86jV//hIhJdkJMNIfB7EvDXFsXfE7kclRDwfQJmIUhXs/Prb3Lojo1JL9xvbXn0zsjM7li+iDtu4rTeac5Sl+8opGixFkp8xczHT591jKilsGklePBg6leHQlpEmCnL3VXGPIYLG9ZLdd1t3IMF6PJ+rax21sftweq+UoxMmT4p7pKEgBD4fQjYsyiKUPx9zrMciRBwQcCYpMIYRCNRHDL5pEA02jYLRe5LldHRyJKlEBACQkAI+GMCIhT98cmRoQmB34WACMXf5UzKcQgBIfCnEbAnFAP/aTDkeIWAEBACQkAICAEhIAQ8RkCEosc4SSkhIASEgBAQAkJACPxxBEQo/nGnXA5YCAgBISAEhIAQEAIeIyBC0WOcpJQQEAJCQAgIASEgBP44AiIU/7hTLgcsBISAEBACQkAICAGPERCh6DFOUkoICAEhIASEgBAQAn8cARGKf9wplwMWAkJACAgBISAEhIDHCIhQ9BgnKSUEhIAQEAJCQAgIgT+OgAjFP+6UywELASEgBISAEBACQsBjBEQoeoyTlBICQkAICAEhIASEwB9HQITiH3fK5YCFgBAQAkJACAgBIeAxAiIUPcZJSgkBIRCACNSvXQWJE8XXI06VIqmfjDxsmNBu9hsuXFgEChTIzXz3MkKECIGgQYPaLBYqVEgECRLEZl6Y0KG81a/NRv35Tp4H77C2d3i+2bb5GrY3Bt/Oy5cnOwoVzK27iRLZAVGjRvaRLvPlzoZihfP5SFvmRvwLN/OYvLpu73seLFhQ8Lv+K5LtvzS/omfpQwgIASHgSwSyZ82AC5eu4OHDx/h3ZF9UqNYUr9+89VBv6dKkxMC+nXH0xGn0HTAarZrVQ6ECzjdKNqCFWODAKFSqJtL+lcJFWeZXKFMMLf6uq/p7g2BBg6Fbn6E4c/Yis1AgXw60b9UIz56/RPx4sTF7/nLMmrtU53nkP96oOba4cWLqcWzftR+Dho3Dt2/fwbyhA7ojWrTICB82LNZt3I7hY/7Tzab9KyX6926P79+/wyFiBPw7YSZWrNnkkS79rAzF9Pdv3/D2nZPNMZQvUxSd2zfDwKHj9LFaFzLO48ePHxFZsRk++j+s37TDupiXtn2zbWNAxjV87fotY5efLJMlSYiQIUNg247/oVL5EggWLBjGTZrl7bHwQS5ihPDYtHW3t9syN+AfuIUIHhytm9dHrerlUaR0LXz9+hXTJw03DxOxYkXH0JGTsHb9NhdlHz1+qr/Lbn3P+bDXr1d7JIwfF4GDBMY79f3o0nMI7t1/6KJ9n9wQoeiTNKUtISAE/BWBd07vUahkTQ+PKVuWDKhRpSx27T2AsGHD6Hq8KZpvjM0a19YiLWvm9K7KpkieBA3rVUP5qo21MM2TKysG9O6IslUaaUtMn+5tUatBW9y990C3v2j2eJw/fxmHj53y0Bh7dm2NPfsOY/6ildqiOGPycBRxzKtvtl06NMfR46cwaeo8BA8eDKsWT8W+g0dx+OgpjB7aC6079sW5C5cROZID1iydhv8dOIrHT556qF+/KFS/dmV9E5w+e7Gr7ps0qKH5nTpz3lUedwRWQn7U0N7qBjpYMTmNBPHjYOm8Sdi996CbwtNmQzZ2+mbbNrrzV7smT5vvr8bjXwczZEBX7P3fYX39coxPn73QfwOM8YZWYm/zmrnYsm0PrMuyjL3veUv14PpcPWh27DZQN1e1UmkM6NMR9Zt2NJr38aW4nn0cqTQoBISAdwn8lTo5hg/qgdbqj+LsKSN1c4kSxMMstb5v+3LM/G8EuG2k/HlzYNWSqdi2fr5+Oje7Gtcum66sIM7PxO1aNsSerUv1H2m6vqzT6bMX0KZTXzx4+MQ6y7JduoQj1m3YBltlHzx4hHpNO1isl/yD/uXLF103RbLEuHfvoRaJ3PH27Tts2LwTBQvksrRtrNSsVh4bVs7SY+VNgBYKpnETZ2LhklV6ne3SSmq0T9E0f5Fz3qdPn3Hn7gOEVq4pergbNOusRSIrvnr9Bl+Vpe7zl8+6HeM/WkpXLppibOrlnGmjES1qFL3uHjsWIve/G9XElrXzsH39AlDQGSlliiRYMncCDu5ehXkzxiBmjGg6ixarpfMn4cDOlRg1pJc+1jIlC6N65TJoUKcKli+YbDRhWc5duAKj/p2KDx8+WvaZV+gSnjl3iRaJ3E8WX799RdAf14G5bMF8OfW1w+tiUL/OlgcElrF1Hjzatk9ew5tWz0GJogWUwJ+OXZsXo2ypIpZDoPuWvDn+pg1tPxSxfmHHPNi6bj7CK0stH4KG/NMVu7cs0W3SvWwkimp+z9jeKPWAEcYUQlGlYinQtcvkkX5Zjg9US+ZN1N/baZOGaWs491snWt/Wr5ilr5te6oHIcKvy4a1vz3aW4tGjRbH8TeBOe999SyW1EitmdEwaOxB7ty3DysVTkDN7Jks2++AYd29egsn/DkTsWDEseWRH6zWX/H4kThgPbdXfEf4dWrt8BmyFtnTvM0xb7GnBt5Uc1XeeDzD8/toqa+97ni5NKuz+3yFLs6vXbQGvtQjhw1n2+fSKCEWfJirtCQEh4G0CwZV7K6+yxn1Ugqddl3+0hWzi2AHaxehYsoZ214wY3ENbjnhj692tDcZOmIHyysVMN0+mDGksY4ihBAkFTPq0qZA5Y1oULVMbnXsM0nXMgpIV3r//YKlnayVD+tRwUmUuX71hsyxF2JMnz7TrqG7NiujeqQUmTpmrm3ry9DmSJ08MWhOMFDp0SPDGZ06lijuiVPGCqNOoHUpVqK9v7I0bVNdFrt24rd3MuXNmAa2TgdVx0TLING/hSotApds2dcpk2pr4+fMX3Lp9V5epUqEkxg7vg+WrNuLFi1d6n/Ef24oRPaqxqZfRVDxaEOXe8gg7VqBrkmNr2KwTaqvxU4wXLZRXt9WvRzssWroWeQtXxukzFy0iskObJpgyYwHyF62qXWllShXGxi07sXz1RsxTwpccrJN754k3YPIwEs/77dv38PLla2OXXvKmT479B41FifL1tPBs26KBznPrPHi0bR+9hqNHQ0oVa1u5ZjMtLHhd8TpinGq3ji1Qr0l7lKncUPPn98E6xVD1C6iHKZ4Xjr+3EmJkWLpiA3TvOwz9lBCLFTOabo9iaocKaShRri42K7cwrxkjUSSHDx/Ww/0yRGJw/y6K7xjkL1YVh4+c1BZ2oz1jWbpkIS08azdsq88D9/MYmej2jqTCJYzE+NtoP74z7n33zXV4XJu37Ua+IlW0y3ekeiihYI4XNxYG9e2kw0wKFK+K9erhjWLRiAEmu/jx4qBs5UZYpUTZ7KmjdbMFi1fHqjWb0bFtE73N8hSUXLp3fZYpUUg9bG7X9WyVtfc9f/r0GTKm/8s4NB0KEEz1af13xFLAB1ZEKPoARGlCCAgBnyfw/MVL/Dd9PrjMrp743ygL3Eb1RzyIcitu2b4HFEP8I1+udFHsVe7YnbsP4I26CVJ0GFY286j4BzxI0CBaeJ06cwFFy9bRMXu8EUWMGF5/zOVtrZcuXghrlTXRvRQmTBj1lJ9Cx8YFU25gpouXruLsuUsYqiw5tLJQVOXNlc3VRItqlUtr0Ut3FW/qQ0dNxhUlTM2JAid1yqRaFBuWF3N+1w7NMH/xKotwNPI4JsaG0dJBF6pHk1vseKMlO8NNX6FsMS3QaEl99eo11qo4Scf8zhbTHv1GqBvtZtDauWP3fiRMEFd3z7bDqZjKL0rgt+/SX4tYiluW+/TpExg+wGScI54vW8mt88gJAd06NceIsVNdVSurrh2Kh0uXr+l4yEVL16Dgj/F65DzYa5ud+eQ1PG3mQvXg9An7Dx7Dw0dPEDd2TG0tDhQ4ECI5RNQimA9Bt5QgtpUYPnH7zn0tMGnFnjZrkb5+bqiHDwq4XDmyIFuW9PramLNguXbRb1au0TPqmrVO6pkCtvrluTTOE9crlC2OVWs346wKr+A5nTFnCbbu/J/ra75iaR03S148xhFjp+iQCrfOtTEej373eVwv1fW4au0W9aD1DQcPn8CAIf+C8X4c4/LVm3D+4hX9EMaYQcYQs46RGP7AcVEYUihPVX9juL1SbSdLkkgXix83lhLc7XXssVHP1pKCLlnSRCqE5KdV0FY57rP1PV+wZDUqliuu4x8zpEutRf7bt06umLrVplf2S4yiV6hJHSEgBHydAIO6jRRH3RRjKcvgQhXTZyQ+iTs4REC8OLFcuGJ4Qzpz3vXN7diJM/qGSDcnb0hzF6zQoqSRiimsW6uSbja3YyVw8oOtxLg/zv6sWONvW9ku9tGC16n7QP2Uv275TC1i2W7ztj3RqG5V1KpWTrmuL4J/9JP8mJ1tNBAvbmzcuHnH2NRB6taB6pwEw0/fHm2Vi7asslrOsZRnjCWtIL36O7vsLRlqpfc/I/UNZY1yxx88dNzDsZFusft3RF+kURN6zikhUK9JB/A8tWpWH82b1LF0e1GJMKaYylrZs0srNcFHzdZUllSnd84CcMTY/9Czcyt0UpYZiqBhoyfDfO5Zl+zpNmWaq477XyV6rJOt80iLMa1FW7fvVdbVk9ZV1HhjgK687FkzWvIYEsBQBffOg3tts0HzcXj3Gqa12kgUPXxA4LU+ZMREDBvYHRSttACOGjfN5oPSo8fO4RR0qwZS/2hhMyeKuXhK7Bw/eda8GydOndVWK/NOt/rNkimtmjzWTxdt07Ev4qtrmQ8FRuIDnNnSa+yPq/q9aRK4/G4/VpYzMrOXPPrd58SxG7d+fqfYpjGxiW1s37XPRTf8/pHFvgPOu/kAyvTm7VstNI2HF26HDOX84EIroGOJ6qDnwF4qWawgtqqJQWToXrL1PafI7dZ7KMqrhxyK1JlqMlw6NVnNvX7d68tevghFe3QkTwgIAT8jwCd/Iz17/gJXr91EXSVGrFOZEoW1ZcC831a8Dm/sY5R7esyE6dqiN0a5YCkexk+erT/m+rbW8+fJgQsXr2rXsq187mNMHidMXLpyXRehUODYkysLwrXrN3Xsk1nkMGjdLApZieXpZjREBl2MtG7w+CuVK4HR46frtvnfiVPnUbzIz1eMcFY1XbeNmnfRNzSWYQwe2+AsaCZaE0+eOqcFnnkSzZev33QMX2BloeIsaibDouMWuwZ/d9LljP849sHDJ+LQkRPGLr2koO+rrC0167dW8Z+PlThLic7tnAU3Z/XWbNAGUaNE0rFfrZs3QA/lDjUnWhez5C5t3uVq3dZ5bN+6sbaMTfjvp5A2V6Tlc6Wa/c261smt80DLNZN7bbOMT1/DbNOceF62KBHMWNekKtZzoIpnZQwtLV3WyTinz5Sl+rv6V7VOC1cuUsZBmkMj2EaE8OFVuIWzqDfatNev+TzR3Z1STfAyrj3WZ2wjhZI5cUyMYTUmV7F9upufKtHFcIjgIZxjdFknpBLERqJ4plXQnGx99589e4lUahzmxPAUPoA9ffZc920IR5aJHCmil4SXR8Qa3ez9Bo4xD8XFOt319r7ntDJS1B9QD3pM/N4w9vblK5ehJC4a9eZGYG/Wl+pCQAgIAV8ncOTYaeUyTaBvhuyMrs6508fom8TBw8fBP77GhA9aNThBwjrxtRmMa+QNk0/lnOBAAeLRpCexbLTvdqY7qk7NSsqtq3xzKjFOkLOMaWH8rKwpFKdGoDzjqxzz51Q3+R3aOlRZxYKx3k4VH8YYJsOlzIkddAs+fvIcJZQ1IkniBLptuvby582u3KbOopQB7ZyR3bxNTz1RRhdS//Hm27BeVTC+jInscmTLqMUs+zD6pcWTr9qghY2JcVB0aTJ5lN2uPQfB8dICyMQ4TU5SiB4tqh4TRSITXe9G4sxtihzeZHfuOaDdzcyj293WTd+o596yepUyiK0mMPRT8XHmZD5m9kfXOIUsE2MxOYmKya3zwDy32uZN3nC1s5w5+cQ1bG6P6+HUueQMdl4LDE/gg8PHj59cXE/WdWhNv3TpGkqrWFgKMiZOIqJl+IR6gMiSKZ2e+MH9vHaL2njXoVv9so450ZrIySbGuxd5njnhhnHE5kSxW650Ecs1SmvZRXVd03J6//4jpFUhE8ZDCyflGMm97z6/szyGI+ptAPze8TVRTBSXjE3lQ9PWHXtV/GZOHaPJPO3uTZUcR9TbAjyTaIXmd8mYOGerLsVw8GDBcfK07dn6rOPe9zyL+u7wFVvGuWvaqJaOdzQeBGz16919YlH0LkGpLwSEgK8T4M2tS6/BGKfcWhQQvNHQhUUXEG8yFDecyUixcfvOPVfuMw6QT+Alizli0Zzx2jW3X00CMax27h0AhQSFU2f1uhV7ibOOe3RuqV5NM025lj7rGaOdew7SM41Zb5h6l99Q9eqMkCFDKmEbDD1V3B4nlfAGQgvVTnVjnaJi0eii3bhqtp4lzePla14o5Lr2GqJnq35SYiCOEiUUvJNVHCdnJo8f1V8Pbfa0UZYhzlFu2qUr1utJJIvmTNDs6G7lOP+3/4iLfhkTOUZZKyf/O0hZP2/pWdKMhWPyKDvGlHLG6qbVc3UcHc8bXfAULzeV649uf1qBHj36GVZAa15f3rTVv48fP2PIyIm6z+0qlm3MsD7IqqypNeq1dmGd0wXs/JcrR2Z0ad9cjeExVishZaRO3QepG6yzNZCs96lrgNZevkqIM9J5zgYNn6CLu3Ue7LWdUcWMlVMTGqxdmWzQJ65h4ziMJa8NThBaMOtfPRGHcaGcDZ4oUTzL9cTzap34bk++p6+2EvLv1XfooIpRNN71yXf7Ubzzu/H+wwfsUmLaOrnVr3U5XjdLlq/VM9f5vQym3ivKyTPWaYaKAWQc6boVM3H/wWP1wPJOhU4M18Wu37ytY5J3blqMyyqM4bgSs0ay991nDC6/U05O4/T56KiuQ373GOvMBxnGMvMY+eHrphjWck+JUgq9rupvjdnVb/Rnb8lZ/OyP8Z631LHaSvR+mK2rtsrY+56z/Ao1yatP93ZYsfA//WJ9vi92pIrp9M0UyCFaGtvzt93o9c3zC27kyG4hIAT+ZALWr4JIldHRV3DQGmDECJk7oFWFNwCnH5MfzHnmdd4Ivio3q9ktaM73iXXepPhaESO2ybpNxpPxhmBOZpcv9/N4OFZbsyJpFeR+a8uMuT1b6+HDhdU3SvO5su6XfQYOHMTV+NieR9mxHC0e1hZbjpvnxxZ7W0zYJy2Athgwz6vJ+pg5VlqsbPVj7zzY6t+6bVtlvHsN22qTFnVatI3kkXGQLV8xZL4eWJ88eK7cun6NPri07tecZ6yzPX4fGP9pL3FGM68dW689okv8gxKutixnbn33bTHgcdFybn3MHBet7m694N3euI08W/0ZeV5Z2vuekxW52pq455W+zh93Dk0x6rJtI4lQNEjIUggIAW8RsP7D61tC0VuDlMpCQAgIASHgioA9oSgxiq5wyQ4hIASEgBAQAkJACAgBEhChKNeBEBACQkAICAEhIASEgE0CfuJ6TpAgARInTqwDuh0cHGwOTHb6HIGnT9WPjEeJ4nMNSkt/BAGzK9lY59L8YawZt7k0fxg7d+vRz3ipPwKYHKQQEAJCIIASiB89uJ4cw/hq84exir981nPChAnVz1glV2/tf4Xz592eIh5AWfvLYTs6OmL7dpeBqv5yoDIof0vAEIrGAM3bxjqX5vVo8dIZxWUpBISAEBAC/pjAkSNH9OQYDpHi0JjMooVim/6nPTX0AS2d34/lqUqmwokSJVI/NfQSt27dMu2VVSEgBISAEBACQkAICAH/RuCXxyiGChVKRKJ/uwpkPEJACAgBISAEhIAQsEHglwvFiBGd3/RvYyyySwgIASEgBISAEBACQsAfEfjlMYpuHTtfmBk6dGj1ss1gFt+4W2V9ez/jrPiGficnJx97maVvj1naFwJCQAgIASEgBISATxPwF0KRIjFChAh+LhANuAzeDK7eck/Rykk3PvXmc6N9WQoBISAEhIAQEAJCICAQ+OWuZ1tQaEk0ZtjYyverfRwTxyZJCAgBISAEhIAQEAJ/IgF/YVGk5c6/Jv88Nv/KTMYlBHyLQLPGtS1NHz1+CkeOee6tDXz4c+s3fS0N++BK/dpVsGffIVy77vZbHvLlzqZ/z3jT1t0+2PPv2xTf8RZMeaHMv2vsk0ebJVNaZM7o/GqnSVPnernpfHmy698t3rbjf3bb4G/2liruCPY7ePgEm79jbrcBlSnXkHuEJN87BPyFRdE/WhMNqP55bMYYZSkEfncCvImePrzZcpgUiX83+ikaLRl2VurWrIht6xdg+qTh+lMwX05L6XDhwiJsGJ/3HmTPmgFRo0Sy9GNrJXGi+EiVIqmtLH+xzyzOjQFxn639Rr6xjBLZAauXTHPxOfK/tahUvoRRxMVyUL/O+jyHUKE/1ilUqJAY2Lcztm9YgHkzx2LaxKGIFtVnf0iAx8TrI3PGtOr4annoGK3HaWwnS5IQKZMnMTbdXPIaKVW8IKbOXKTE72c3y9nLMF9DZBfJQSaN2uMleZ4j4C8sip4bspQWAkLgTyNAUdiwWScXFsTpk9LqmzpZTJ4210WeNZ90aVKidMnCKF6uDj6pm7GDQwTM/G8Ejp04g1ev36B+7cp4984J02cvtq76x29TMDGZrWvcx/PhXnr67AXKVmlkKRY6dChsXjMXW7btsewzVjKkT63iwb/qX/gx9pmX/Xq0w7PnL1G6UkO8ffsOxQrnw8SxA1ClVnM365jre2SdxzVp6jx9rHw4oWg0H7dH2vBsmQzpUuPQkZO4dfuuZ6vaLJ8pQxrUqVkBf7fuYTNfdgoBzxL4LYRi/PiJwE+8+An18XN97x7nXyLZs2ebZ5n4avkkSZLr9o2l0dmmTWuMVVkKASFgIsAbNpO1m5nbHhErrBsxYgQ8evREi0Ruv3jxCtXqtNTCpIwSkNUrl9Fio0TRAqhY42+EVxbGQf27IFP6v/Dy1Wv0HzwWBw4dx1+pk6NerUq4e+8hWO/Nm7fo3mcYzl24zGaRP28OtG3ZQFsn16zf5iL2OmWKJKDYiRcvNq5eu4lO3QfhwcPHup75v1rVy6vxlEXIEMGxa+9BjBg7Be/ff3C3b1pIW7eor61J/9t/BIOUG5OCyruJwsmcKJ7I3vp8mMu4te5YIBeOHj+N14qbOQUOHAhtmzdApx6DFddC5iy9TmFPV27eIlXw8eNHvY+u+gZ1qyKzEkaHj51yVccrO3hMtFYzGe5nj7aTIH4c9FXnN1HCePoYb9+5D/6UJRM9U00b1kCFssURRLnOFy9fhykzFuhrqGbVcvraq1yhJIqVrYOSxQqiVbN6+hrcu+8wuqnri+00aVADT58+x4o1m3SbhR3zIE3qFBj171S9zf84hkH9OyOMso5TkDdTYvH6zduWfFkRAl4h4C9cz14ZuFEnb95CqFW7sRaJFIf8DBzQzchGj56DwTJ+nSgMW7TsiKLFSuuhXL16CcaHO4oVK6M/1gLSr8dt9B9I/XGz5YavVK02GjRuqYuFCBEC02YvRZSo0YxqLpZswzqxTVv7rct5ZluPleO18fFMO1LWfxDgDZviwjvpiBIScWLHxPjR/2i3Z/y4sfHhw0f9RoONW3Zi+eqNmLdoFeo0aqe7adqwJp4+e478Rati1Lhp6N7Z+RoPruKpC+TNiUtXrqNE+brYtHUXOrZtouvwJt27WxuMnTAD5as11Td3WneMRJG4aOla5C1cGafPXNQ3fiPPWJZWIomWstoN26r26+nd3Tu10Et7fSdW4qRP97boP2isrsdja9uigdGst5a0qBluWIp2fmjB9UoqU6IQ1m1wfog31y9fphiOqHP8+MlT827LeuyY0fHo8VOLSDQybt66i9ixYxib3l7yOjNCEwzrokca5Zs7Jo0diB279qNEubrYrERsFSX8jERXe+6cWfSDTW11jTGmsGihvDBfexWrN9XisFfX1mjRrheKlKmN6NGj6nJsJ3z4sFoAGm2GVj9eETFCeGNTL2/fuYd/Bv+Lk6fOge3dvH3HRb5sCAGvEHB95/ZKK35UhwKQVsR5c6fqz61b19WvvlzXo6ElkR9DNPqlWKT4o0DcvGktJowfoQUi9xmikIKRFkUuWc7Y70dYXXWbOk06bNtzHINHjHeVFzlyFESNHl3vDxQoMBImToqgQW1PTtq66yjYlpEiRnTAtDnLUKFSdWOXt5cOkSJj884j+rNF9cdxG9sr1+/ydvvSwK8nYFh4bPVsCBdbeeZ9Tk7vUbVOC+xWFrocWTNi7owx+HdEXz3Z4PPnL9rS+OnTJ8tEggVLVmP4qMl6wgRv/jFjRAMnHTDdvHUHGzfv1EJzyfL1YCwaU7nSRUEL0M7dB7SlkRYj86u1evQbgVXrNuu+duzej4QJ4up65v+qVSyNfyfMxPMXL3XftCYWccyrJ+CwnFt9l1V9b962G5cuX8P3b9+UIF2DgvlzmZv21rphVWQIgFetidGjRUGypIn05B7zYMKGDQNa1WbOWWLe7WKdMaTv1HttrZPT+/cuxJN1vme3KYpppaZg5NKjbudsWdLr3zmfs2A53qoQhs3KtX7m3CVL9xXKFsO8hSvxXLnOXykL9dqN2+Gozo/52mM9TtChK50WZ1qrDx4+ri2UlobcWfn27bu2PtMCyfa4LUkIeJdAgHU9G8KPItG9RMFIqyPr+IUrmuKPApGJlkMjURgyaXF4NbkWi1BeBW5fHf/zj4xR3q+WBRyLYfvWjchXoDDCq/ddvlbvlvRuChc+AoaN+Q+b1q/G8iXzvducpf6L589QJF8mvZ1IidapysJZukhOV5YISwVZ8fcEKExoVeREA/ON29klXfvH+O3HKLIQrWxLV6zXH1q/J4z5R7v+lq/a6IpBsGBBMUR5JjgRhTfboEGCqo+zUGRMo5HoluYkC6Z4cWJh9/8OGVlaBJw5//N7HFNZh3p2aaVn7IYKHRJO795byhorcePGUlage8amvuk/fvpMW0O5062+4yirWro0qZBdiWAj0e3M46AY8W4id2MykeHuJ3/PuJ/pUt2qZgBbj6dZo1pa2L5TYt6t9FhZEx1U+IB1okWNcZA+kXh9cRILj4vCmKKYcbBGzKK9PuKp83b85FkXRU6cOqvfxcudtGa3alYfzZvUsZS5qES9deI1mj9fDhQvkl9fd7z+1m/aYV1MtoXALyUQYIVinryOFmuhR4jRJU2xaLY6eqSeb5Qxu5x1+z/EIdeZ1yJJR9/o1ktt0n2br2BhdGjdGDFjxUZuxX3D2hVeasuoFDZsOAwfM1mJzw1YumiOsRu0BrZu1xUZMmXVv4qzbvUyLJo/U1lygmKC+sM9duRAnDvzMxap78CR2LltE3bv3Gppw95KkmQp0L33IDRvVFOJBuebUujQYXTbXdo3Q/wEiVCpam0sW6xuEi3bI1q0GDh39hTGjR6Me3edXTh0MdVXrvaChYohRMiQOLBvNyaPG6me/l/rrnPmzo+mLdohatToOHvmJIYO6Ilnz2y70+yN1T/lJU6cTF+XfjkmChXDJWi4oSlSDNHi3tga1KmCO/ceYOv2vboo49wOqwkEsZRL01YaMbindiHTQsh0dN86W8Vc7KOIC6Mma5hThPDh9CZj7Pr2bI+a9VvruEROrunc7m9zUb3+TIkexjL9uOpTAABAAElEQVQaLliGZkRSAomxaYybdCvRUrVSxa6NnzzbrSLe3m9YFQ1xSPFurHukcbrV+w0c46Jo3DgxUaNqWdy5+wDV1ZKJr79ZPG8Cuqh4Rbr4me7efwSy5CxqszCkNXfSlLm6jHf+o0hkMq4nikVashs2c3ZFuyeKX716o965a33uw4MWT6Znz1+oV99MVJNWTuhtt/6jlZFu6bqNO+iH20b1qoEWV6avaqJPCBW3aiTzurFPlkLANwgESNczLYPGZBXGILr3YXlDIHKiy69O165etriTDfcy4xX5oYWRrmbD4sh1w9L4q8dpq7/0GTLj+dOnuH3zBnYoq2IBx6K2inl4X+jQYTFk1ETs2bUNi+fPstSjW88Iyu7U9m8lzoagcLFSqFC5hrJAfMKF82dQqmwlS/noMWIiazYVGH/kgGWfeytXL1/UN6H8jkUsRXPnLYi3b97g8aOHyr0XCilTp0GN2g2VwOuFxvUq6/2jx8/QopCVWrfvjsxZc2D08AHo3qmlihFyQOce/XV7FMC9+g/F9CnjdN2PHz/g71YdLH0F5JVmzdu7Ofz6DZohXz7fjwPmTZyxcYYr2hCMbg7MlHH95h3UqVHR4sLlK0Ty5s6KU6fP61KcXGGIOu5gTNyFi1d0HmelMj7QvUQ3IcWQ8WoXigvDLR09WlQ9scSYvJI1c3qbzW1RQrZc6SKWV/WUVy7li5ev6wk1Niv82LlzzwHtyqQgZUqfNhWGD+rxI9dnFhTrZouued29Hih+gwcLjpM/eFMgUhQ9fvxMx1Q2bdUNzdv01J9vynXepkNfPQmDnPjqIAr7VWu3oI2Ku+TEF6aypYroSUmGmHRvDPbyrY+NAtgQwYZ4tFf/hIoJzJIpneXBI3IkBxRVsaZG2rXnoLZeBw/ufB3xVU2ctGSd+OByQ12rPF4+JGRW15CR7j14pLd5/Px7WTD/z9c7GWW4fK3+noUP7zJ20Zwv60LAswQCrEXROFAjBtHYtrekuKQl8lcnxh8aglDHIv5wK9sShRSJSZQbmiKSAtOvZ0Mbbmcy27Vji7aWMbbw5UuvuXvad+6FWzevYcGc6S5OQ978hdQkmOho3riWcrc54crlC4gUOTJq1mmsLXzrVi3D2EmzMH7MULx7+xaOhUtg7+7tet1FQ+5srFuzHCVKVdAubxZ1LFICG9attNQKHSo0hg7shYcPnN1/Y0YMwJxFa1BIlTu4fy+KlyqH9q0a4cyp47rOpPEjMXvhasSIGUtZFMLgg5qduv9/u/FF/Vb4qGH/IEHCxJa2A+rKtWuXkfhaMlAsTpo4ysVhNGjYHNevXcHu3b/m7QLGzdtYuhiMnY1dSkglTZwAS+dP0nFivJGvXrdFxcs5Wwy37/wfxgzrg6wq1qxGvdb6NTnzZoxVbuC7eMjZ0up8upco8uj+Xbl4Cp4oCyAnFhjuyMvKMsb4QvZPy+OjR7atzDPU63m6dWqOdStm4v6Dx+qVPe/Uw8dw97rGvgNHkVzF/61aPBX31Ixs/lY9Zz37l1SmRGGsU3F5RsqTMyvKlSmK7bv22Zz5TeZ0UVerXBoPHz7BeSXax6hJQt06NsPaZTNVnOcnFcf5Ch26DTCa9NWle9cbHwCGjpyEGZOH60k37z98AK85I/03fT44SWXT6rn6emIMaqfuA41sy5Kxjf+NG4RZU0bqmEfzrPUNygXNWMcta+fpc3xFxTHyp2at07kLV3R8I6+1AUP+xakzF6yLyLYQ8BSBQH0nf/dUtOuAlu4/WdsbQa1atbB9+88/GCwbJUoUe1Vc5dGC6BmBaDRAayKFokfiGo06XD5VFjWfSEZ8YuIkybQIZJvGurE0+jHEJfcb1kYjz7NLR0dHV8w90gbdrEtXb0cnNavzyeNHukrfgaOwY9tGrF21VG/TzRrRIZK2wNEit37bAdSsXNIitMz9cGLJxHEj0LBpK4wY3Bc7t2+2ZDf6uzUKFy2FUyeOWvaFDhMG2XPmRclC2fUT9sSp87Fpw2qsWblET4IZN2owTp08ZilvvWLEKJZwzKbrM5+xkUtWbcHfDarj9etXmLVgFaqVL6rFaZ58jsrl3EGNv4SLprr2GqCtjocO7MXAYeO0YFZ/xS1l8uR3VLNd2+HEscOYOG2BslqFVGJxF44ePoBjRw7qP/iWwgF05bs63qJFS2vh+9/kMfqYGikXPEXi9u3Or+tgGX6YuIwWL52/PFq6cN+o+D1jrOZBMt6Qr6JhYhwjk/E6Fr3hgf/4vaHliBNorBPdiNxPq5m9RIsR4wsZs+aZRCvUr/zlGc+MzbosLWPuTbbg8VifJ7qmydezbKz7941tjpfnmBNRbCWeU5bhuzztJV6j1q8QMsqzfbOANPZbL83XsnWebAsBawKPb5+yvNmE1yg/TFwGSIsi3cgUfcYMZx4MxaN1ogXRPHmF5WvFb2xdzNe3aTnkx9o6aGsfB0NBSYsiE62KfpUyZcmOcOHCYbwpBogzm799/2YRip4d26WL59R7vrqjR+/BylLwABfOndZNUGQ+f/4Ux44edNEkrYZGWqtiFstWqIKzp0/oJ+nTP6x6Rr5Hlm+UONyzc5uyDJZXbuUH2Ktc4LRgGumTchdbJ/WVUTO5g2rXNN3gx6zc3Rzzndu39AzXlk1q60k/2XLmQb9Bo1TZQ0pEtrVuMkBub968FoULl8TQoeNxRVm+KRJ37Pgp9gPKQbl1A+b4DZHIdc8KRNZh4kxn82xn573O/3vkBs+SnLVqvIPPXN+9dYoq8zG4V94v890TiRybtUjkPops/ygSjfG6JRKZbz2Rh/tsJXvXqEevoYByHdg6ftnnvwgESKFoC6FHLIzm2EZbbfjWPu1OVkLRcCcbMYjGfvbLmc5M/sHdrAei/iugJmz8N3GMqwkni1ZsRqRIUbSwM8p6Zrlvz07MnDZRuUXGoEWTWsr6eB93bt3Q8Y9bNq3Tr/dge8GDh0DcePEtN2xaMpu36qjc3+2xcd0qmzcRj4yDgrP/4NF4ouISx4wc5KJKDDVhh6LVmOzCzHQZM2PZorm4rcbIvEsXzuHmjWuWegkTJcHLF88RLXoMxIkTH1s3r9MfWoOnzFqiLAzhlAXg50xZS8UAuLJ163rwY+sGHgAPR4YsBISAEBAC7hAI7E6+v8zmDdsvYg29A4Oi0HAhGxZGI26R7TLPyB89Zqq2Kpoti97p2yt1KdJy5S6g4wDN9fn6mfNnTyNvgULm3Z5e52xnWgvpyqWLeYeavcwZ1tVq1NPbtODRRV25eh1L2x9V3A9FGGdFb9m4xrLfsyu0SPI4gqoJCoZF02gjcOAgaKYmoND1x1nNFSrX1EJv25YNKrbyOo4fPYRadRuDk2mYGFvZb9Bobf1h3BStiLHjxNN5oVS8I2dLv3tn2w2lC8l/QkAICAEhIAT8MYEAaVGkC5lC0dr9TM50QVu7nA3+rOMRy6NR3ieXhjikYDQsikb7Rp7hiqaLmutM1mWNOr69zJYjN+7fV4H8PyZ1mPujwOPs51XLF5l3e3qdM5spFPv8M0LPIO7WoTnaqckuNes2UpNC3uPihbMYNfQfF+3SksdYQe++cobtWItEdnT/7m0lCG9gtprAEl7FM75+9VIFobfVFkPm023etmMPHdvISTX3VPmRQ/rqmdm0Ks6YOl5bSsOqWYecLT51knM8H+tKEgJCQAgIASEQ0AgEyMkshEw3svGrLB6BzvJM5phFj9RjGZ+azMK2zBNauM1Ed7MhII187jdEorHkPq8kr05m8UpfPlGHs4c/fXL+eTXr9v6bsQizZ0zWk0Ws8zy6zVnbc5esQy016eaVEoJG4mSWBo1boH6tCjqAly5j4/2IRhljSWtkMPULNOb4RiOPSx6Dk5P3f2fX3KZfrlu7ms3bxjqX5nX/OpnFLzlK30JACAgB/0jgt5vMQsgUfBR//NgTf8ZMZ7qr7ZX7VSfOekKLdb9GvuGW9q5ItG4/IGy7JbBS/ZUODuonA2lR9E4qUboCjh7a70IkWrdHweOWSGRZvv6GH7eSW8fgVnnZLwSEgBAQAkLAPxIIkK5nA6QhFg13M/dzH8Uhk+GedssVrQv50/8MwehPh+cnw4oQISImjh3mpdmg5gHzRdgL580079Lrd5Ubma/fkSQEhIAQEAJCQAg4EwjQQpGHQGFoCEZuUzQar82hFZEi0dhmvqSAS4A/l+cTya3flr6hXvfCjyQhIASEgBAQAkLAmYC/EIp08xkvd/TqiaFYZDKWXm3Hup4Rc2W9X7aFgBAQAkJACAgBIfC7E/AXr8fhz0351+Sfx+Zfmcm4hIAQEAJCQAgIgd+DgL8Qik5OTpbZkv4JK62JHJskISAEhIAQEAJCQAj8iQT8hVDkz129evVK/9C7f3D1cgx8eTLH5NZPcf2JF4scsxAQAkJACAgBIfBnEfAXMYpETkH2+vXrP4u+HK0QEAJCQAgIASEgBPwxgV9uUXzx4oU/xiFDEwJCQAgIASEgBISAEDAI/HKh+EH9Xm+CBAmM/mUpBISAEBACQkAICAEh4E8J/HLX87Vr15AiRQr1Uuz46v2Gt/wpFhmWEBACfkmgQPGKftm99C0EhIAQCHAEdm5c7itj/uW/9cyjSJgwIRIlSoRQoUIhYsSIvnJg0uhPAvyt6ihRovzcIWtCwAMEzBPLjHUuzZ9v377pbS7Nn69fv+LWo08e6EWKCAEhIASEgF8TiB89OIIECYLAgQO7+PAd17/cokgYN27c0B+/BiP9CwEh4HMEDDFptJgqo6OxKkshIASEgBDwxwQ2btzoYnTmH0H55TGKLkYiG0JACAgBISAEhIAQEAL+loAIRX97amRgQkAICAEhIASEgBDwWwIiFP2Wv/QuBISAEBACQkAICAF/S0CEor89NTIwISAEhIAQEAJCQAj4LQERin7LX3oXAkJACAgBISAEhIC/JSBC0d+eGhmYEBACQkAICAEhIAT8loAIRb/lL70LASEgBISAEBACQsDfEhCh6G9PjQxMCAgBISAEhIAQEAJ+S0CEot/yl96FgBAQAkJACAgBIeBvCYhQ9LenRgYmBISAEBACQkAICAG/JSBC0W/5S+9CQAgIASEgBISAEPC3BEQo+ttTIwMTAkJACAgBISAEhIDfEhCh6Lf8pXchIASEgBAQAkJACPhbAiIU/e2pkYEJgT+XQJjQoZA3V1b9yZUjMxImiIugQYP6GhD2dWDnSmTKkMbX+rDXsPl4w4YJ7aJosGBBLSwiRgjvIs+jG9myZNDHlzNbJnersD+yaNWsnrtlpYAQEAK/PwHf+8v7+7OTIxQCQsCXCMSJHRPjR//jovWPnz5hxuwlmD57ET59+uwiz9ZGhvSp8e3rN5w6c8FWtot9FKFhlEALEiSIi/2/asN8vENHTcb8RSstXRfImxMjBvfQ2w2bdcKRY6cteR5dCRIksPPxBfXY8ZFF8ODBPdq8lBMCQuA3JvDLhWLMmDF/Y5xyaELg9yTw/ft3Fwdm3jbWuTSvu6jgxY0FS1Zj8tR5iB0rBqpVLo1mjWshapRI6D94rLstdm3fHB8+fkTdxu3dLeufClQoU9SFUCxXuoh/Gp6MRQgIgd+QQJQoURAoUCB9ZFya18X1/BuecDkkIfC7EKDl8OWr1zh34TJ69R+prWkVyxVH/Lix9SHmzpkFS+dPwpH/rcXmNXNRpUJJvb9vz3ZInDg+UqVMinXLZyJdmpR6f91albBp9Rxdfsm8iciY/i8XqOjinj11FA7tXo0500YjRfIklny3+mKBFk3rYOemRbrexDED4OAQQdcLESIEOrZtgi1r52Hf9uUYNaQXokeLYmnTeuXk6fNImiQh/kqVTGdFjRoZObNncmUVDR48mHYNb1g5C/t3rMCU8UOQIlliS3NJEifAzP9GaBcylwnjx7XkcWXG5OHo1bW1ZV+hgrk1p8QJ41n2GSv2joFu8uGDeuDArlXYu20ZunRohsCBnW82Rn1ZCgEhELAJiFAM2OdPRi8E/igCe/Yd0k+6yZIlQoTw4TBmeB88evwUbTr0xaXL19CjSystItes24onT57hwYPHGDdpJu7cfaDj/Dq0bozNW3ejY9cBCKFcq0MHdHPBr2nDmth34Cj6DBiFaEqkTRo7ABRD9vpifCPrTZ42H2069UXav1KiZdO6ut0+3dugQpliOq9b76E61nL00N5uiqmNW3bindN7lFd1mMqUKIRnz17gf/uP6G3jv+6dW6JOzYrYvfcQRoydqq2sM6eMRMwY0RAqVEj8N24w4saJiQlT5mD/wWNoWK+aUVUvY8WMrusYO3mM8eLGQjAb7mZ7x9BEHXduFUPatlM/jJs4EzWrlkORQvmMZmUpBITAb0Dgl7uefwNmcghCQAj4EYHPP2ITHdSkDrq5W7XvjQuXruK90weEDhMK+fPmUBa5BNi2cx9ev36rXc+bt+3Ro71+8w6atuqGQ0dOIlTIEFoQ1qpeXotA43BWrdmEKTMW6E3GRI4d3he0JFJsudVXKDXxhilkiOC4e+8hipappcUsrYqlijtizfqtyhJ6UpfZsHmntgTGjxcHN9R4rJOTOo4Nm3agRNECGD7mP5QtVQSr1m3B169fLUU5oYXik6Jy6KhJej9F8sLZ41C5fAlcunLd4p5ftnKDzg+pjrdx/erwrK3PvWPgWL6qONBwYUNj687/gaw/fPxkGausCAEhEPAJiFAM+OdQjkAI/DEE8ijrHdOtO/fx9p0TsqvZvIP6dQYFy4cPH3Ve0GDB9NL6v3dOTqDbesywPsqi99OZwlm+Rjp87JSxius3nIUcrW/2+tqybS8K5suJdq0aoUObJtrCOWTERDx/8VK3RbduvjzZLe2+ev1GW/5sCUUWWrZqAyorF3rHtk0RP15srFi9CcWL5LfUTxA/jl4/evyMZd/5i1f08SdQLmZaJJlOnDxryT9x6pxl3TMrCZSgZXLrGGbMWYxkSRNilLKSMnEc3XsPw/Wbt/W2/CcEhEDAJ/Dzr2XAPxY5AiEgBH5jArRuZc2cXguwc+cvoVzpoqhfpwr+VS7PrHnLoG3n/naPvnO7v5X7ORvqNumgy8+ev8xV+dQpnWMDmZFaxTcyPVYubHt90ZI4TM1UzlGgPFq264WPyqLWrVNzJRif6PqLl65FnkKV9KdAsWooW7mRsjD+FKS6kOm/CxevasHFeMvDR0/i3v2Hplzg4SPndlOa4icpHmk1vPfgEZ49f6HLm+MrjRhNoyFaAcOGDWNsqhnRP9ctO9WKe8dAUdq8TU/wuHr/MxJJEydE4wbVzU3IuhAQAgGcwM9H6QB+IDJ8ISAEfj8CSRLFVyKtiIq3i6XFGidK0FpHC1/kSBH1AT94+Fi7WmvXqOACwO2795EtS3o9YeXmrbuI5BBR13v58pWapJJYu4VdVFAblZTrlkLszZu3WoRSCNHtTEskk62+0qqJMhPUq3wYn3j2/GVV/7Eue1/FRx49fhqlVJwhX9FzUbmHW6jYxWxZ0qGMEoufP3/R5Wz9R5dx725tsHzVRlfZHN+BQ8dRxDGvbvPKtRs6RvLLly/azc2xU6xSRNN6yeOm0DWn23fuIUvmdChUIJcS3q/0jHJzvrHu3jHUrlYeJZV7vUnLrjhx6jyc3r8HWUsSAkLg9yEgFsXf51zKkQiB344A4wP79miHomqCxKkz51G9bitsUpNRmBi7d+3GLT3jd+WiqXj69JmL41+0dI0SfO8wS03ySJc2JWbMWaJe2h1Ez0AeN7Ifzl+44qI8N+jm5Yum+Q5HCqzOPQZpC6a9vvbuO4ylK9ajT/e22Lp2vop/DKknkbC9Lr2GqH4uY+SQnuAM5fjxYqmJMqPh9MM9zDK20kYVy3hfWQd37N5vKxucGHPoyAl0VbOMZ08ZhXhKSHNCyZWrN7TQ7dZnqBbPnIHdvEltJTidYxWNlxxN+G+2juGky7ifmiG+c/cBm/1wp71jmLtwhY4RXThrHJap2ednzl7EkhXr3GxLMoSAEAh4BAL1nWz1gjR3jmFAS9vxP+5Us2TLexQtKGRFCAQYAsb7EY0Bm7eNdS7N69HipTOK+9qS7/pyiBhBv0Ln27dvNvuJGDE8Xr58rfP4Qm3OYDbiB21WUDtZhtY4c3KvL+aHVjOOjRhBc12+ziaYeqm3rTxzOc+uM74ydKhQrsbKdn6O9xW+fTMk4s8eaJ0NHy6cZvdzr9tr9o6BeerNa+AEIElCQAgEPAKPb59y8e5E/v1g4lJczwHvfMqIhYAQ+EGAwtQ90WeIRFbh7GH3yrOctUjkPvf6Yr5bQpDvg/TIr8mwH88kuq9ffXYpaI367o2X4pHvqPRosncMvnFsHh2XlBMCQsB3CQQd2zut7/YgrQsBISAEhIAQEAJCQAgESAISoxggT5sMWggIASEgBISAEBACvk9AhKLvM5YehIAQEAJCQAgIASEQIAmIUAyQp00GLQSEgBAQAkJACAgB3ycgQtH3GUsPQkAICAEhIASEgBAIkAREKAbI0yaDFgJCQAgIASEgBISA7xMQoej7jKUHISAEhIAQEAJCQAgESAIiFAPkaZNBCwEhIASEgBAQAkLA9wmIUPR9xtKDEBACQkAICAEhIAQCJAERigHytMmghYAQEAJCQAgIASHg+wREKPo+Y+lBCAgBISAEhIAQEAIBkoAIxQB52mTQQkAICAEhIASEgBDwfQIiFH2fsfQgBISAEBACQkAICIEASUCEYoA8bTJoISAEhIAQEAJCQAj4PgERir7PWHoQAkJACAgBISAEhECAJCBCMUCeNhm0EBACQkAICAEhIAR8n4AIRd9nLD0IASEgBISAEBACQiBAEhChGCBPmwxaCAgBISAEhIAQEAK+T0CEou8zlh6EgBDwQQLNGtf2wdakKSEgBISAELBHQISiPTqSJwSEgL8iMH3ScGTOmBZc+peUK3sWRI0SWQ8nSuRICBYsqJeG5p269joMpDKDBQtmr4i7eb41Nnc79mIBHnOIEMHdrR00aFAECSy3QXdBSYE/moDX/qL90cjk4IWAEPArAg2bdQItipOmzvXWECjsmjaojRcvXuL79+/4+vUbDh87gROnz3q63UQJ4uHBw0d48vQZihcuiAOHj+Lq9Zs222lQqxrChAmlREwIUKS8e/dOl5u9cJm7dW026M7OHFkzIUfWzHjz5g0+ff6MQ0dP4OLlq+7Ucp3t3nG5ruFze8KFC4tyJYvCIWIE/Dt5houG48SOifKliuPW7btYs3GLzsuYPg0K5skFp/fvEViJwGWr1+Pho8cu6oUNEwblSxdTbUZEcCWiL1y+gg1bduhrwUVB2RACQgAiFOUiEAJC4I8k8ObNW0yYOksfe8iQIdCoTg08fvIU9x489DKPuYuW2a07Y94inZ8pfVrEixsbK9dutJR3r66loAdXKKLS/ZUKYydNU0L4K0KHDoX6NatqUfX+wwcPtuJczKfH5tHOQ4YMicplS+HM+YtK8GZ0US2hEujZMmXApSvXEFIJb6ZoUaPAMW9ujJ8yEzxGisaSRR0xfc5CF3W57/LVG0o4H9cWxbo1qyBVimQ4d+GSi3KyIQSEAEQoykUgBITA70WAbunJ0+biyLHTHj6wDx8+4vXrN4gcyUELRbpaSxcrrIXHoydPsG7TNjx99ly3lzxpYhTKnwchggfHqbPn1T46Op1TuVLFcOLUWdy6c1eXyZAuDT4rS96GLduVMLluFLO5NNetWLYk7ty9jwxpUyNM6NDYsmO3rlOoQB7lRg6OrWr75Jlzep9bYw0dKhReKzFMkcjk5PQeU2bNwzdlPWVyq17smDGQI1tmPH/xAvHjxsHMeYthHptb9ejqrVimBOLFiaPr0pL3XFls7SVaVhvXrYH/Zs5VnL7oovlyZcc7JyccPXEanz99wuyFS/VYrYXi3XsPcOPmbWTLnBEhozoLRVoQ127aqkUiG3vy5Jm2GFqPYceefZbz+fXbN3xQovKbWkoSAkLANQEJznDNRPYIASEQgAhkyeQcs0iXND+eFYlBggRBsiSJEDdOLNy+dx/crlW1Ak6fu4BRE/7TYrByuVIIHCiQFpKlihXCtl17MXH6bC0u4ivLoJEo6uhSjhs7FhLEi4MxE6cq1+c6sM5POWmUdrk06nJvGGX9oyCdo1zSS1atRanihZEuTSpMnjEPi1es1m5qxh3aG+vN23e0u7ZG5XKgBTOSg4MWYxRG9uoFCap4JE6IL1++YsmKtXqQxtjs1cuaMYMShq8wfOxEnLt4GQXy5nJ5gDa2Pn78+P/2zsM7qyrf+78UEkKQJJRAkN57IIANQXoTpCg6qKgzYL2z1tx33uVa8ze8966545or6ohtcMaCigICiihNWmihJNR0WggkpJJAkvf33XE/OXnytEAqfPdaec4+++y9zz6fBw5ffmVH3eJF0r9vH9fVUWoFTcvIMudYqxW6rg6/VSDA3QtczE7X+oD+fSQ1PcO9mwkTQMjBgH59zX8IgvS7PZuaVqcfG0iABEQoFPmngARIoFUSgEBEGZcQL4hdPHAoyZwHakmM6nCfvPmnN+Qvf/6jsf59uXa95Odfl359equFqcy4O4OCgiVZRQ9coDEx0WrhGyFnzqUZdyf67Ni9z6MlKjgk2MTHRahLG5avt1aukiqzusA/Eg8dMZYxjL9+vUAS9flg+crMOq+WwkIVftE+11peftNYEE+dSdV+vWT5C0vld08uMCLR1zNihbDo7fh1rzk6V+xrHJ4Z8X4hKpR/3ZtYy63unMO9DlE5dNAA04zY0Vu3bsnVa3nu3ep9DssnXO+7dC3eSpfOHaV7XFf9DqvuOOHH2z3YTgKtnQBjFFv7N8j1k8A9TAAWRKdADFQkAtl1dTUjfg9Zyz26xxkBiHYkTUR16CCvvPQcTk2B9QpWNYgzpwsZ1q7zF+rGNGZqcgWsYq/+4QV1+ZbInsSDcujIMTtdQEcIUVtQdz9vo4LM11ohtuDOPXjkqPmBpfO5JYuMZTI0JNTrM+KeBQVF9ta1jr7uh2QguOv/7x9flUs5ObJ1+y4jamtN4OEEiSRTJj5ihPUQFYzJp8546FW/poiItvLM4idk/aYtmjBU4nXwnv0HNfnooMxXi+0DGu+4bedur315gQTuVQIUivfqN8/nJoFWTgCisD7C0NvjQihAFEKkwG1ZXFIsObm5JjbPfQwsVGEam+gsECXuBa7Mreqehou6b++eKloWaDxdluTl+47Zc5/H37mvtUIA56mFFBZRFFjq0jIyJVpFMOIuvT0jkmzglvVUfN0P28ysUatsqFoVx2oSyZPz58r/qOvdX4GQw1rgqsd38O2Gzf6G+LwOQQzL6a69++VcWl23MzKdsT58N7YgHnTEsMH2lEcSIAEHAbqeHTBYJQESuDsIIKHFuqb9PRGSGNap5WnO9Clm25r0jGyzLyIyaFGQcLF82VIjEFMzMqotcipGUPr06imxsV1M3fnRV93XT2lcIwRXqiZcQCBWVFQnazj73Wnd11qRfPPw+LGufR0hoAZqLGaWurJ9jfO1Jl/jJk96RJmPMck7iO+8qcI00AIxC4seXNfYZggFsYqRke3qTIHYTMRcQoy7F7Qs0oSiFLVKJh1DolFNgUCEEC0sKpKRw4eaRCVchcBFPOily1dqOrNGAiTgIkCLogsFKyRAAi2dAMTf6y8/bzbd9rXWapG4TC2Ob/rq5rp2QbfESVFr4gzNKkaG8zfrNgqSQEpLy6SyqlL2Jh6Scs3ATU45rW7q7vLGihelqKhYrmpmcGZWtmseW0lNS5dRw4cYSyUSMrCvIjKQG7ogltDbWrFtDMTua7pfZHFxqRFdR46eUBd7dfa1t3G+1ujrfokHj+h+h7PNc8MeWR83bsqpsyZBZ9ee/eb2SByaOWWSbFDmzuQUXOzcKUZmTJ1k4kSLftuH0gzSjymPTZAhgwdKt65dZLzGrqJgj8yVqz6RgZqggxhTzIdnXzx/jtzS0AEIyDRNeNmuMZksJEACdQkExcSO9OxjqNvXtBReS/FyJbDmuLi4wDqyFwmQQIsh4O6KdJ7bOo7Oemyv6n+oG/ohIAL9uZwbYlNurBtuZghE9wIrFLKDkTDiqyBLuEqFYqUXV66vsfW95m2tmAfJOGWaCOPpZe9rnK81eBsHyyXc3HdaYDG0f57c5/J1zb2v89x9HKzFiD/l1jhOSqzfiwRyMpNcVnr8PcEPiqlTKN6LfyT4zCRQPwLu/2A7z20dR2e9sYRi/VbO3iRAAiRAAv4I+BKKjFH0R4/XSYAESIAESIAESOAeJUCheI9+8XxsEiABEiABEiABEvBHgELRHyFeJwESIAESIAESIIF7lACF4j36xfOxSYAESIAESIAESMAfAQpFf4R4nQRIgARIgARIgATuUQJNvo9i587Vm9jeo7z52CTQqgjYLGa7aHvuPKLu6ceO4ZEESIAESKBlE4jW/UTttjjuxyYXirn6q5pYSIAEWhcBKwztqp3ntm7FIvqgHtuht+3OIwmQAAmQQAsmkK+/ParW3omOfRTpem7BXxyXRgIkQAIkQAIkQALNSYBCsTnp894kQAIkQAIkQAIk0IIJUCi24C+HSyMBEiABEiABEiCB5iTQ5DGKzfmwvDcJkMDdQQC/y3lcwqhaD/PuqtV+fwd0rQE8IQESIAES8EuAQtEvInYgARJoKQTGjx0lr61YJgcOHZXlr79Za1m49sE7/1WnvVanRjiZ8NB4OX02Va7kXpXOnTrK9YICuXnzlutOYWFtpLz8puu8KSqDB/Y3geknT59t1NuFh4dJeVm5VAV4F38sfF0PCQmR4OBgZdu0LAN8NHYjgbuWAIXiXfvV8sFI4O4jMC4h3iUEIQohGGFZxPGd91dr/ajA2oi6r9Klcyd59Q/LJC8v32RoV1RUyv6Dh+Xw0eO+hnm81q9PL7l46bIRinNmTJU9+w/I2dR06dent8ybPU3KVEhVVFbKqTPnZOfufR7naOjGrrFdJFizFhtLKPa4P04WzZsjt27dksjIdvLD1u1y7ESKhIaGyrTHJsiD48fK397+hxQUFplH69+3jzw+a5rpHxISLHsTD0vioSOux/Z1PSwsTBbMnWlEOLIyy8rL5et1GyU//7prPCskQAKNR4BCsfHYcmYSIIEGJmDdzbAeOi2KEIdog0CEgAykFKqIefv9j03Xtm3DZcULz0rOlVw5f/FSIMM99ln9+VemHdavxU/MkVX//MwIGoi2Z59eLFm9Lkh6ZpbHsa2lEc/y9KInVKx9LxmZ2dKpY4y8pqL79NlzsvDx2XL6XKqK4zLX40CUz58z3Yi7rOwLEh4eLsueWSzFJSWSfPK0+Ls+ddIE03fNtxvMnOP1PwsLH58lH//rS9c9WCEBEmg8AhSKjceWM5MACTQwAVgOURIPHjWC0J7bNohFZ5vpHMDHjRtlUlBQaEQPhCJcyPNnz5DYLp3l8pUrsmHzT5J79ZqZCW7d6ZMnSrhaupKOJ2tbkOsOC+fNlsNJx+VSTo66foOlqKjYXKvUfSU/++rbmn3KtHXShIckIX6kBAUH6ZqTZMdv1sa4brHyxJyZ0jEmRnJ039mvVCBd17U9OG6MEVndu3WVq9fyZMsvO6Rv754yc+pkiY7qIJcu58i6TVskT/dDQ4Fb+JnFT0ifXj2NxXPNdxuktPSGuebtAyLu5Reflfc+Wu1ynz+m64SoO3C4mn2Y9tm9L9GIRMyTp5a9ysoqCQkOkW/WbzKu4ZlTHnPdAsIOTCASUSAid+7ZLw8/MNYIRX/Xe6r18pedu13zHTl2Qp/5MYlo21ZKb/h+HtcgVkiABG6bALOebxsdB5IACTQ1AQgqWAytRRHnsCLiB20QkCi2TyDrg/Vv0IB+0rNHd8k8f0Fw/rxavI6qK/Wvb79nxOCShfOMKxfWs3mzp8tP23bKyg8+UYFUKb173u+6TWS7dsb9CnfzudQ0tVIuFcQw3h/XTaq0L1y1KAmjR8mA/n3l43+vkQ9Xf27uP3zoIHMNInG/umX/31srJfv8RZn0yEOmHSLuwbFjBEJp+697JUZ/k8Ki+XNl/eYt8t9/f1fSMjJl4bxZpi8+hg8dLNt27ZG//+NDuan3fXBcguuatwpEHCytcAXbMmrEMJ27xgp6Q8XZ3sRD9rL07tVDruXlSUlpqcf4weioKCNsXQO0AqEbo+0o/q4Xqtju1aOGsYlV1O+oQ4f7zHh+kAAJNC4BWhQbly9nJwESaEAC1UJwtUloeW1F9cSIS7RxiohhtOLx6P4fZNQDNcLJfRlRKjTe/NMbggQKxCp+uXa9cRMP7N9PYGE8lnzSWAXhHp386CMSExMtY0aNkDPn0ky8IeaDFRCWMU9lrVrXBqn1ESJ0rApDiERYFWGBSxg9Uq1yB4ylDmOTjqfIkEED5UTKaVm7YbOJd8Rvtzl55qxMnTjBNT2SZmzc4cRHHpAjR4/Lhd9c5b/uTZRyTfSw9s2UU2fkcs4VMxaid4QKx0DKCX3eoYMGmPvALYx1Q9h5KohJnKtxmRt/3OrpsmmDW7/MLZmnXOMMIXxR/F1H7OjiJ+YaIQpr78Ma/+h0bZtJ+EECJNBoBCgUGw0tJyYBEmhoAohFhBB0xie636N665x4tTJ+6n6p1jncuW+9s8pY/Hp0jzMCEB1ioqMkqkMHeeWl51z9kWkLa2FHFYsQa7ZUVFTI+QueYxqRCYwEFvygTJv8qEzReLtvNBED1jQkfUyZ+Ii5hg+4jlFw73mzpkuwJn2EtUHGdLlpx0dBYaGr3kld01Y0ohEJM05Ln9PNXKrWPgjiQErK6TNmXcgwHqKCMVkFp6cCQbpIXe0Q0k6Lo3tfWCgj20XUao6IiJCi4mq3vL/rqemZymyTjIkfIV27dJFfVWAjmca69WtNzBMSIIEGJ0Ch2OBIOSEJkEBjEYCL2QpBew8IR2yZg2Kzn+21QI579h80ohCiCMKruKTYxAZ+9OkXdYbHqxsWWbjOEhHR1nlq6siE7qs/W7ftcl07czbNxDaiATF/G7f8LGkqgpylnQqqJ+bOkFWf/NvEJUIQzZ422dXF/l5tNBQVlwjiGWEttAXuZlgS76QU67yIjeyjLmUw+VYtnJ7KDI0TRAayM37QUz8kCMVpXCVc5rZ006xsbCeE4u86rJoXLl2S1PQM0799+0gTDwlXNwsJkEDjE2CMYuMz5h1IgAQaiIC1KEIwQiDiBwUWRvxYIVmfGEXEGSIJZM70KcYdmp6RbTJxkciCAhfp8mVLjUBMzciQ+JHDTBwiriFRJFZFj3vJUREEUYkkE1uGDh4oWRoDiQIr42i9jng7FLivHxqfIB3uu89spwNrJ0rf3r3M0dMHRC0Sa+5r395cxnqReILnudMCK+EDGg8Ji6YVdIhVxFY4KA+MHW2ebYNy81cOHjmm8ZKDBFv2oMDVjOc9eKQ6ntTfdTCeMXmSy6WOZzx6Itlsa+Tv3rxOAiRw5wRoUbxzhpyBBEigiQhYIYhYRFsgFu2WOLdjUcQ8iPNLUeE1Y8pEk+EM9/CzSxZqlnCZVFZVu3ThAk7WGMIe3bvLGyteNK7Pq5rEkZmVbZfiOsItikzppU8tNAkesEIiXhCCFAXJKEiK+c83Vphsa1gY13z7vVRoPCCyq7HdDFzHTleza/LfKrCwJcKauvwFk0wC0bl2wyb3brd1nnLqrGBPyF2anYyCLXFmTpkkG5QBYhZnq6iGmP2PV14y1/GB9Vv3uatRK3Axf6XXntQ4Q4hYsNh34JDZaxL9/F0/lHRMs8BnyOvKHO5w7Fm57ucdzluwTgIk0IgEgmJiRwa6qb5ZRuG1GjfH7awrLi7udoZxDAmQQDMScLo8sQznua3j6KzH9qoRc421dGQ6o9hsZ9SrXdOjpCF+pR9EjTNGEPOjhKhgCQkNCeg3rmAOCEDEELoXa1FErKOzwIp5U0UZttXxVxAriC1rGjvBA5td2+/X35q8XffG0/b3dR0iEc/qiaMdzyMJkMDtEcjJTKrZvkv/ruPvOwqOFIq3x5SjSOCeIuAuEJznto6js94UQvGe+hL4sCRAAiTQSAR8CUXGKDYSdE5LAiRAAiRAAiRAAq2dAIVia/8GuX4SIAESIAESIAESaCQCFIqNBJbTkgAJkAAJkAAJkEBrJ0Ch2Nq/Qa6fBEiABEiABEiABBqJAIViI4HltCRAAiRAAiRAAiTQ2glQKLb2b5DrJwESIAESIAESIIFGIkCh2EhgOS0JkAAJkAAJkAAJtHYCFIqt/Rvk+kmABEiABEiABEigkQhQKDYSWE5LAiRAAiRAAiRAAq2dAIVia/8GuX4SIAESIAESIAESaCQCoY00L6clARIggUYjgN/x/NqKZR7nP3DoqLzz/mqP19hIAiRAAiRQPwIUivXjxd4kQAIthMC7q1ZL4sGjtVZjBeTrLy9rMrE44aHxcvpsqlzJvSqdO3WU6wUFcvPmrVrrCuQkSDuFtmmjY2967R4aGiqVFRVSqb9Xu7kK1hkWHiZlZeU+l9CmDdZaKRWVlT778SIJkEDLJkCh2LK/H66OBEjAAwF3gejsAgE5LiFefInFLp07yat/WCZ5eflSpaKrQgXN/oOH5fDR486pAqr369NLLl66bITinBlTZc/+A3I2Nd3n2L46ZtqkCbLqn5+Zfg8/MFYefmCcFBYWSrkKxX0HDsvJ02ddcwwZNEAem/CQEYihISFSUloqm7b8IjlXck2f8QmjZe7MqfKBzpd94aJr3P/5j1f0Hv/WeYtcbXdSSRg9UqZOnGDuHxwcLF99971cupxTa8qItm3lyQVzpW14uISFhUlGVrZs+vFnl7htHxkpLz67pNaY6KgOsvmnbXLwSG3hX6sTT0iABJqFAIVis2DnTUmABG6HACyGKFYo4tzW7XzWJY1rvlzQEE9vv/+xGda2bbiseOFZI7zOX7xkp6r3cfXnX9V7TI/74yR+xDB5651VKlgrpF27CPn9c89IRma2lN64IePGxAuE4qdffCPFJSVm/u5x3eSZxU/Imm/Xq1C7YtogGmdOe0w+XP15vdcQyIDYLp1V3D4q//uPj8y6IBofnzXNiFPn+GmTH5Ws8xdl+649Auvj0iWLJH7UcDmcVC3Ci4qLXdwxLiysjfzn6y/LiZOnndOwTgIk0EIIUCi2kC+CyyABEvBPAJZCiD+nQHTWIRoTD75pJoJFMdBy40aZFBQUSqeOMQKhCBfy/NkzBOLo8pUrsmHzT5J79ZqZbvDA/jJ98kQJV2tZ0vFkbYMcqi4L5802gghWNPQZEz/SuJI3/rjVuKdtP+exXUSEFKhohUhEKSkplX98/Klx28IiB+G18v1PXCIRfS7oGiHEZk+fIh//60s0SboKS1jmhg0ZJMn1FF2wikKQfrl2vZkLH889vUi2bt/lEqKwIK7fvMWIRFy/cuWqhKmr3L1UVlbJrVvVrnc4yENDQ+SWD1f80EEDjdXxhopiFhIggZZHgFnPLe874YpIgAT8EHC3Ivrp7vNyiLpyBw3oJz17dJfM8xcE588/s1iOnkiRv779nhGDSxbOk+CgICMk582eLj9t2ykrP/hEKjX+rnfP+13zR7Zrp8IoVHre31369Oohf1v5vrpnNwjG1MhJV3dTSc/MkpjoKHl2yUIZO3qUdIyJMTGOiO3rooK1qKhYCovquo4xrlvX2FqTbfllh0xVlzaeoT4lM/uC9OvTWyBaUTrc1166dukil3+zVqINLmanO3xA/z6Smp6BS7XK7n2JMnzoYHWFT5OlTy2U0tIbkuJwo9fqrCewplYLbvcrPCcBEmgJBCgUW8K3wDWQAAkERGBcQrXrGVZEW2BlvJ0S1eE+efNPb8hf/vxHY/2DNS0//7oRTLAwHks+KUFBwcY611bj7mJiomXMqBFy5lyanDpzTtBnx+59Riy63z84JFhggYtQl3a2umHfWrlKvKWflJffNBbEU2dS9d69ZPkLS+V3Ty4wYi8ysp25j/v8OIdbGlZNCFNbYPVMy8iUB8aOtk0BHWEBPJuWLrCWogweOMCIO29rhsUVAm/X3sQ680dHRQniKGEhzMvPF3Bu3z6yTj80GEEa28Uw9diBjSRAAs1OoOYN0+xL4QJIgARIwDcBbH1jixWLBw4l2aZ6Ha+rqxlxgcha7tE9ziVWYN2L6tBBXnnpOdd8yESGtbCjikVkONsCd/H5C3VjGjPVDZyWkaUJMy+oK7lE9iQelENHjtlhdY7IkkYiB34g/J5DXN/IYZKZdV4FalSd/mjAGhFnad28ttO2nXvM2o8cO2GbAjrCXQ3xh4QexETu2L3X47iIiLYmPnL9pi1SXFwdM+nsOHPqJOOizlIrJcqD4xLkUWUM9717GTl8qCSfOu1yu7tf5zkJkEDzE6BQbP7vgCsgARIIkABEoTMm0VkPcIo63fbsP2iEFcQRXKvFJcWSk5srH336RZ2+EFKIG3QWCCf3EqRu6q3qnoaLum/vniqsFkhaepaxsKFvGxWDdtsYCNU8tWTauEIIP1gFo1UIHsk7oUKwQvr37S3n0mq7eYdrLCL6uRckvBxQwTn50YfdL/k8P3MuVebNmm6sfLAYQqS6F4hYWDt37d1fZz3oCytqV3WHX86pzsZG2xVlOWr4EFTrFPCE4GQhARJouQToem653w1XRgIk4EagOlmlxqrYELGKiDNcp2JljiaGhOuWLukZ2YLtc5DIgoK25cuWGoGYmpFhLH3W3dunV0+JVdepe+mr8X5PaVwjtt5JTc80ArGiomZvRYjHa9fyzTC4ix8eP1aw7yAK5h6oMZPIHMbaEHeIGEe7HvSBcMSWOL/s3I3TOgXiF3GX2Kom0AKrJoQnYgshGrH2mOhoY13EHIixXKTJOimnzkjSMSTx1BQ8T1y3rma9lzWWceSwamGIMUiusZnkth9GxnWL1WcN0eestjzWzMYaCZBASyJAi2JL+ja4FhIggYAIWLdzQwhF3BBZxEi4mDFlonGRfrNuo0kuKS0t0/3/KmVv4iEpLy+X5JTT6qbuLm+seNEkmVzNy1PLW3adNadqvB+saHBfw3KIfRWR2YykGIhQWN7+vWatGYd4R4jA13Rfx+LiUkFc4pGjJ4xYQ4cTKadM5vTi+XM0ZjLIjMUWM598tkbyrxfUuTcaYJWECxpZ2PUpcAM/tWCe2G1+Bvbva+IyYWmd8tgEGTJ4oCbQdFGRWh0Xiv0nV676xIhWuPKxn+TXym7h47NNH4hebNvz3cYfzDIgbm0/WBOPHk+pz/LYlwRIoBkIBMXEjvQWr+xxOYXX7uwvdlxcnMd52UgCJNByCcC65CzOc1vH0VmP7XV7SSbO+3irQyj6S2JB4svy16u3yvE2j792uJkhEN1LiAq9ELWGIRHFV0H2cZUKRfubVDAOv9UEmcCeCpJmyjQJpDbtmp4QXpjPuq1rrjReDeLUfq/e7gLLofuasT8ihKTd9gdjPfXzNifbSYAEmo5ATmaS+Y8o7oi/8/ixdVoUDQp+kAAJtCYC7i7oxlq7J5GIe0GoVZT7/9V0TpFkx3kTibjuby9B98QVjGns4k8k4v7uIhFtnkS0p37oy0ICJNByCTBGseV+N1wZCZAACZAACZAACTQrAQrFZsXPm5MACZAACZAACZBAyyVAodhyvxuujARIgARIgARIgASalQCFYrPi581JgARIgARIgARIoOUSoFBsud8NV0YCJEACJEACJEACzUqAQrFZ8fPmJEACJEACJEACJNByCVAottzvhisjARIgARIgARIggWYlQKHYrPh5cxIgARIgARIgARJouQQoFFvud8OVkQAJkAAJkAAJkECzEqBQbFb8vDkJkAAJkAAJkAAJtFwC/BV+Lfe74cpIgAT8EMDvfH5txTI5cOio/iQJfrUfCwmQAAmQQMMRoEWx4VhyJhIggSYiAIH4wTv/JeMS4mX562/KO++vNvXXX17WRCuouc2Eh8ZLl86dTEPnTh2lTZvb///3E3NnSkhISM3kraQWEhwc0HODDfqykAAJtB4Ct/9Gaz3PyJWSAAncRQQgBscljJJ3V62uZUGEWESxYtGee3p0CLtX/7BM8vLypaqqSioqKmX/wcNy+OhxT919tvXr00suXrosV3KvypwZU2XP/gNyNjXd4xjc95XfPy9Xr14zgjA4OEi27dwjx5JPmv4jhw2RTVt+1vV4HN7iGoODgmTurGkyaEB/XXOFXMvLkzXfbpAbN8pqrTWibVt5csFcaRseLmFhYZKRlS2bfvxZKpW9p2I57Us8JD9t2+mpC9tIgASaiACFYhOB5m1IgATunIAVibAieisQiOgHi6OvfoWFRfL2+x+badq2DZcVLzwrOVdy5fzFS96m9tu++vOv/Pa5fr1A3v2wWtR26hgjr/5+mZw+lyplZeV+x7a0DgmjR0lMdJT8beX7UlVZKYvmzxFYWLdu21VrqdMmPypZ5y/K9l17JEivLF2ySOJHDZfDSZ6F+Ywpk+REyqlac/CEBEigeQhQKDYPd96VBEjgNghYK6E3q6EVkrA22r6B3AYWsIKCQoFwg1CEC3n+7BkS26WzXL5yRTZs/kly1QqIMnhgf5k+eaKEq2Us6XiytkD6VJeF82Yb8QOLGfqMiR8pN2/elI0/bpXTZ1NtN9fxut4TFs1gD+7YaBVg89RaF9e1qxQUFsqWX3ZIanqmGQsX7qxpk9WS109u3bql1tAjsletbyhPLnhcsrIvyBgVYpHt2smPP2837dOnTFT3cJhs0fMjx06YNl8fkx55UG6plXD3vgOmG8T07597Rt776FOpVFGIUlRcbNZlz6/kXpP27duZa86Pysoqs060wYYYGhoit27ecnZx1YcMGqCWyXwpKSkx1kfXBVZIgASahQCDRZoFO29KAiRwuwQQn2hFIKyGEIdowxEJLbAi1iepBTGBEFw9e3SXzPMXjEv4+WcWy9ETKfLXt98zYnDJwnkCNyuE5LzZ0407dOUHnxjB1Lvn/a5HgTALDQ2Vnvd3lz69ehhL21ffbTBjrJxs06aN9OvTW4YOHigLHp9lRFtp6Q3XHKggju/5p3UNx1Pkv//+rqzftEUWzpsjHWNiTL+5M6YZgfnWOx/IB6s/lxFDB0v8yGHmWmS7CCNm//nZV/Llt+tl3pwZ5tq7H34qX3zznXGPYw3+SkbWeRk1fKir28D+/SRH3etWFOLCydNn5dLlK64+A/r1cYlZV6NWdu9LlOG6xrkzp8nSpxYKnjdFx7oXfBeTJjwk23/d436J5yRAAs1EgEKxmcDztiRAArdHACLQWhSdrmWIRyS3QDxCOPorUR3ukzf/9Ib85c9/NNa/L9eul/z860bEwcKIuMGgoGBJPnla2mqMXUxMtFrpRsiZc2ly6sw5E4e3Y/e+WsLJ3jM4JNhYCSPUCpetLte3Vq4yljRcDw8PM8INwgmCsqyszIhLOxbHvhr3CGsdxCosjhc0BvJw0jFJiB9hkkaGDx1kLIWICywuLpGt23fJ+DHxrikSDx2R0hs3zL3h6k5UAX1DzzNV/ME62VGfxV/JzD4v7VT4wrWMMkQtqWDhrYxWCyZEpCfLaXRUlISqCMQa8vLzBezbt4+sM9UjD4wzLmd34VynIxtIgASajABdz02GmjciARJoKAIQhRCLVjBiXmtRtNZGf/eC2/etd1aZmLoe3eOMAMQYCKOoDh3klZeec00B9zGshRBYTiEEoXb+Qt2YxszMbEnLyNKEmReMC3VP4kE5dOSYma+oqFjWrt/kmvvFpUtkqLpbbUILLuA+V6/lufqgAtc3rJAx0dFSqHPcdLhuc6/mqZCttjairzOZBHX38zZq9fRXIFBPnj4jcAXDtd27Zw/59vvNHofdr/weU0vgh6u/MMLWvdPMqZNk/eYtxiWOaw+OS5BHNZYRLn1bBABj3AAABsNJREFU7mvfXkYOH2Jc27aNRxIggeYn4P9t0fxr5ApIgARIoA4Bm/kMKyIK3M6o18ftjHF79h80ohCCCK7U4pJidbHmykeffoHLtUr8iGF14uYiItrW6oOTIHVTb9VsXWTs9u3dU55ZvEDS0rPq9EMDLHfdusbWEopFaiUc3a1rrf6RkZFGIEJoIn4RVk5Y6FAiI9tJUVFRrf4NcXJCLYjTJj2qIjXPZCo7xamdH8J6kcZmfv71Ol1f3TUg/rKrPt/lnFw7RDPEc9WtPcR1jsrUSROMlfFVzQpHaacudFh0ERvpFJTmIj9IgASajABdz02GmjciARJoSAJwO0MYQjBWH+NdsYv1uQ/cpes0BnDO9CnqFg6X9Ixssy8iEllQ0LZ82VIjEFMzMozbGHGIKH169ZTY2C6m7vzoqzGIT2lcI6xySECBu7Wiom7yBuYeqPGR2FrHWdJ0DKyasOKhwF0Nt3PKqTNSUloqWepCHjdmlImbROzjQ+MTJFmvNXSBqzo6uoO5F+6NAosmRDUKtr15etF8+e77H1QI1sQq4hoEcpyKXfC9fDlHsPUPCtY7bMggV3b5KBXfELo/bd8p72k2+L++/Mb8JB1LVlf3Kfl5x69mHD9IgASahwAtis3DnXclARJoAAKwIlpXcyBxid5ueUEznZFcMUMzg2G9+mbdRnl2CZIuynSvv0qTUVxeXi7JKaelR/fu8saKF9WCVyxXdd/ATM1wdi+paenGYgb3dYUKJeyrWKDb8XRRYRgV1UFe0z0cYXXEvoKw2lVnT9fMgvjCNRoziQ24kdWMJA/s85ieWW2VXKsu4IWaCDN29EgpL79pYhF/3ZtYM0ED1SB0EY85euRw+Xrd92bWgf37mljNU8rrd08tMLGbC+fNct0xM+uCfLfxBxmfMFrg3scek18rz4WPz9a2eBOPiW2I0AcJQjN1K5wNyhbWXGdB7CbuX1JS6mxmnQRIoIkJBMXEjvS846mXhRReS/FyJbDmuLi4wDqyFwmQQIshgH+wncV5bus4OuuxvWqSK5xjG7IOceh0PdfX7exvLdgcGgLRvSArOUS3eIFI81Ug8LC/oLeNpX2NtddgTfS2xyK2ycFm4c5MZDuuMY8Qufa79nYfWA5r/6kRtcq2MetFbKctgcxl+/JIAiTQOARyMpPMf14xO/5O4sfWaVE0KPhBAiRQHwLe/nH31l6fuevTF8KwocWh8/6eRCKuw0pYUV69l6Czv3vdKYjcrwV67k0kYrynmMFA572Tfv5EIuZ2F4lo8ySsA5kLY1lIgAQan4AViM47MUbRSYN1EiABEiABEiABEiABFwEKRRcKVkiABEiABEiABEiABJwEKBSdNFgnARIgARIgARIgARJwEaBQdKFghQRIgARIgARIgARIwEmAQtFJg3USIAESIAESIAESIAEXAQpFFwpWSIAEGoqAp8y5hpqb85AACZAACTQsAV/vbArFhmXN2UjgriTg6yVyVz4wH4oESIAESMAQoFDkHwQSIIE7ImBFpD3e0WQcTAIkQAIk0KwE7LvcHikUm/Xr4M1J4O4jYF8ud9+T8YlIgARI4O4l4O3dTaF4937nfDISaFQC3l4q9qZV+juSWUiABEiABFo2AX/vagrFlv39cXUk0KoIWPGIY/mNwla1di6WBEiABO5FAnhXO9/d7gwoFN2J8JwESKDeBOxLxjmwpCBH/P1P1dmfdRIgARIggaYlgHc03tXuxflOp1B0p8NzEiABjwScLw6PHX5rtP0qbt6Q/JxzUlZ6nYLRFzBeIwESIIEmJgCBiHcz3tF4V6PYd7f7UkLdG3hOAiRAAoESwIulqqrKdHfW7Xi8gApyM8yp7YcTZ9329dRmr/FIAiRAAiQQOAFPos/ZZuv26JzZ2YY6haKTDuskQAINQgAvFyv8bN2+fNBu67iZs1+D3JyTkAAJkAAJGALOdy0anOfe6u7oKBTdifCcBEjAKwG8WKyws52cbYHWMdbO43xZ2Tnt0fax5zySAAmQAAnUJuDrHWp7uvdxnvurUyhaijySAAncNgG8aKyo81XHDZz97A1tmz23R+cLzLbxSAIkQAIk4J+Ap/ene5vz3FudQtE/a/YgARJwEMDLxJuws92cfezLx46x5+jrqc3OwSMJkAAJkMCdE3C+c+1s7m3u57YfjhSKThqskwAJ3DYBvGis8MMkns7R7t4HbZ6Ks5+n62wjARIgARKoJuBL6DkZeern3uZ+TqHoJMg6CZBAQATwIvEk5Nzb7QvH2de24UbOdvcbO/u5X+M5CZAACZBAYAS8vUs9tXtq+/9ZurTi1zD5YQAAAABJRU5ErkJggg==" - }, - "image.png": { - "image/png": "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epXyBZCXS0IAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIFIAaZ1ihThMwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCOxUAYITO5WXgyOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggECkAMGJSBE+I4AAAggggAACCCCAAAIIIIAAAggggAACCCCAwE4VIDixU3k5OAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCEQKEJyIFOEzAggggAACCCCAAAIIIIAAAggggAACCCCAAAII7FQBghM7lZeDI4AAAggggAACCCCAAAIIIIAAAggggAACCCCAQKQAwYlIET4jgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIDAThUgOLFTeTk4AggggAACCCCAAAIIIIAAAggggAACCCCAAAIIRAoQnIgU4TMCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgjsVAGCEzuVl4MjgAACCCCAAAIIIIAAAggggAACCCCAAAIIIIBApADBiUgRPiOAAAIIIIAAAggggAACCCCAAAIIIIAAAggggMBOFSA4sVN5OTgCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAghEChCciBThMwIIIIAAAggggAACCCCAAAL/Z+8s4KM42jD+YgECwV2Du7u7u7u7O21xaKEU+XB3d3f3IoXiUtzdJZAg/eaZY4+74y45IjQhz9vfZXdnZ2dn/3vldl8lARIgARIgARIgARIggQAlQONEgOLl4CRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArYEaJywJcJtEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBACVSNIweAABAAElEQVRA40SA4uXgJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACtgRonLAlwm0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIEAJUDjRIDi5eAkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAK2BGicsCXCbRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggQAlQONEgOLl4CRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArYEaJywJcJtEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBACVA40SA4uXgJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACtgRonLAlwm0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIEAJUDjRIDi5eAkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAK2BGicsCXCbRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggQAlQONEgOLl4CRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArYEaJywJcJtEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBACVA40SA4uXgJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACtgRonLAlwm0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIEAJUDjRIDi5eAkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAK2BGicsCXCbRIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggQAlQONEgOLl4CRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAArYEaJywJcJtEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiCBACVA40SA4uXgJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACtgRonLAlwm0SIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIEAJUDjRIDi5eAkQAIkQAIkQAIkQAIkQAIkQAIkQAL3H70gBBIgARIgARIgARKwIkDjhBUObpAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACQQ0ARonApowxycBEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABErAiQOOEFQ5ukAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJBDSBH8o48f79B8HHO/nw4aN4enl518VP+zC+T3Pw0wl4sBw68reMmTDNTALblmK5bbtueZzlMX5Z//jpk+C+2wraPnz8ZNustz99+lfe2znG6Ozp9V7Qx1LQ/9a9J/LqzTvLZq6TAAmQAAmQAAmQAAmQAAmQAAkEEAG8173z9DR/vNS7mn/J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EVQBY9WnbPWmurD25pWzJX7c2LpbCAmh/pEPZRzCpTMEEDXR5V9TTxgd8FlWxGSwMFI2YYkP2rEfxghETBgGDN9EXqgzIrcj6j7ULIsQDPsCDwZ4IGxTqZoMQW0JSJmC1g8GaMuRManAiJE2eXyJrDwbLKVf+yqSK3MyWbrxsPQYukh6/rFYFq09KEjxNGd4K0FNCwoJkAAJkAAJkAAJkAAJkAAJkMD3JVC/ZmXtCNlr0Ah94jbN6svYYf1krEornSJLEUmfu7SgkHbh/KZ3x17d2kqnNk1kzKRZkq1QRdmwZZdMGKHeVS0E+gFDELGwc++fkipbcYmaKLNUrddGH1+q6Bedg9HXWELPUKtqOb3ZrGEto1kvfdKB2NNN+DQHS72Js/oPq0l93rCs3WlvP9tMBC7feCDHz12XOhXyiKsyGtiTC1fvyWkV9eBILL9j6PPx40e5popmX7n5UB+CbOb9O1SR1MniyRBVH/Pn4Uu0rmxwtxoSKWJ4R8OynQRIgAR8TSDEyzcen7W8vhvDzTXo/+OE/IuoAwGPBt8I6lXAc8I7IwMKYH369K/u55tz8BhvCNzerawG6mMpCQubtgxjhOW+ILqOAlSeyugRPUrEIHoFnDYJkAAJkAAJkAAJkAAJkEBwJXD/0QuJE9Ox1/+PxAV1IVCT0lJ5b1wflMEeb9/ptEtGm3dL9H31+rWgXoWt06V3x3m371t1IN86B+o/vKMfdPZ9UAXg36vvK50ig84940xJICgSoHEiKN41zpkESIAESIAESIAESIAESIAESIAEghCB4GScCEK3hVMlARIgARIggf+UgHWuo/90Kjw5CZAACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAcCBA40RwuMu8RhIgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIRARonAhEN4NTIQESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIHgQIDGieBwl3mNJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACJBCICNA4EYhuBqdCAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAsGBAI0TweEu8xpJgARIgARIgARIgARIgARIgARIgARIgARIgARIgARIIBARoHEiEN0MToUESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEggMBGieCw13mNZIACZAACZAACZAACZAACZAACZAACZAACZAACZAACZBAICJA40QguhmcCgmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAkEBwI0TgSHu8xrJAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIIFARIDGiUB0MzgVEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEggOBGicCA53mddIAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAoGIAI0TgehmcCokQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkEBwI0DgRHO4yr5EESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEAhEBGicC0c3gVEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEggOBCgcSI43GVeIwmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAmQAAkEIgI0TgSim8GpkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkAAJkEBwIEDjRHC4y7xGEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEghEBGicCEQ3g1MhARIgARIgARIgARIgARIgARIgARIgARIgARIgARIggeBAgMaJ4HCXeY0kQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkQAIkEIgI0DgRiG4Gp0ICJEACJEACJEACJEACJEACJEACJEACJEACJEACJEACwYFA6OBwkbzGH4vAvUcv5Pb9Z/LitYd8+vSvv15cyJAhJHJEV0kQJ6rEjRnZX8fmYCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiRAAiYCNE7wmxCkCPxz/b6cPn1NDuw8KieOX5QQIULIa2WkcHUNL2/fvpNQoULKx4+fxMUljLS8/5eE+/Thm64vVLhwEipXdrlUoZK8zJpeUrnH+abj2ZkESIAESIAESIAESIAESIAESIAESIAESIAESIAESMBnAjRO+MyIPQIJAURMnD17XVYt2iZv33lKuHBhJUWKhHLy1CVJmTKR3Lx1Xxsl3nu9l4gq+iFNxcYSwSWUr2Yf8u51eRkrhtyLEJ4RFL4iyINIgARIgARIgARIgARIgARIgARIgARIgARIgARIwDEBGicc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PLY2Po7tzbVXvrJ/J0CAAIFmgcpxorlwtxMgQIAAAQIECBAgQIAAgVkLGCdmLe79CBAgQIBAvsDLf2gw/yYJCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAgWAB40RwOaIRIECAAAECBAgQIECAAAECBAgQIECAAIF5FDBOzGOrbiJAgAABAgQIECBAgAABAkECS4sLQWlEIUCAAAECBBIEjBMJLchAgAABAgQIECBAgAABAgQIECBAgAABAgSKBIwTRWU7lQABAgQIECBAgAABAgQIECBAgAABAgQIJAgYJxJakIEAAQIECBAgQIAAAQIECBAgQIAAAQIECBQJGCeKynYqAQIECBAgQIAAAQIECBAgQIAAAQIECBBIEDBOJLQgAwECBAgQIECAAAECBAgQIECAAAECBAgQKBIwThSV7VQCBAgQIECAAAECBAgQIECAAAECBAgQIJAgYJxIaEEGAgQIECBAgAABAgQIECBAgAABAgQIECBQJGCcKCrbqQQIECBAgAABAgQIECBAgAABAgQIECBAIEHAOJHQggwECBAgQIAAAQIECBAgQIAAAQIECBAgQKBIwDhRVLZTCRAgQIAAAQIECBAgQIAAAQIECBAgQIBAgoBxIqEFGQgQIECAAAECBAgQIECAAAECBAgQIECAQJGAcaKobKcSIECAAAECBAgQIECAAAECBAgQIECAAIEEAeNEQgsyECBAgAABAgQIECBAgAABAgQIECBAgACBIgHjRFHZTiVAgAABAgQIECBAgAABAgQIECBAgAABAgkCxomEFmQgQIAAAQIECBAgQIAAAQIECBAgQIAAAQJFAsaJorKdSoAAAQIECBAgQIAAAQIECBAgQIAAAQIEEgSMEwktyECAAAECBAgQIECAAAECBAgQIECAAAECBIoEjBNFZTuVAAECBAgQIECAAAECBAgQIECAAAECBAgkCBgnElqQgQABAgQIECBAgAABAgQIECBAgAABAgQIFAkYJ4rKdioBAgQIECBAgAABAgQIECBAgAABAgQIEEgQME4ktCADAQIECBAgQIAAAQIECBAgQIAAAQIECBAoEjBOFJXtVAIECBAgQIAAAQIECBAgQIAAAQIECBAgkCBgnEhoQQYCBAgQIECAAAECBAgQIECAAAECBAgQIFAkYJwoKtupBAgQIECAAAECBAgQIECAAAECBAgQIEAgQcA4kdCCDAQIECBAgAABAgQIECBAgAABAgQIECBAoEjAOFFUtlMJECBAgAABAgQIECBAgAABAgQIECBAgECCgHEioQUZCBAgQIAAAQIECBAgQIAAAQIECBAgQIBAkYBxoqhspxIgQIAAAQIECBAgQIAAAQIECBAgQIAAgQQB40RCCzIQIECAAAECBAgQIECAAAECBAgQIECAAIEiAeNEUdlOJUCAAAECBAgQIECAAAECBAgQIECAAAECCQLGiYQWZCBAgAABAgQIECBAgAABAgQIECBAgAABAkUCxomisp1KgAABAgQIECBAgAABAgQIECBAgAABAgQSBIwTCS3IQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEigSME0VlO5UAAQIECBAgQIAAAQIECBAgQIAAAQIECCQIfEgIMWW4ufufEkUOAgQIECBAgAABAgQIECBAgAABAgQIECBA4A0FYsaJpcWFNzzTSxMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIpAn7WKaUJOQgQIECAAAECBAgQIECAAAECBAgQIECAQImAcaKkaGcSIECAAAECBAgQIECAAAECBAgQIECAAIEUAeNEShNyECBAgAABAgQIECBAgAABAgQIECBAgACBEgHjREnRziRAgAABAgQIECBAgAABAgQIECBAgAABAikCxomUJuQgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIlAsaJkqKdSYAAAQIECBAgQIAAAQIECBAgQIAAAQIEUgSMEylNyEGAAAECBAgQIECAAAECBAgQIECAAAECBEoEjBMlRTuTAAECBAgQIECAAAECBAgQIECAAAECBAikCBgnUpqQgwABAgQIECBAgAABAgQIECBAgAABAgQIlAgYJ0qKdiYBAgQIECBAgAABAgQIECBAgAABAgQIEEgRME6kNCEHAQIECBAgQIAAAQIECBAgQIAAAQIECBAoETBOlBTtTAIECBAgQIAAAQIECBAgQIAAAQIECBAgkCJgnEhpQg4CBAgQIECAAAECBAgQIECAAAECBAgQIFAiYJwoKdqZBAgQIECAAAECBAgQIECAAAECBAgQIEAgRcA4kdKEHAQIECBAgAABAgQIECBAgAABAgQIECBAoETAOFFStDMJECBAgAABAgQIECBAgAABAgQIECBAgECKgHEipQk5CBAgQIAAAQIECBAgQIAAAQIECBAgQIBAiYBxoqRoZxIgQIAAAQIECBAgQIAAAQIECBAgQIAAgRQB40RKE3IQIECAAAECBAgQIECAAAECBAgQIECAAIESgXumrFovOTRS3gAAAABJRU5ErkJggg==" - } - }, - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ "## Check Redis Version\n", "\n", @@ -187,10 +174,10 @@ ] }, { - "cell_type": "code", - "execution_count": 5, "metadata": {}, + "cell_type": "code", "outputs": [], + "execution_count": null, "source": [ "import os\n", "\n", @@ -725,41 +712,10 @@ ] }, { - "cell_type": "code", - "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'\\n# NBVAL_SKIP\\n%%sh\\ndocker run -d --name redis -p 6379:6379 redis:8.0-M03\\n'" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# NBVAL_SKIP\n", - "%%sh\n", - "docker run -d --name redis -p 6379:6379 redis:8.0-M03" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "assert redisvl.__version__ >= '0.4.0'" - ] - }, - { "cell_type": "code", - "execution_count": 25, - "metadata": {}, "outputs": [], + "execution_count": null, "source": [ "int_hf = HFTextVectorizer(model=\"sentence-transformers/all-MiniLM-L6-v2\", dtype='int8')\n", "\n", @@ -767,24 +723,11 @@ ] }, { - "cell_type": "code", - "execution_count": 26, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "embeddings_int8[0]" - ] + "cell_type": "code", + "outputs": [], + "execution_count": null, + "source": "embeddings_int8[0]" }, { "cell_type": "markdown", @@ -817,8 +760,8 @@ "Requirement already satisfied: joblib>=1.2.0 in /Users/justin.cechmanek/.pyenv/versions/3.11.9/envs/redis-ai-res/lib/python3.11/site-packages (from scikit-learn) (1.4.2)\n", "Requirement already satisfied: threadpoolctl>=3.1.0 in /Users/justin.cechmanek/.pyenv/versions/3.11.9/envs/redis-ai-res/lib/python3.11/site-packages (from scikit-learn) (3.5.0)\n", "\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.0.1\u001b[0m\n", - "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m24.0\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m25.0.1\u001B[0m\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\n" ] } ], From 45f81de68dd85f9b030664a35b29b91115dee234 Mon Sep 17 00:00:00 2001 From: Vishal Bala Date: Tue, 9 Dec 2025 18:14:44 +0100 Subject: [PATCH 3/6] Remove incorrect version comparison --- .../vector-search/03_dtype_support.ipynb | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/python-recipes/vector-search/03_dtype_support.ipynb b/python-recipes/vector-search/03_dtype_support.ipynb index 0f510280..6c80cf84 100644 --- a/python-recipes/vector-search/03_dtype_support.ipynb +++ b/python-recipes/vector-search/03_dtype_support.ipynb @@ -77,35 +77,12 @@ "Let's start with float16 and bfloat16 support" ] }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m24.0\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m25.0.1\u001B[0m\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\n", - "Note: you may need to restart the kernel to use updated packages.\n" - ] - } - ], - "source": [ - "%pip install -q \"redis>=5.0.8\" \"redisvl>=0.4.1\" numpy sentence-transformers" - ] - }, { "metadata": {}, "cell_type": "code", "outputs": [], "execution_count": null, - "source": [ - "import redisvl\n", - "assert redisvl.__version__ >= '0.3.4'" - ] + "source": "%pip install -q \"redis>=5.0.8\" \"redisvl>=0.4.1\" numpy sentence-transformers" }, { "metadata": {}, From 531606ad0001bfff7d89a00386fdf96ea6118705 Mon Sep 17 00:00:00 2001 From: Vishal Bala Date: Wed, 10 Dec 2025 17:54:30 +0100 Subject: [PATCH 4/6] Update hybrid search notebook to show FT.HYBRID usage --- .../vector-search/02_hybrid_search.ipynb | 2564 +++++++---------- 1 file changed, 962 insertions(+), 1602 deletions(-) diff --git a/python-recipes/vector-search/02_hybrid_search.ipynb b/python-recipes/vector-search/02_hybrid_search.ipynb index 5eaaec99..ec845dfc 100644 --- a/python-recipes/vector-search/02_hybrid_search.ipynb +++ b/python-recipes/vector-search/02_hybrid_search.ipynb @@ -9,11 +9,16 @@ "\n", "Hybrid search is all about combining lexical search with semantic vector search to improve result relevancy. This notebook will cover 3 different hybrid search strategies with Redis:\n", "\n", - "1. Linear combination of scores from lexical search (BM25) and vector search (Cosine Distance) with the AggregateHybridQuery class\n", - "2. Client-Side Reciprocal Rank Fusion (RRF)\n", + "1. Linear combination of scores from lexical search (BM25) and vector search (Cosine Distance)\n", + "2. Reciprocal Rank Fusion (RRF)\n", "3. Client-Side Reranking with a cross encoder model\n", "\n", - ">Note: Additional work is planed within Redis Query Engine core to add more flexible hybrid search capabilities in the future.\n", + "The Redis Query Engine supports a unified interface for hybrid search with the [FT.HYBRID](https://redis.io/docs/latest/commands/ft.hybrid) command introduced in Redis Open Source 8.4.0, prior to which hybrid searches were only possible using [the aggregations API](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/aggregations/). RedisVL added an interface for FT.HYBRID in 0.13.0 (via `HybridQuery`), and provided an interface for the aggregation approach for Redis prior to 8.4.0 (via `AggregateHybridQuery`). This notebook will demonstrate the usage of both approaches.\n", + "\n", + "## Requirements\n", + "- Redis 8.4.0+\n", + "- redisvl>=0.13.0\n", + "- redispy>=7.1.0\n", "\n", "## Let's Begin!\n", "\"Open\n" @@ -32,7 +37,8 @@ "metadata": {}, "outputs": [], "source": [ - "%pip install sentence-transformers pandas nltk \"redisvl>=0.11.0\"" + "from redis.commands.search.aggregation import Reducer\n", + "%pip install \"git+https://github.com/redis/redis-vl-python.git@feat/RAAE-1236/hybrid-search\" nltk pandas sentence-transformers" ] }, { @@ -116,6 +122,30 @@ "3. With docker: `docker run -d --name redis -p 6379:6379 redis:latest`" ] }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T14:17:05.530129Z", + "start_time": "2025-12-10T14:17:05.493208Z" + } + }, + "cell_type": "code", + "source": [ + "from packaging.version import Version\n", + "\n", + "from redis import __version__ as redis_version\n", + "from redisvl import __version__ as redisvl_version\n", + "\n", + "\n", + "if Version(redis_version) < Version(\"7.1.0\"):\n", + " raise RuntimeError(\"redis-py version must be >= 7.1.0\")\n", + "\n", + "if Version(redisvl_version) < Version(\"0.13.0\"):\n", + " raise RuntimeError(\"redisvl version must be >= 0.13.0\")" + ], + "outputs": [], + "execution_count": 1 + }, { "metadata": {}, "cell_type": "markdown", @@ -126,10 +156,13 @@ ] }, { - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T14:17:09.115687Z", + "start_time": "2025-12-10T14:17:09.106885Z" + } + }, "cell_type": "code", - "outputs": [], - "execution_count": null, "source": [ "import os\n", "import warnings\n", @@ -143,7 +176,9 @@ "\n", "# If SSL is enabled on the endpoint, use rediss:// as the URL prefix\n", "REDIS_URL = f\"redis://:{REDIS_PASSWORD}@{REDIS_HOST}:{REDIS_PORT}\"" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", @@ -154,347 +189,54 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T14:17:10.815899Z", + "start_time": "2025-12-10T14:17:10.700827Z" } - ], + }, "source": [ "from redis import Redis\n", + "from redisvl.redis.connection import RedisConnectionFactory\n", "\n", "client = Redis.from_url(REDIS_URL)\n", - "client.ping()" - ] + "client.ping()\n", + "\n", + "if Version(client.info()[\"redis_version\"]) < Version(\"8.4.0\"):\n", + " raise RuntimeError(\"Redis version must be >= 8.4.0\")\n", + "\n", + "installed_modules = RedisConnectionFactory.get_modules(client)\n", + "if \"search\" not in installed_modules:\n", + " raise RuntimeError(\"Redisearch module is not installed\")" + ], + "outputs": [], + "execution_count": 3 }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T14:17:30.917996Z", + "start_time": "2025-12-10T14:17:30.907177Z" + } + }, "source": [ "import json\n", "\n", "with open(\"resources/movies.json\", 'r') as file:\n", " movies = json.load(file)" - ] + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "19:18:27 sentence_transformers.SentenceTransformer INFO Load pretrained SentenceTransformer: sentence-transformers/all-MiniLM-L6-v2\n", - "19:18:27 sentence_transformers.SentenceTransformer INFO Use pytorch device_name: mps\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6f1ad2e22cde435fa05bcfe2d4de40ae", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00\\x17\\xbeA\\x1e\\x05\\xb9Hu\\xbfg3\\xbd$\\xcd\\xbd\\xbd\\xa1$\\xf7;\\x04\\xf5z=\\xfc\\xb4\\x8c=\\x89\\x0e\\xc6\\xbdhI\\x90\\xbd^\\x16\\xbd;z\\xe7\\x0c\\xbd\\x1b3\\xc9\\xbc\\x89\\xf8\\xbb\\xbc\\x18\\'u\\xbb>\\x8f\\xca<\\x02\\x80J=\\x0e\\xaf*=\\x8dOU\\xbd\\xcf\\xf0\\x95\\xbc \\x02\\x19=\\x19\\xf4K<\\xc5\\xc2\\t=J\\x83\\xac=\\x95\\xd7\\xb8\\xbd\\xf2\\xb5\\x9c\\xbd=\\x85\\x18=\\x94d&=03\\xf8<\\xee\\xf7\\x88<\\x80v\\xf2\\xbb9=[\\xbdG\\xac\\xee\\xbb<:A\\xbd\\xe1d\\x19\\xbd!d\\xf2\\xbb\\x1d\\xbax;\\xec;O<\\xd21,\\xbc\\xec\\xae\\xae=r\\x00-\\xbc\"\\x06\\xae\\xbdl\\xd6\\x1a=\\xc4\\xbf\\xcd=\\x19\\x150=\\xe3\\xf1\\x9d\\xbc\\xa6GK=\\xb2\\xb8 =\\xb2\\xf1I\\xbd-e\\x9e\\xbb\\xe9\\x8a\\xf7:\\x88\\xf8\\x1c=\\x7f\\xba\\xde<\\xd2n\\x16\\xbb\\xb4\\\\p\\xbb\\xd4\\xd5<<\\x89\\xa5\\xa3\\xb8\\xc79s<=4&<\\x84\\x1c\\x18<\\x18\\xd9-\\xbd\\xdf\\xe6\\x98<\\x15\\xa1N=\\xa2/\\xa5=\\x1d\\xf3\\xdd<\\x17L\\x13<\\x10\\x10\\xce\\xbac\\x9e\\xdc\\xbc\\xa68\\x05=+\\xa1\\xf5\\xbd\\x84\\x1bF\\xbd\\xa0?\\x14\\xbe\\xc4\\x8f(\\xbd\\xe6O\\x89\\xbd\\xf7\\xad\\xd4<\\xa7\\x12\\xc3=\\xaf\\x05O\\xbd\\x99\\x8ep\\xbc\\x18\\xb5\\xac\\xbc\\xc9\\x9ee\\xbdH\\x8es;$a\\xc1;\\xd9\\xfaB\\xbd\\xa8#\\xfe:\\x92\\xe6\\xf4=\\xcd\\x15*<\\x86\\xf8\\x1b=\\x01\\xfcV\\xbd\\xd3\\xd1\\r=9\\xee\\x06=\\x13u\\xba\\xbd\\xf7\\xa3\\xd6<\\x1a\\xec\\xd9;\\xb79/=\\xa4\\xc2\\x85=p\\x0b\"=\\xe1i\\xef<:\\xe8c=\\xfb2\\x08\\xbe\\xce\\x12;=OVW;V\\xa4b<\\xd0\\x9d\\xb7<\\x87r;\\xbdqz\\x91\\xbcV\\x00<\\xbd\\xfe\\x19\\xa3<\\xeaJ%\\xbc!\\xe7\\xbf\\xbb\\x7f\\x87\\x12=\\x94\\x1d\\x95=b|\\xfd\\xbc\\xf3\\xf1\\xd1\\xbd\\xf5y\\x84;\\xc9\\tu=]\\x8ai<3\\x91R\\xbd\\xec\\xf3m\\xbd\\x93\\xb83=V\\xedF=\\x1f\\xf3\\xd1\\x08yA\\xba<#\\xacO\\xbd\\x01\\x0f\\xc7;\\x7f\\xf4\\x04\\xbdP\\x82\\x92\\xbd\\x9b\\xddD=p\\xd8;\\xbc\\xd3;\\xf4\\xbc\\xb3\\x8f\\x97\\xbd1\\\\\\r\\xbd\\xea\\x8c\\xf5\\xbd\\x8c\\x13(=\\x9e\\xc8\\xc6=\\xa3\\xed\\x1a=\\x98\\xa8\\xf8=\\x84\\xc1\\xee\\xbc\\xcd-\\x18\\xbb\\xf5~;<\\xd6F\\t\\xbd\\x14\\x08\\x17=\\xa5\\xa5\\x1e=\\x14K\\xcb\\xbd.\\xf7\\x8c\\xbdyb\\xed\\xbb\\x86[\\x19\\xbc]\\x0c\\x13\\xbcgq\\x83=\\xf0wd\\xbd\\xe3\\xc7\\xd1\\xbb8lY\\xbc\\xa7|a=3\\xcf\\xfd\\xbc\\x1f\\xa5\\x83\\xbb\\x99O\\x19\\xbd6\\x02]\\xbd\\xbb\\xeaz=\\x036\\x9c=:^\\xa9\\xbd)^9\\xbcg\\xe4N\\xbcs\\x07x\\xbd\\x18{\\xa0=:\\x9f\\x96<\\xecq8\\xba\\x9e\\xbb=\\xbd\\xe4|(<\\x96\\xdf\\xb4\\xbbl\\xc9\\x0b\\xbd\\xc4\\x01\\x95\\xbd\\xf7\\xc6T=\\tp\\xd1\\x17\\xbee\\x15\\x05\\xb9Ou\\xbf<\\xc3\\xe2b\\xba\\xd2\\xa6\\xa8\\xbd\\x80\\xdc\\xec\\xbcMc%=\\xcf\\xe7r\\xbb\\x15OG=A(\\x85=e@\\xa2\\xbc.Z\\xd0\\xbdR%K\\xbd\\xdb\\xed\\x94\\xbcf\\xddH=|&F<\\xd9*\\xec<\\x8f\\xd8\\x8d\\xbd\\xb7Z\\x98<\\x10\\xa3\\xa3=Gg3\\xbd$\\xcd\\xbd\\xbd\\xba$\\xf7;\\x04\\xf5z=\\xfb\\xb4\\x8c=\\x8b\\x0e\\xc6\\xbdhI\\x90\\xbd\\x0f\\x16\\xbd;}\\xe7\\x0c\\xbd)3\\xc9\\xbc\\x8a\\xf8\\xbb\\xbc\\x94&u\\xbb.\\x8f\\xca<\\x03\\x80J=\\n\\xaf*=\\x8eOU\\xbd\\xcc\\xf0\\x95\\xbc\\x15\\x02\\x19=1\\xf4K<\\xc8\\xc2\\t=C\\x83\\xac=\\x9a\\xd7\\xb8\\xbd\\xf9\\xb5\\x9c\\xbdE\\x85\\x18=\\x9fd&=73\\xf8<\\xf1\\xf7\\x88<\\x0ev\\xf2\\xbb/=[\\xbd\\x9e\\xac\\xee\\xbb6:A\\xbd\\xe4d\\x19\\xbd#d\\xf2\\xbb\\xb1\\xb9x;\\xf1;O<\\xcf1,\\xbc\\xf1\\xae\\xae=p\\x00-\\xbc\\x12\\x06\\xae\\xbdg\\xd6\\x1a=\\xcc\\xbf\\xcd=!\\x150=\\xd9\\xf1\\x9d\\xbc\\xb4GK=\\xa9\\xb8 =\\xb0\\xf1I\\xbd[e\\x9e\\xbb\\x19\\x8b\\xf7:\\x8b\\xf8\\x1c=\\x94\\xba\\xde<\\x11p\\x16\\xbb\\xd5]p\\xbb\\xba\\xd5<<\\xc8\\x95\\xa3\\xb8\\xce9s<\\x184&\\xbd\\x7f\\x1bF\\xbd\\x9f?\\x14\\xbe\\xc3\\x8f(\\xbd\\xe0O\\x89\\xbd\\x0e\\xae\\xd4<\\xaa\\x12\\xc3=\\xb9\\x05O\\xbd\\x97\\x8ep\\xbc\\x14\\xb5\\xac\\xbc\\xc5\\x9ee\\xbd.\\x8es;Ca\\xc1;\\xd8\\xfaB\\xbd\\xe7#\\xfe:\\x99\\xe6\\xf4=\\xd7\\x15*<\\x81\\xf8\\x1b=\\xfd\\xfbV\\xbd\\xc6\\xd1\\r=6\\xee\\x06=\\x15u\\xba\\xbd\\xfd\\xa3\\xd6<\\x9e\\xeb\\xd9;\\xb89/=\\xa6\\xc2\\x85=x\\x0b\"=\\xd7i\\xef<<\\xe8c=\\xfb2\\x08\\xbe\\xd7\\x12;=\\xdeUW;@\\xa4b<\\xc8\\x9d\\xb7<\\x88r;\\xbdnz\\x91\\xbcR\\x00<\\xbd\\x17\\x1a\\xa3<\\xf0J%\\xbc\\x1d\\xe7\\xbf\\xbb~\\x87\\x12=\\x93\\x1d\\x95=\\x85|\\xfd\\xbc\\xf7\\xf1\\xd1\\xbd8z\\x84;\\xda\\tu=r\\x8ai<7\\x91R\\xbd\\xe2\\xf3m\\xbd\\x94\\xb83=Q\\xedF=-\\xf3\\xd1\\x08~A\\xba<\\x1f\\xacO\\xbd5\\x0f\\xc7;\\x83\\xf4\\x04\\xbdQ\\x82\\x92\\xbd\\xa7\\xddD=V\\xd8;\\xbc\\xcc;\\xf4\\xbc\\xb6\\x8f\\x97\\xbd:\\\\\\r\\xbd\\xe6\\x8c\\xf5\\xbd\\xa7\\x13(=\\x9f\\xc8\\xc6=\\xa2\\xed\\x1a=\\x97\\xa8\\xf8=\\x8f\\xc1\\xee\\xbc\\x80-\\x18\\xbb\\x00\\x7f;<\\xceF\\t\\xbd\\x0f\\x08\\x17=\\xa8\\xa5\\x1e=\\x16K\\xcb\\xbd8\\xf7\\x8c\\xbdwb\\xed\\xbb\\xc4[\\x19\\xbc\\x1a\\x0c\\x13\\xbccq\\x83=\\xfcwd\\xbdt\\xc7\\xd1\\xbbYlY\\xbc\\xa9|a=@\\xcf\\xfd\\xbcW\\xa5\\x83\\xbb\\xa5O\\x19\\xbd2\\x02]\\xbd\\xc2\\xeaz=\\x016\\x9c=4^\\xa9\\xbde^9\\xbco\\xe4N\\xbcu\\x07x\\xbd\\x1b{\\xa0=K\\x9f\\x96<\\xcdq8\\xba\\xa4\\xbb=\\xbd\\xe6|(<\\xbe\\xdf\\xb4\\xbbq\\xc9\\x0b\\xbd\\xc6\\x01\\x95\\xbd\\x00\\xc7T=\\x13p\\xd1\",\n", + " vector=,\n", + " vector_field_name=\"\",\n", + ")\n", + "```\n", + "\n", + "This defaults to using the reciprocal rank fusion (RRF) method to combine scores, and only outputs the final keys and combined scores. A more common minimal usage might be:\n", + "\n", + "```python\n", + "query = HybridQuery(\n", + " text=\"your query string here\",\n", + " text_field_name=\"\",\n", + " vector=,\n", + " vector_field_name=\"\",\n", + " combination_method=\"RRF\",\n", + " rrf_window=20,\n", + " yield_text_score_as=\"text_score\",\n", + " yield_vsim_score_as=\"vector_similarity\",\n", + " yield_combined_score_as=\"hybrid_score\",\n", + " return_fields=[\"\"],\n", + ")\n", + "```" ] }, { - "cell_type": "markdown", "metadata": {}, + "cell_type": "markdown", "source": [ - "## 1. Linear Combination using AggregateHybridQuery\n", + "## 1. Linear Combination\n", "\n", - "The goal of this technique is to calculate a weighted sum of the text similarity score for our provided text search and the cosine distance between vectors calculated via a KNN vector query. Under the hood this is possible in Redis using the [aggregations API](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/aggregations/), as of `Redis 7.4.x` (search version `2.10.5`), within a single database call.\n", + "The goal of this technique is to calculate a weighted sum of the text similarity score for our provided text search and the vector similarity score for our provided vector.\n", "\n", - "As of RedisVl 0.5.0 all of this is nicely encapsulated in your `AggregateHybridQuery` class, which behaves much like our other query classes." + "The FT.HYBRID API introduced in Redis 8.4.0 supports a linear combination of text and vector scores (accessible as of RedisVL 0.13.0 in `HybridQuery`), and it is also possible with the aggregations API, as of `Redis 7.4.x` (search version `2.10.5` - accessible as of RedisVl 0.5.0 in `AggregateHybridQuery`)." ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T14:20:24.727302Z", + "start_time": "2025-12-10T14:20:24.704993Z" + } + }, "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], "source": [ "# Sample user query (can be changed for comparisons)\n", "user_query = \"action adventure movie with great fighting scenes against a dangerous criminal, crime busting, superheroes, and magic\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First, we will import our `AggregateHybridQuery` and understand its parameters.\n", - "At a minimum, the `AggregateHybridQuery` needs 4 arguments:\n", - "```python\n", - "query = AggregateHybridQuery(\n", - " text = \"your query string here\",\n", - " text_field_name = \"\",\n", - " vector = ,\n", - " vector_field_name = \"\",\n", - ")\n", - "```" - ] + ], + "outputs": [], + "execution_count": 9 }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:08:29.899375Z", + "start_time": "2025-12-10T16:08:29.869588Z" + } + }, "cell_type": "code", - "execution_count": 11, - "metadata": {}, + "source": [ + "import pandas as pd\n", + "\n", + "from redisvl.query.hybrid import HybridQuery\n", + "\n", + "vector = model.embed(user_query, as_buffer=True)\n", + "\n", + "query = HybridQuery(\n", + "\ttext=user_query,\n", + "\ttext_field_name=\"description\",\n", + "\tvector=vector,\n", + "\tvector_field_name=\"description_vector\",\n", + "\tcombination_method=\"LINEAR\",\n", + "\tyield_text_score_as=\"text_score\",\n", + "\tyield_vsim_score_as=\"vector_similarity\",\n", + "\tyield_combined_score_as=\"hybrid_score\",\n", + "\treturn_fields=[\"title\"],\n", + ")\n", + "\n", + "results = index.hybrid_search(query)\n", + "pd.DataFrame(results[:3])" + ], "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "eef2a2e2bf504bbb95caea19bb8c4705", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
text_scoretitlevector_similarityhybrid_score
09.1624524482The Incredibles0.6770122349263.22264429891
15.02411250758Skyfall0.6012274026871.92809293416
24.13361061261Explosive Pursuit0.6956753134731.72705590321
\n", + "" ] }, - "execution_count": 11, + "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], + "execution_count": 37 + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "Alternatively, for Redis versions prior to 8.4.0, we can use the aggregations API:" + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:08:42.379757Z", + "start_time": "2025-12-10T16:08:42.351361Z" + } + }, "source": [ - "from redisvl.query import AggregateHybridQuery\n", - "\n", - "vector = model.embed(user_query, as_buffer=True)\n", + "from redisvl.query.aggregate import AggregateHybridQuery\n", "\n", - "query = AggregateHybridQuery(\n", + "agg_query = AggregateHybridQuery(\n", " text=user_query,\n", " text_field_name=\"description\",\n", " vector=vector,\n", @@ -752,40 +586,95 @@ " return_fields=[\"title\"],\n", ")\n", "\n", - "results = index.query(query)\n", + "print(f\"Query being executed:\\n{agg_query._build_query_string()}\")\n", "\n", - "results[:3]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "That's it! That is all it takes to perform a hybrid text matching and vector query with RedisVL.\n", - "Of course there are many more configurations and things we can do with the `AggregateHybridQuery` class. Let's investigate.\n", - "\n", - "First, let's look at just the text query part that is being run:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, + "results = index.query(agg_query)\n", + "pd.DataFrame(results[:3])" + ], "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query being executed:\n", + "(~@description:(action | adventure | movie | great | fighting | scenes | dangerous | criminal | crime | busting | superheroes | magic))=>[KNN 10 @description_vector $vector AS vector_distance]\n" + ] + }, { "data": { "text/plain": [ - "'(~@description:(action | adventure | movie | great | fighting | scenes | dangerous | criminal | crime | busting | superheroes | magic))=>[KNN 10 @description_vector $vector AS vector_distance]'" + " vector_distance title vector_similarity text_score \\\n", + "0 0.645975530148 The Incredibles 0.677012234926 9.1624524482 \n", + "1 0.797545194626 Skyfall 0.601227402687 5.02411250758 \n", + "2 0.608649373055 Explosive Pursuit 0.695675313473 4.13361061261 \n", + "\n", + " hybrid_score \n", + "0 3.22264429891 \n", + "1 1.92809293416 \n", + "2 1.72705590321 " + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
vector_distancetitlevector_similaritytext_scorehybrid_score
00.645975530148The Incredibles0.6770122349269.16245244823.22264429891
10.797545194626Skyfall0.6012274026875.024112507581.92809293416
20.608649373055Explosive Pursuit0.6956753134734.133610612611.72705590321
\n", + "
" ] }, - "execution_count": 13, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "query._build_query_string()" - ] + "execution_count": 38 }, { "cell_type": "markdown", @@ -794,43 +683,24 @@ "### Choosing your stopwords for better queries\n", "You can see that the user query string has been tokenized and certain stopwords like 'and', 'for', 'with', 'but', have been removed, otherwise you would get matches on irrelevant words.\n", "RedisVL uses [NLTK](https://www.nltk.org/index.html) english stopwords as the the default. You can change which default language stopwords to use with the `stopwords` argument.\n", - "You specify a language, like 'german', 'arabic', 'greek' and many others, provide your own list of stopwords, or set it to `None` to not remove any." + "You specify a language, like 'german', 'arabic', 'greek' and many others, provide your own list of stopwords, or set it to `None` to not remove any.\n", + "\n", + "Note that both `HybridQuery` and `AggregateHybridQuery` process stopwords identically." ] }, { "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3e4537950607485cb399928dd7bc0c04", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00[KNN 10 @description_vector $vector AS vector_distance]\n", - "(~@description:(action | adventure | movie | great | fighting | scenes | against | dangerous | criminal | crime | busting | superheroes | magic))=>[KNN 10 @description_vector $vector AS vector_distance]\n", - "(~@description:(action | adventure | movie | with | great | fighting | scenes | against | a | dangerous | criminal | crime | busting | superheroes | and | magic))=>[KNN 10 @description_vector $vector AS vector_distance]\n" - ] + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T15:50:31.843735Z", + "start_time": "2025-12-10T15:50:31.828706Z" } - ], + }, "source": [ "# translate our user query to French and use nltk french stopwords\n", "french_query_text = \"Film d'action et d'aventure avec de superbes scรจnes de combat, des enquรชtes criminelles, des super-hรฉros et de la magie\"\n", "\n", - "french_film_query = AggregateHybridQuery(\n", + "french_film_query = HybridQuery(\n", " text=french_query_text,\n", " text_field_name=\"description\",\n", " vector=model.embed(french_query_text, as_buffer=True),\n", @@ -838,7 +708,7 @@ " stopwords=\"french\",\n", ")\n", "\n", - "print(french_film_query._build_query_string())\n", + "print(french_film_query.query._search_query.query_string())\n", "\n", "# specify your own stopwords\n", "custom_stopwords = set([\n", @@ -847,7 +717,7 @@ " \"then\", \"there\", \"these\", \"they\", \"this\", \"to\", \"was\", \"will\", \"with\"\n", "])\n", "\n", - "stopwords_query = AggregateHybridQuery(\n", + "stopwords_query = HybridQuery(\n", " text=user_query,\n", " text_field_name=\"description\",\n", " vector=vector,\n", @@ -855,10 +725,10 @@ " stopwords=custom_stopwords,\n", ")\n", "\n", - "print(stopwords_query._build_query_string())\n", + "print(stopwords_query.query._search_query.query_string())\n", "\n", "# don't use any stopwords\n", - "no_stopwords_query = AggregateHybridQuery(\n", + "no_stopwords_query = HybridQuery(\n", " text=user_query,\n", " text_field_name=\"description\",\n", " vector=vector,\n", @@ -866,120 +736,335 @@ " stopwords=None,\n", ")\n", "\n", - "print(no_stopwords_query._build_query_string())" - ] + "print(no_stopwords_query.query._search_query.query_string())" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(~@description:(film | d\\'action | d\\'aventure | superbes | scรจnes | combat | enquรชtes | criminelles | super\\-hรฉros | magie))\n", + "(~@description:(action | adventure | movie | great | fighting | scenes | against | dangerous | criminal | crime | busting | superheroes | magic))\n", + "(~@description:(action | adventure | movie | with | great | fighting | scenes | against | a | dangerous | criminal | crime | busting | superheroes | and | magic))\n" + ] + } + ], + "execution_count": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Choosing your text scoring function and weights\n", - "There are different ways to calculate the similarity between sets of text. Redis supports several, such as `BM25`, `TFIDF`, `DISMAX`, and others. The default is `BM25STD` and is easy to configure with the `text_scorer` parameter. Just like changing you embedding model can change your vector similarity scores, changing your text similarity measure can change your text scores.\n", + "There are different ways to calculate the similarity between sets of text. Options for text scoring functions are TFIDF, TFIDF.DOCNORM, BM25STD, BM25STD.NORM, BM25STD.TANH, DISMAX, DOCSCORE, and HAMMING; the default is BM25STD and is easy to configure with the `text_scorer` parameter. Just like changing you embedding model can change your vector similarity scores, changing your text similarity measure can change your text scores.\n", + "\n", + "> For more information about supported scoring algorithms, see [the Redis documentation on scoring](https://redis.io/docs/latest/develop/ai/search-and-query/advanced-concepts/scoring/).\n", + "\n", + "When combining text and vector scores using a linear combination (`combination_method=\"LINEAR\"` in `HybridQuery` and the only option for `AggregateHybridQuery`), you can control the relative balance of these scores with tunable parameters.\n", + "\n", + "The FT.HYBRID API calculates the combined score as:\n", "\n", - "Because hybrid queries are performing a weighted average of text similarity and vector similarity you also control the relative balance of these scores with the `alpha` parameter.\n", + "```python\n", + "hybrid_score = {alpha} * text_score + {beta} * vector_similarity\n", + "```\n", "\n", - "The documents are ranked based on the hybrid score which is computed as:\n", + "Where `alpha` and `beta` can be provided to `HybridQuery` via the `linear_alpha` and `linear_beta` parameters. If neither one is specified, FT.HYBRID defaults to `alpha=0.3` and `beta=0.7`. If only `alpha` is specified, `beta` is set to `1 - alpha`, and vice-versa.\n", + "\n", + "`AggregateHybridQuery` defines the combined score in reverse as:\n", "\n", "```python\n", "hybrid_score = {1-alpha} * text_score + {alpha} * vector_similarity\n", "```\n", "\n", - "Try changing the `text_scorer` and `alpha` parameters in the query below to see how results may change.\n" + "Where the `alpha` parameter is configurable on the `AggregateHybridQuery` class. If not specified, it defaults to `0.7`.\n", + "\n", + "Try changing the `text_scorer` and `linear_alpha` parameters in the query below to see how results may change." ] }, { "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'vector_distance': '0.645975351334',\n", - " 'title': 'The Incredibles',\n", - " 'description': \"A family of undercover superheroes, while trying to live the quiet suburban life, are forced into action to save the world. Bob Parr (Mr. Incredible) and his wife Helen (Elastigirl) were among the world's greatest crime fighters, but now they must assume civilian identities and retreat to the suburbs to live a 'normal' life with their three children. However, the family's desire to help the world pulls them back into action when they face a new and dangerous enemy.\",\n", - " 'vector_similarity': '0.677012324333',\n", - " 'text_score': '8',\n", - " 'hybrid_score': '6.16925308108'},\n", - " {'vector_distance': '0.653376042843',\n", - " 'title': 'The Dark Knight',\n", - " 'description': 'Batman faces off against the Joker, a criminal mastermind who threatens to plunge Gotham into chaos.',\n", - " 'vector_similarity': '0.673311978579',\n", - " 'text_score': '8',\n", - " 'hybrid_score': '6.16832799464'},\n", - " {'vector_distance': '0.608649373055',\n", - " 'title': 'Explosive Pursuit',\n", - " 'description': 'A daring cop chases a notorious criminal across the city in a high-stakes game of cat and mouse.',\n", - " 'vector_similarity': '0.695675313473',\n", - " 'text_score': '6',\n", - " 'hybrid_score': '4.67391882837'}]" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:08:56.262304Z", + "start_time": "2025-12-10T16:08:56.242045Z" } - ], + }, "source": [ - "tfidf_query = AggregateHybridQuery(\n", + "tfidf_query = HybridQuery(\n", " text=user_query,\n", " text_field_name=\"description\",\n", " vector=vector,\n", " vector_field_name=\"description_vector\",\n", " text_scorer=\"TFIDF\", # can be one of [TFIDF, TFIDF.DOCNORM, BM25, DISMAX, DOCSCORE, BM25STD]\n", " stopwords=None,\n", - " alpha=0.25, # weight the vector score lower\n", + "\tcombination_method=\"LINEAR\",\n", + " linear_beta=0.25, # weight the vector score lower\n", " return_fields=[\"title\", \"description\"],\n", + "\tyield_text_score_as=\"text_score\",\n", + " yield_vsim_score_as=\"vector_similarity\",\n", + " yield_combined_score_as=\"hybrid_score\",\n", ")\n", "\n", - "results = index.query(tfidf_query)\n", - "\n", - "results[:3]" - ] + "results = index.hybrid_search(tfidf_query)\n", + "pd.DataFrame(results[:3])" + ], + "outputs": [ + { + "data": { + "text/plain": [ + " text_score title \\\n", + "0 6 Explosive Pursuit \n", + "1 6 Despicable Me \n", + "2 6 Skyfall \n", + "\n", + " description vector_similarity \\\n", + "0 A daring cop chases a notorious criminal acros... 0.695675313473 \n", + "1 When a criminal mastermind uses a trio of orph... 0.651065170765 \n", + "2 James Bond returns to track down a dangerous n... 0.601227402687 \n", + "\n", + " hybrid_score \n", + "0 4.67391882837 \n", + "1 4.66276629269 \n", + "2 4.65030685067 " + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
text_scoretitledescriptionvector_similarityhybrid_score
06Explosive PursuitA daring cop chases a notorious criminal acros...0.6956753134734.67391882837
16Despicable MeWhen a criminal mastermind uses a trio of orph...0.6510651707654.66276629269
26SkyfallJames Bond returns to track down a dangerous n...0.6012274026874.65030685067
\n", + "
" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 2. Client-side fusion with RRF\n", + "## 2. Reciprocal Rank Fusion (RRF)\n", "\n", "Instead of relying on document scores like cosine similarity and BM25/TFIDF, we can fetch items and focus on their rank. This rank can be utilized to create a new ranking metric known as [Reciprocal Rank Fusion (RRF)](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf). RRF is powerful because it can handle ranked lists of different length, scores of different scales, and other complexities.\n", "\n", - "Although Redis does not currently support RRF natively, we can easily implement it on the client side." + "The FT.HYBRID API introduced in Redis 8.4.0 supports using RRF to combine results from text and vector queries (accessible as of RedisVL 0.13.0 in `HybridQuery`). Unless otherwise specified, RRF is the default combination method.\n", + "\n", + "The parameters available to customize the behaviour of RRF are `rrf_window` and `rrf_constant`. The `rrf_window` parameter controls the size of the window over which the RRF score is calculated, and the `rrf_constant` parameter controls the constant used in the RRF formula. Try changing these parameters to see how results may change." ] }, { + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:09:04.234221Z", + "start_time": "2025-12-10T16:09:04.208827Z" + } + }, "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], "source": [ - "def fuse_rankings_rrf(*ranked_lists, weights=None, k=60):\n", - " \"\"\"\n", - " Perform Weighted Reciprocal Rank Fusion on N number of ordered lists.\n", - " \"\"\"\n", - " item_scores = {}\n", - " \n", - " if weights is None:\n", - " weights = [1.0] * len(ranked_lists)\n", - " else:\n", - " assert len(weights) == len(ranked_lists), \"Number of weights must match number of ranked lists\"\n", - " assert all(0 <= w <= 1 for w in weights), \"Weights must be between 0 and 1\"\n", - " \n", - " for ranked_list, weight in zip(ranked_lists, weights):\n", - " for rank, item in enumerate(ranked_list, start=1):\n", - " if item not in item_scores:\n", - " item_scores[item] = 0\n", - " item_scores[item] += weight * (1 / (rank + k))\n", - " \n", - " # Sort items by their weighted RRF scores in descending order\n", - " return sorted(item_scores.items(), key=lambda x: x[1], reverse=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 27, + "query = HybridQuery(\n", + "\ttext=user_query,\n", + "\ttext_field_name=\"description\",\n", + "\tvector=vector,\n", + "\tvector_field_name=\"description_vector\",\n", + "\tcombination_method=\"RRF\",\n", + "\trrf_window=20,\n", + "\trrf_constant=60,\n", + "\tyield_text_score_as=\"text_score\",\n", + "\tyield_vsim_score_as=\"vector_similarity\",\n", + "\tyield_combined_score_as=\"hybrid_score\",\n", + "\treturn_fields=[\"title\", \"description\"],\n", + ")\n", + "\n", + "results = index.hybrid_search(query)\n", + "pd.DataFrame(results[:3])" + ], + "outputs": [ + { + "data": { + "text/plain": [ + " text_score title \\\n", + "0 9.1624524482 The Incredibles \n", + "1 4.13361061261 Explosive Pursuit \n", + "2 4.13361061261 The Dark Knight \n", + "\n", + " description vector_similarity \\\n", + "0 A family of undercover superheroes, while tryi... 0.677012234926 \n", + "1 A daring cop chases a notorious criminal acros... 0.695675313473 \n", + "2 Batman faces off against the Joker, a criminal... 0.673311859369 \n", + "\n", + " hybrid_score \n", + "0 0.032522474881 \n", + "1 0.032266458496 \n", + "2 0.031498015873 " + ], + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
text_scoretitledescriptionvector_similarityhybrid_score
09.1624524482The IncrediblesA family of undercover superheroes, while tryi...0.6770122349260.032522474881
14.13361061261Explosive PursuitA daring cop chases a notorious criminal acros...0.6956753134730.032266458496
24.13361061261The Dark KnightBatman faces off against the Joker, a criminal...0.6733118593690.031498015873
\n", + "
" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 40 + }, + { "metadata": {}, + "cell_type": "markdown", + "source": [ + "### Client-side RRF for older Redis versions\n", + "\n", + "When using Redis versions prior to 8.4.0, you can still perform RRF by fetching the top-k results from both the text and vector queries, and then fusing them together on the client-side." + ] + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:11:49.264732Z", + "start_time": "2025-12-10T16:11:49.253781Z" + } + }, + "source": [ + "def fuse_rankings_rrf(*ranked_lists, weights=None, k=60):\n", + " \"\"\"\n", + " Perform Weighted Reciprocal Rank Fusion on N number of ordered lists.\n", + " \"\"\"\n", + " item_scores = {}\n", + " \n", + " if weights is None:\n", + " weights = [1.0] * len(ranked_lists)\n", + " else:\n", + " assert len(weights) == len(ranked_lists), \"Number of weights must match number of ranked lists\"\n", + " assert all(0 <= w <= 1 for w in weights), \"Weights must be between 0 and 1\"\n", + " \n", + " for ranked_list, weight in zip(ranked_lists, weights):\n", + " for rank, item in enumerate(ranked_list, start=1):\n", + " if item not in item_scores:\n", + " item_scores[item] = 0\n", + " item_scores[item] += weight * (1 / (rank + k))\n", + " \n", + " # Sort items by their weighted RRF scores in descending order\n", + " return sorted(item_scores.items(), key=lambda x: x[1], reverse=True)" + ], + "outputs": [], + "execution_count": 41 + }, + { + "cell_type": "code", + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:11:49.543077Z", + "start_time": "2025-12-10T16:11:49.515763Z" + } + }, + "source": [ + "# Below is a simple example of RRF over a few lists of numbers\n", + "fuse_rankings_rrf([1, 2, 3], [2, 4, 6, 7, 8], [5, 6, 1, 2])" + ], "outputs": [ { "data": { @@ -994,15 +1079,12 @@ " (8, 0.015384615384615385)]" ] }, - "execution_count": 27, + "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "# Below is a simple example of RRF over a few lists of numbers\n", - "fuse_rankings_rrf([1, 2, 3], [2, 4, 6, 7, 8], [5, 6, 1, 2])" - ] + "execution_count": 42 }, { "cell_type": "markdown", @@ -1013,9 +1095,12 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:11:50.436413Z", + "start_time": "2025-12-10T16:11:50.424796Z" + } + }, "source": [ "# Function to create a vector query using RedisVL helpers for ease of use\n", "from redisvl.query import VectorQuery, TextQuery\n", @@ -1044,13 +1129,18 @@ " num_results=num_results,\n", " return_fields=[\"title\", \"description\"],\n", " )" - ] + ], + "outputs": [], + "execution_count": 43 }, { "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:11:51.011520Z", + "start_time": "2025-12-10T16:11:51.003232Z" + } + }, "source": [ "from typing import List, Dict, Any\n", "\n", @@ -1078,27 +1168,23 @@ "\n", " # Perform weighted RRF\n", " return fuse_rankings_rrf(vector_titles, full_text_titles, weights=[alpha, 1-alpha], k=k)[:num_results]" - ] + ], + "outputs": [], + "execution_count": 44 }, { "cell_type": "code", - "execution_count": 30, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:11:51.563529Z", + "start_time": "2025-12-10T16:11:51.534499Z" + } + }, + "source": [ + "# Test it out!\n", + "weighted_rrf(user_query, num_results=6)" + ], "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "848faeb9dbfe4150917d407dfe865e92", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
genremax_hybrid_scoreavg_hybrid_scorecountmax_ratingmin_ratingrating_range
0comedy0.02928692699490.016670548914610862
1action0.0325224748810.027186972153410963
\n", + "" + ] + }, + "execution_count": 110, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 110 + }, + { "metadata": {}, + "cell_type": "markdown", "source": [ "## Comparing Approaches\n", "\n", @@ -1304,9 +1473,12 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:13:01.309286Z", + "start_time": "2025-12-10T16:13:01.282284Z" + } + }, "source": [ "movie_user_queries = [\n", " \"I'm in the mood for a high-rated action movie with a complex plot\",\n", @@ -1325,28 +1497,37 @@ " \"I'm interested in a movie with themes of revenge or justice\",\n", " \"What are some visually stunning movies with impressive special effects?\"\n", "]" - ] + ], + "outputs": [], + "execution_count": 49 }, { "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:18:03.336507Z", + "start_time": "2025-12-10T16:18:03.324940Z" + } + }, "source": [ - "def hybrid_query(text, alpha, num_results) -> List[Dict[str, Any]]:\n", + "from typing import Tuple\n", "\n", - " query = AggregateHybridQuery(\n", - " text,\n", - " text_field_name=\"description\",\n", - " vector=model.embed(text, as_buffer=True),\n", - " vector_field_name=\"description_vector\",\n", - " text_scorer=\"BM25\",\n", - " stopwords=\"english\",\n", - " alpha=alpha,\n", - " return_fields=[\"title\", \"hybrid_score\"],\n", + "\n", + "def hybrid_query(text, num_results: int, **kwargs) -> List[Tuple[str, float]]:\n", + "\n", + " query = HybridQuery(\n", + "\t\ttext,\n", + "\t\ttext_field_name=\"description\",\n", + "\t\tvector=model.embed(text, as_buffer=True),\n", + "\t\tvector_field_name=\"description_vector\",\n", + "\t\tstopwords=\"english\",\n", + "\t\tnum_results=num_results,\n", + "\t\treturn_fields=[\"title\"],\n", + "\t\tyield_combined_score_as=\"hybrid_score\",\n", + "\t\t**kwargs,\n", " )\n", "\n", - " results = index.query(query)\n", + " results = index.hybrid_search(query)\n", "\n", " return [\n", " (\n", @@ -1355,887 +1536,94 @@ " )\n", " for movie in results\n", " ]" - ] + ], + "outputs": [], + "execution_count": 52 }, { "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2025-12-10T16:18:36.589033Z", + "start_time": "2025-12-10T16:18:36.578526Z" + } + }, "source": [ "import pandas as pd\n", "\n", "\n", "rankings = pd.DataFrame()\n", - "rankings[\"queries\"] = movie_user_queries\n", + "rankings[\"query\"] = movie_user_queries\n", "\n", "# First, add new columns to the DataFrame\n", "rankings[\"hf-cross-encoder\"] = \"\"\n", "rankings[\"rrf\"] = \"\"\n", - "rankings[\"linear-combo-bm25-cosine\"] = \"\"" - ] + "rankings[\"linear\"] = \"\"" + ], + "outputs": [], + "execution_count": 58 }, { "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c562a6abb1eb47a982891fb9d6c9fc99", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Batches: 0%| | 0/1 [00:00\n", "