Skip to content

Commit 67c92d2

Browse files
authored
Merge pull request #135 from HeidiSteen/main
Update Tutorial-RAG with new index that uses vector storage minimizat…
2 parents 9a460f3 + e55c718 commit 67c92d2

File tree

2 files changed

+172
-1
lines changed

2 files changed

+172
-1
lines changed

Tutorial-RAG/Tutorial-rag-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
python-dotenv
22
azure-core
3-
azure-search-documents==11.5.1
3+
azure-search-documents==11.5.2
44
azure-storage-blob
55
azure-identity
66
openai

Tutorial-RAG/Tutorial-rag.ipynb

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,177 @@
940940
"\n",
941941
"print(response.choices[0].message.content)"
942942
]
943+
},
944+
{
945+
"cell_type": "markdown",
946+
"metadata": {},
947+
"source": [
948+
"## Create a second index with reduced vector size\n",
949+
"\n",
950+
"Azure AI Search has multiple approaches for reducing vector size, which lowers the cost of vector workloads. In this step, create a new index that uses the following capabilities:\n",
951+
"\n",
952+
"- Smaller vector indexes by compressing the vectors used during query execution. Scalar quantization provides this capability.\n",
953+
"- Smaller vector indexes by opting out of vector storage for search results. If you only need vectors for queries and not in response payload, you can drop the vector copy used for search results.\n",
954+
"- Smaller vector fields through narrow data types. You can specify Collection(Edm.Half) on the text_vector field to store incoming float32 dimensions as float16.\n",
955+
"\n",
956+
"All of these capabilities are specified in a search index. After you load the index, compare the difference between the original index and the new one.\n"
957+
]
958+
},
959+
{
960+
"cell_type": "code",
961+
"execution_count": null,
962+
"metadata": {},
963+
"outputs": [],
964+
"source": [
965+
"from azure.identity import DefaultAzureCredential\n",
966+
"from azure.identity import get_bearer_token_provider\n",
967+
"from azure.search.documents.indexes import SearchIndexClient\n",
968+
"from azure.search.documents.indexes.models import (\n",
969+
" SearchField,\n",
970+
" SearchFieldDataType,\n",
971+
" VectorSearch,\n",
972+
" HnswAlgorithmConfiguration,\n",
973+
" VectorSearchProfile,\n",
974+
" AzureOpenAIVectorizer,\n",
975+
" AzureOpenAIVectorizerParameters,\n",
976+
" ScalarQuantizationCompression,\n",
977+
" ScalarQuantizationParameters,\n",
978+
" SearchIndex,\n",
979+
" SemanticConfiguration,\n",
980+
" SemanticPrioritizedFields,\n",
981+
" SemanticField,\n",
982+
" SemanticSearch,\n",
983+
" ScoringProfile,\n",
984+
" TagScoringFunction,\n",
985+
" TagScoringParameters\n",
986+
")\n",
987+
"\n",
988+
"credential = DefaultAzureCredential()\n",
989+
"\n",
990+
"index_name = \"py-rag-tutorial-small-vectors-idx\"\n",
991+
"index_client = SearchIndexClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential) \n",
992+
"fields = [\n",
993+
" SearchField(name=\"parent_id\", type=SearchFieldDataType.String), \n",
994+
" SearchField(name=\"title\", type=SearchFieldDataType.String),\n",
995+
" SearchField(name=\"locations\", type=SearchFieldDataType.Collection(SearchFieldDataType.String), filterable=True),\n",
996+
" SearchField(name=\"chunk_id\", type=SearchFieldDataType.String, key=True, sortable=True, filterable=True, facetable=True, analyzer_name=\"keyword\"), \n",
997+
" SearchField(name=\"chunk\", type=SearchFieldDataType.String, sortable=False, filterable=False, facetable=False), \n",
998+
" SearchField(name=\"text_vector\", type=\"Collection(Edm.Half)\", vector_search_dimensions=1024, vector_search_profile_name=\"myHnswProfile\", stored= False)\n",
999+
" ] \n",
1000+
"\n",
1001+
"# Configure the vector search configuration \n",
1002+
"vector_search = VectorSearch( \n",
1003+
" algorithms=[ \n",
1004+
" HnswAlgorithmConfiguration(name=\"myHnsw\"),\n",
1005+
" ], \n",
1006+
" profiles=[ \n",
1007+
" VectorSearchProfile( \n",
1008+
" name=\"myHnswProfile\", \n",
1009+
" algorithm_configuration_name=\"myHnsw\",\n",
1010+
" compression_name=\"myScalarQuantization\",\n",
1011+
" vectorizer_name=\"myOpenAI\", \n",
1012+
" )\n",
1013+
" ], \n",
1014+
" vectorizers=[ \n",
1015+
" AzureOpenAIVectorizer( \n",
1016+
" vectorizer_name=\"myOpenAI\", \n",
1017+
" kind=\"azureOpenAI\", \n",
1018+
" parameters=AzureOpenAIVectorizerParameters( \n",
1019+
" resource_url=AZURE_OPENAI_ACCOUNT, \n",
1020+
" deployment_name=\"text-embedding-3-large\",\n",
1021+
" model_name=\"text-embedding-3-large\"\n",
1022+
" ),\n",
1023+
" ), \n",
1024+
" ],\n",
1025+
" compressions=[\n",
1026+
" ScalarQuantizationCompression(\n",
1027+
" compression_name=\"myScalarQuantization\",\n",
1028+
" rerank_with_original_vectors=True,\n",
1029+
" default_oversampling=10,\n",
1030+
" parameters=ScalarQuantizationParameters(quantized_data_type=\"int8\"),\n",
1031+
" )\n",
1032+
" ]\n",
1033+
")\n",
1034+
"\n",
1035+
"semantic_config = SemanticConfiguration(\n",
1036+
" name=\"my-semantic-config\",\n",
1037+
" prioritized_fields=SemanticPrioritizedFields(\n",
1038+
" title_field=SemanticField(field_name=\"title\"),\n",
1039+
" keywords_fields=[SemanticField(field_name=\"locations\")],\n",
1040+
" content_fields=[SemanticField(field_name=\"chunk\")]\n",
1041+
" )\n",
1042+
")\n",
1043+
"\n",
1044+
"semantic_search = SemanticSearch(configurations=[semantic_config])\n",
1045+
"\n",
1046+
"scoring_profiles = [ \n",
1047+
" ScoringProfile( \n",
1048+
" name=\"my-scoring-profile\",\n",
1049+
" functions=[\n",
1050+
" TagScoringFunction( \n",
1051+
" field_name=\"locations\", \n",
1052+
" boost=5.0, \n",
1053+
" parameters=TagScoringParameters( \n",
1054+
" tags_parameter=\"tags\", \n",
1055+
" ), \n",
1056+
" ) \n",
1057+
" ]\n",
1058+
" )\n",
1059+
"]\n",
1060+
"\n",
1061+
"index = SearchIndex(name=index_name, fields=fields, vector_search=vector_search, semantic_search=semantic_search, scoring_profiles=scoring_profiles) \n",
1062+
"result = index_client.create_or_update_index(index) \n",
1063+
"print(f\"{result.name} created\")\n"
1064+
]
1065+
},
1066+
{
1067+
"cell_type": "markdown",
1068+
"metadata": {},
1069+
"source": [
1070+
"## Run the indexer to create the new index\n",
1071+
"\n",
1072+
"Your ability to create and populate the new index is predicated on reusing data structures created earlier in this tutorial. If you have run every cell in this notebook, you have an existing data source and skillset, but here we create a new indexer so that there's no history or caching to get in the way. The indexer uses the notebook's current values for skillset_name, target_index_name, and data_source_name. Because the skillset and data source haven't changed, the existing references are still valid. Because you just created a new index in the previous cell, the current target_index_name is now \"py-rag-tutorial-small-vectors-idx\"."
1073+
]
1074+
},
1075+
{
1076+
"cell_type": "code",
1077+
"execution_count": null,
1078+
"metadata": {},
1079+
"outputs": [],
1080+
"source": [
1081+
"from azure.search.documents.indexes.models import (\n",
1082+
" SearchIndexer\n",
1083+
")\n",
1084+
"\n",
1085+
"# Create an indexer \n",
1086+
"indexer_name = \"py-rag-tutorial-small-vectors-idxr\" \n",
1087+
"\n",
1088+
"indexer_parameters = None\n",
1089+
"\n",
1090+
"indexer = SearchIndexer( \n",
1091+
" name=indexer_name, \n",
1092+
" description=\"Indexer to index documents and generate embeddings\", \n",
1093+
" skillset_name=skillset_name, \n",
1094+
" target_index_name=index_name, \n",
1095+
" data_source_name=data_source.name,\n",
1096+
" parameters=indexer_parameters\n",
1097+
") \n",
1098+
"\n",
1099+
"# Create and run the indexer \n",
1100+
"indexer_client = SearchIndexerClient(endpoint=AZURE_SEARCH_SERVICE, credential=credential) \n",
1101+
"indexer_result = indexer_client.create_or_update_indexer(indexer) \n",
1102+
"\n",
1103+
"print(f' {indexer_name} is created and running. Give the indexer a few minutes before running a query.')\n"
1104+
]
1105+
},
1106+
{
1107+
"cell_type": "markdown",
1108+
"metadata": {},
1109+
"source": [
1110+
"As a final step, switch to the Azure portal to compare the vector storage requirements for the two indexes. The index created in the last step uses half-precision floating-point numbers (float16) for the text vectors. This reduces the storage requirements for the vectors by half compared to the previous index that used single-precision floating-point numbers (float32). Scalar compression and the omission of one set of the vecctors account for the remaining storage savings. For more information about reducing vector size, see [Choose an approach for optimizing vector storage and processing](https://learn.microsoft.com/azure/search/vector-search-how-to-configure-compression-storage).\n",
1111+
"\n",
1112+
"Consider revisiting the queries from the previous lessons so that you can compare query speed and utility. You should expect some variation in LLM output whenever you repeat a query, but in general the storage-saving techniques you implemented should not cause significant degradation of search result quality."
1113+
]
9431114
}
9441115
],
9451116
"metadata": {

0 commit comments

Comments
 (0)