demo-dotnet/QuantizationAndStorageOptions/Program.cs (156 lines of code) (raw):
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using QuantizationAndStorageOptions;
using Azure.Identity;
using Azure;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Text.Json;
var configuration = new Configuration();
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddEnvironmentVariables()
.AddJsonFile("local.settings.json")
.Build()
.Bind(configuration);
configuration.Validate();
var defaultCredential = new DefaultAzureCredential();
var searchIndexClient = InitializeSearchIndexClient(configuration, defaultCredential);
string baseIndexName = configuration.IndexName;
string dataPath = Path.Join("..", "..", "data", "documentVectors.json");
string jsonString = File.ReadAllText(dataPath);
Document[] documents = JsonSerializer.Deserialize<Document[]>(jsonString);
string baselineIndexName = $"{baseIndexName}-baseline";
CreateAndInitializeIndex(
CreateStorageIndex(
baselineIndexName,
useFloat16: false,
noStored: false,
useQuantization: false),
searchIndexClient,
documents);
string narrowIndexName = $"{baseIndexName}-narrow";
CreateAndInitializeIndex(
CreateStorageIndex(
narrowIndexName,
useFloat16: true,
noStored: false,
useQuantization: false),
searchIndexClient,
documents);
string quantizationIndexName = $"{baseIndexName}-quantization";
CreateAndInitializeIndex(
CreateStorageIndex(
quantizationIndexName,
useFloat16: false,
noStored: false,
useQuantization: true),
searchIndexClient,
documents);
string storedIndexName = $"{baseIndexName}-stored";
CreateAndInitializeIndex(
CreateStorageIndex(
storedIndexName,
useFloat16: false,
noStored: true,
useQuantization: false),
searchIndexClient,
documents);
string allIndexName = $"{baseIndexName}-all";
CreateAndInitializeIndex(
CreateStorageIndex(
allIndexName,
useFloat16: true,
noStored: true,
useQuantization: true),
searchIndexClient,
documents);
SearchIndexClient InitializeSearchIndexClient(Configuration configuration, DefaultAzureCredential defaultCredential)
{
if (!string.IsNullOrEmpty(configuration.AdminKey))
{
return new SearchIndexClient(new Uri(configuration.ServiceEndpoint), new AzureKeyCredential(configuration.AdminKey));
}
return new SearchIndexClient(new Uri(configuration.ServiceEndpoint), defaultCredential);
}
SearchIndex CreateStorageIndex(string indexName, bool useFloat16, bool noStored, bool useQuantization)
{
const string vectorSearchHnswProfile = "my-vector-profile";
const string vectorSearchHnswConfig = "myHnsw";
const int modelDimensions = 3072;
SearchFieldDataType dataType;
if(useFloat16)
{
dataType = SearchFieldDataType.Collection(SearchFieldDataType.Half);
}
else
{
dataType = SearchFieldDataType.Collection(SearchFieldDataType.Single);
}
SearchIndex searchIndex = new(indexName)
{
VectorSearch = new()
{
Profiles =
{
new VectorSearchProfile(vectorSearchHnswProfile, vectorSearchHnswConfig)
{
CompressionConfigurationName = useQuantization ? "my-compression" : null
}
},
Algorithms =
{
new HnswAlgorithmConfiguration(vectorSearchHnswConfig),
}
},
SemanticSearch = new()
{
Configurations =
{
new SemanticConfiguration("semantic-config", new()
{
TitleField = new SemanticField(fieldName: "title"),
ContentFields =
{
new SemanticField(fieldName: "chunk")
},
})
},
},
Fields =
{
new SearchableField("id") { IsKey = true, IsFilterable = true, IsSortable = true },
new SearchableField("title"),
new SearchableField("chunk"),
new SearchField("embedding", dataType)
{
IsSearchable = true,
IsHidden = noStored,
IsStored = !noStored,
VectorSearchDimensions = modelDimensions,
VectorSearchProfileName = vectorSearchHnswProfile
}
},
};
if (useQuantization)
{
searchIndex.VectorSearch.Compressions.Add(new ScalarQuantizationCompressionConfiguration("my-compression"));
}
return searchIndex;
}
void CreateAndInitializeIndex(SearchIndex index, SearchIndexClient indexClient, Document[] documents)
{
Console.WriteLine($"Creating index {index.Name}");
indexClient.CreateOrUpdateIndex(index);
var searchClient = indexClient.GetSearchClient(index.Name);
using var bufferedSender = new SearchIndexingBufferedSender<Document>(searchClient);
bufferedSender.UploadDocuments(documents);
}
class Document
{
public string id { get; set; }
public string title { get; set; }
public string chunk { get; set; }
public float[] embedding { get; set; }
}