From b27eb9ca2d56f6649a4a10255d09448e370ad689 Mon Sep 17 00:00:00 2001 From: Daniel Getu Date: Mon, 6 May 2024 22:01:13 +0000 Subject: [PATCH] [Search] Refactor test setup --- .../test/public/node/searchClient.spec.ts | 4 +- .../test/public/utils/setup.ts | 523 +++++++++--------- 2 files changed, 276 insertions(+), 251 deletions(-) diff --git a/sdk/search/search-documents/test/public/node/searchClient.spec.ts b/sdk/search/search-documents/test/public/node/searchClient.spec.ts index c03caf336730..99547b36e398 100644 --- a/sdk/search/search-documents/test/public/node/searchClient.spec.ts +++ b/sdk/search/search-documents/test/public/node/searchClient.spec.ts @@ -76,7 +76,7 @@ describe("SearchClient", function (this: Suite) { indexName: TEST_INDEX_NAME, openAIClient, } = await createClients(stableServiceVersion, recorder, TEST_INDEX_NAME)); - await createIndex(indexClient, TEST_INDEX_NAME, stableServiceVersion); + await createIndex(indexClient, TEST_INDEX_NAME); await delay(WAIT_TIME); await populateIndex(searchClient, openAIClient); }); @@ -429,7 +429,7 @@ describe("SearchClient", function (this: Suite) { indexName: TEST_INDEX_NAME, openAIClient, } = await createClients(previewServiceVersion, recorder, TEST_INDEX_NAME)); - await createIndex(indexClient, TEST_INDEX_NAME, previewServiceVersion); + await createIndex(indexClient, TEST_INDEX_NAME); await delay(WAIT_TIME); await populateIndex(searchClient, openAIClient); }); diff --git a/sdk/search/search-documents/test/public/utils/setup.ts b/sdk/search/search-documents/test/public/utils/setup.ts index 49d3266b0356..5560cd40a373 100644 --- a/sdk/search/search-documents/test/public/utils/setup.ts +++ b/sdk/search/search-documents/test/public/utils/setup.ts @@ -1,16 +1,20 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { env, isLiveMode, isPlaybackMode } from "@azure-tools/test-recorder"; +import { assertEnvironmentVariable, isLiveMode, isPlaybackMode } from "@azure-tools/test-recorder"; import { OpenAIClient } from "@azure/openai"; import { assert } from "chai"; import { GeographyPoint, KnownAnalyzerNames, SearchClient, + SearchField, SearchIndex, SearchIndexClient, SearchIndexerClient, + VectorSearchAlgorithmConfiguration, + VectorSearchCompressionConfiguration, + VectorSearchVectorizer, } from "../../../src"; import { delay } from "../../../src/serviceUtils"; import { COMPRESSION_DISABLED } from "../../compressionDisabled"; @@ -18,214 +22,274 @@ import { Hotel } from "./interfaces"; export const WAIT_TIME = isPlaybackMode() ? 0 : 4000; +const uniqueNameMap: Record = {}; +function getUniqueName(baseName: string): string { + const i = uniqueNameMap[baseName] ?? 0; + uniqueNameMap[baseName] = i; + return `${baseName}${i ? `-${i}` : ""}`; +} + // eslint-disable-next-line @azure/azure-sdk/ts-use-interface-parameters -export async function createIndex( - client: SearchIndexClient, - name: string, - serviceVersion: string, -): Promise { - const algorithmConfigurationName = "algorithm-configuration-name"; - const vectorizerName = "vectorizer-name"; - const vectorSearchProfileName = "profile-name"; - const compressedVectorSearchProfileName = "compressed-profile-name"; - const compressionConfigurationName = "compression-configuration-name"; +export async function createIndex(client: SearchIndexClient, name: string): Promise { + const vectorizers: VectorSearchVectorizer[] = [ + { + kind: "azureOpenAI", + name: getUniqueName("vector-search-vectorizer"), + azureOpenAIParameters: { + deploymentId: assertEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME"), + resourceUri: assertEnvironmentVariable("AZURE_OPENAI_ENDPOINT"), + }, + }, + ]; + const [azureOpenAiVectorizerName, aiServicesVisionVectorizerName] = vectorizers.map( + (v) => v.name, + ); + + const algorithmConfigurations: VectorSearchAlgorithmConfiguration[] = [ + { + name: getUniqueName("vector-search-algorithm-configuration"), + kind: "hnsw", + parameters: { metric: "dotProduct" }, + }, + { + name: getUniqueName("vector-search-algorithm-configuration"), + kind: "exhaustiveKnn", + parameters: { metric: "euclidean" }, + }, + ]; + const [hnswAlgorithmConfigurationName, exhaustiveKnnAlgorithmConfigurationName] = + algorithmConfigurations.map((c) => c.name); + + const compressionConfigurations: VectorSearchCompressionConfiguration[] = [ + { + name: getUniqueName("vector-search-compression-configuration"), + kind: "scalarQuantization", + parameters: { quantizedDataType: "int8" }, + rerankWithOriginalVectors: true, + }, + ]; + const [scalarQuantizationCompressionConfigurationName] = compressionConfigurations.map( + (c) => c.name, + ); + + const vectorSearchProfiles = [ + { + name: getUniqueName("vector-search-profile"), + vectorizer: azureOpenAiVectorizerName, + algorithmConfigurationName: hnswAlgorithmConfigurationName, + }, + { + name: getUniqueName("vector-search-profile"), + vectorizer: azureOpenAiVectorizerName, + algorithmConfigurationName: exhaustiveKnnAlgorithmConfigurationName, + compressionConfigurationName: scalarQuantizationCompressionConfigurationName, + }, + ]; + const [azureOpenAiVectorSearchProfileName, azureOpenAiCompressedVectorSearchProfileName] = + vectorSearchProfiles.map((p) => p.name); + + const vectorFields: SearchField[] = [ + { + type: "Collection(Edm.Single)", + name: "vectorDescription", + searchable: true, + vectorSearchDimensions: 1536, + hidden: true, + vectorSearchProfileName: azureOpenAiVectorSearchProfileName, + }, + { + type: "Collection(Edm.Half)", + name: "compressedVectorDescription", + searchable: true, + hidden: true, + vectorSearchDimensions: 1536, + vectorSearchProfileName: azureOpenAiCompressedVectorSearchProfileName, + stored: false, + }, + ]; + + const fields: SearchField[] = [ + { + type: "Edm.String", + name: "hotelId", + key: true, + filterable: true, + sortable: true, + }, + { + type: "Edm.String", + name: "hotelName", + searchable: true, + filterable: true, + sortable: true, + }, + { + type: "Edm.String", + name: "description", + searchable: true, + analyzerName: KnownAnalyzerNames.EnLucene, + }, + { + type: "Edm.String", + name: "descriptionFr", + searchable: true, + analyzerName: KnownAnalyzerNames.FrLucene, + }, + { + type: "Edm.String", + name: "category", + searchable: true, + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Collection(Edm.String)", + name: "tags", + searchable: true, + filterable: true, + facetable: true, + }, + { + type: "Edm.Boolean", + name: "parkingIncluded", + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.Boolean", + name: "smokingAllowed", + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.DateTimeOffset", + name: "lastRenovationDate", + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.Double", + name: "rating", + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.GeographyPoint", + name: "location", + filterable: true, + sortable: true, + }, + { + type: "Edm.ComplexType", + name: "address", + fields: [ + { + type: "Edm.String", + name: "streetAddress", + searchable: true, + }, + { + type: "Edm.String", + name: "city", + searchable: true, + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.String", + name: "stateProvince", + searchable: true, + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.String", + name: "country", + searchable: true, + filterable: true, + sortable: true, + facetable: true, + }, + { + type: "Edm.String", + name: "postalCode", + searchable: true, + filterable: true, + sortable: true, + facetable: true, + }, + ], + }, + { + type: "Collection(Edm.ComplexType)", + name: "rooms", + fields: [ + { + type: "Edm.String", + name: "description", + searchable: true, + analyzerName: KnownAnalyzerNames.EnLucene, + }, + { + type: "Edm.String", + name: "descriptionFr", + searchable: true, + analyzerName: KnownAnalyzerNames.FrLucene, + }, + { + type: "Edm.String", + name: "type", + searchable: true, + filterable: true, + facetable: true, + }, + { + type: "Edm.Double", + name: "baseRate", + filterable: true, + facetable: true, + }, + { + type: "Edm.String", + name: "bedOptions", + searchable: true, + filterable: true, + facetable: true, + }, + { + type: "Edm.Int32", + name: "sleepsCount", + filterable: true, + facetable: true, + }, + { + type: "Edm.Boolean", + name: "smokingAllowed", + filterable: true, + facetable: true, + }, + { + type: "Collection(Edm.String)", + name: "tags", + searchable: true, + filterable: true, + facetable: true, + }, + ], + }, + ...vectorFields, + ]; const hotelIndex: SearchIndex = { name, - fields: [ - { - type: "Edm.String", - name: "hotelId", - key: true, - filterable: true, - sortable: true, - }, - { - type: "Edm.String", - name: "hotelName", - searchable: true, - filterable: true, - sortable: true, - }, - { - type: "Edm.String", - name: "description", - searchable: true, - analyzerName: KnownAnalyzerNames.EnLucene, - }, - { - type: "Edm.String", - name: "descriptionFr", - searchable: true, - analyzerName: KnownAnalyzerNames.FrLucene, - }, - { - type: "Edm.String", - name: "category", - searchable: true, - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Collection(Edm.String)", - name: "tags", - searchable: true, - filterable: true, - facetable: true, - }, - { - type: "Edm.Boolean", - name: "parkingIncluded", - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.Boolean", - name: "smokingAllowed", - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.DateTimeOffset", - name: "lastRenovationDate", - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.Double", - name: "rating", - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.GeographyPoint", - name: "location", - filterable: true, - sortable: true, - }, - { - type: "Edm.ComplexType", - name: "address", - fields: [ - { - type: "Edm.String", - name: "streetAddress", - searchable: true, - }, - { - type: "Edm.String", - name: "city", - searchable: true, - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.String", - name: "stateProvince", - searchable: true, - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.String", - name: "country", - searchable: true, - filterable: true, - sortable: true, - facetable: true, - }, - { - type: "Edm.String", - name: "postalCode", - searchable: true, - filterable: true, - sortable: true, - facetable: true, - }, - ], - }, - { - type: "Collection(Edm.ComplexType)", - name: "rooms", - fields: [ - { - type: "Edm.String", - name: "description", - searchable: true, - analyzerName: KnownAnalyzerNames.EnLucene, - }, - { - type: "Edm.String", - name: "descriptionFr", - searchable: true, - analyzerName: KnownAnalyzerNames.FrLucene, - }, - { - type: "Edm.String", - name: "type", - searchable: true, - filterable: true, - facetable: true, - }, - { - type: "Edm.Double", - name: "baseRate", - filterable: true, - facetable: true, - }, - { - type: "Edm.String", - name: "bedOptions", - searchable: true, - filterable: true, - facetable: true, - }, - { - type: "Edm.Int32", - name: "sleepsCount", - filterable: true, - facetable: true, - }, - { - type: "Edm.Boolean", - name: "smokingAllowed", - filterable: true, - facetable: true, - }, - { - type: "Collection(Edm.String)", - name: "tags", - searchable: true, - filterable: true, - facetable: true, - }, - ], - }, - { - type: "Collection(Edm.Single)", - name: "vectorDescription", - searchable: true, - vectorSearchDimensions: 1536, - hidden: true, - vectorSearchProfileName, - }, - { - type: "Collection(Edm.Half)", - name: "compressedVectorDescription", - searchable: true, - hidden: true, - vectorSearchDimensions: 1536, - vectorSearchProfileName: compressedVectorSearchProfileName, - stored: false, - }, - ], + fields, suggesters: [ { name: "sg", @@ -255,54 +319,15 @@ export async function createIndex( allowedOrigins: ["*"], }, vectorSearch: { - algorithms: [ - { - name: algorithmConfigurationName, - kind: "hnsw", - parameters: { - metric: "dotProduct", - }, - }, - ], - vectorizers: serviceVersion.includes("Preview") - ? [ - { - kind: "azureOpenAI", - name: vectorizerName, - azureOpenAIParameters: { - apiKey: env.AZURE_OPENAI_KEY, - deploymentId: env.AZURE_OPENAI_DEPLOYMENT_NAME, - resourceUri: env.AZURE_OPENAI_ENDPOINT, - }, - }, - ] - : undefined, - compressions: [ - { - name: compressionConfigurationName, - kind: "scalarQuantization", - parameters: { quantizedDataType: "int8" }, - rerankWithOriginalVectors: true, - }, - ], - profiles: [ - { - name: vectorSearchProfileName, - vectorizer: serviceVersion.includes("Preview") ? vectorizerName : undefined, - algorithmConfigurationName, - }, - { - name: compressedVectorSearchProfileName, - vectorizer: serviceVersion.includes("Preview") ? vectorizerName : undefined, - algorithmConfigurationName, - compressionConfigurationName, - }, - ], + algorithms: algorithmConfigurations, + vectorizers, + compressions: compressionConfigurations, + profiles: vectorSearchProfiles, }, semanticSearch: { configurations: [ { - name: "semantic-configuration-name", + name: "semantic-configuration", prioritizedFields: { titleField: { name: "hotelName" }, contentFields: [{ name: "description" }],