Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
在本快速入门中,你将使用 .NET 的 Azure AI Search 客户端库来创建、加载,并查询向量索引。 .NET客户端库提供对索引操作的 REST API 的抽象。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
.NET 8 或更高版本。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-dotnet-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-dotnet-samples/quickstart-vector-search code .在
VectorSearchCreatePopulateIndex/appsettings.json中,将占位符值Endpoint替换为在 Get endpoint 中获取到的 URL。请对
VectorSearchExamples/appsettings.json重复上一步。若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login
运行代码
运行第一个项目以创建并填充索引。
cd VectorSearchCreatePopulateIndex dotnet run在
VectorSearchExamples/Program.cs中,取消注释要运行的查询方法。运行第二个项目,以执行这些查询并针对索引进行操作。
cd ..\VectorSearchExamples dotnet run
输出
第一个项目的输出包括确认索引创建和成功上传文档。
Creating or updating index 'hotels-vector-quickstart'...
Index 'hotels-vector-quickstart' updated.
Key: 1, Succeeded: True
Key: 2, Succeeded: True
Key: 3, Succeeded: True
Key: 4, Succeeded: True
Key: 48, Succeeded: True
Key: 49, Succeeded: True
Key: 13, Succeeded: True
第二个项目的输出显示每种已启用查询方法的搜索结果。 以下示例显示了单个矢量搜索结果。
Single Vector Search Results:
Score: 0.6605852, HotelId: 48, HotelName: Nordick's Valley Motel
Score: 0.6333684, HotelId: 13, HotelName: Luxury Lion Resort
Score: 0.605672, HotelId: 4, HotelName: Sublime Palace Hotel
Score: 0.6026341, HotelId: 49, HotelName: Swirling Currents Hotel
Score: 0.57902366, HotelId: 2, HotelName: Old Century Hotel
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。 以下代码 VectorSearchCreatePopulateIndex/Program.cs 创建索引架构,包括向量字段 DescriptionVector。
static async Task CreateSearchIndex(string indexName, SearchIndexClient indexClient)
{
var addressField = new ComplexField("Address");
addressField.Fields.Add(new SearchableField("StreetAddress") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft });
addressField.Fields.Add(new SearchableField("City") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true });
addressField.Fields.Add(new SearchableField("StateProvince") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true });
addressField.Fields.Add(new SearchableField("PostalCode") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true });
addressField.Fields.Add(new SearchableField("Country") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true });
var allFields = new List<SearchField>()
{
new SimpleField("HotelId", SearchFieldDataType.String) { IsKey = true, IsFacetable = true, IsFilterable = true },
new SearchableField("HotelName") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft },
new SearchableField("Description") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft },
new VectorSearchField("DescriptionVector", 1536, "my-vector-profile"),
new SearchableField("Category") { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true },
new SearchableField("Tags", collection: true) { AnalyzerName = LexicalAnalyzerName.EnMicrosoft, IsFacetable = true, IsFilterable = true },
new SimpleField("ParkingIncluded", SearchFieldDataType.Boolean) { IsFacetable = true, IsFilterable = true },
new SimpleField("LastRenovationDate", SearchFieldDataType.DateTimeOffset) { IsSortable = true },
new SimpleField("Rating", SearchFieldDataType.Double) { IsFacetable = true, IsFilterable = true, IsSortable = true },
addressField,
new SimpleField("Location", SearchFieldDataType.GeographyPoint) { IsFilterable = true, IsSortable = true },
};
// Create the suggester configuration
var suggester = new SearchSuggester("sg", new[] { "Address/City", "Address/Country" });
// Create the semantic search
var semanticSearch = new SemanticSearch()
{
Configurations =
{
new SemanticConfiguration(
name: "semantic-config",
prioritizedFields: new SemanticPrioritizedFields
{
TitleField = new SemanticField("HotelName"),
KeywordsFields = { new SemanticField("Category") },
ContentFields = { new SemanticField("Description") }
})
}
};
// Add vector search configuration
var vectorSearch = new VectorSearch();
vectorSearch.Algorithms.Add(new HnswAlgorithmConfiguration(name: "my-hnsw-vector-config-1"));
vectorSearch.Profiles.Add(new VectorSearchProfile(name: "my-vector-profile", algorithmConfigurationName: "my-hnsw-vector-config-1"));
var definition = new SearchIndex(indexName)
{
Fields = allFields,
Suggesters = { suggester },
VectorSearch = vectorSearch,
SemanticSearch = semanticSearch
};
// Create or update the index
Console.WriteLine($"Creating or updating index '{indexName}'...");
var result = await indexClient.CreateOrUpdateIndexAsync(definition);
Console.WriteLine($"Index '{result.Value.Name}' updated.");
Console.WriteLine();
}
要点:
通过创建字段列表来定义索引。
此特定索引支持多个搜索功能:
第二个参数
VectorSearchField指定vectorSearchDimensions,它必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。配置
VectorSearch定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为了简化流程,本快速入门指南提供了包含预计算向量的示例酒店文档。 在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
以下代码将文档从 HotelData.json 上传到 搜索服务。
static async Task UploadDocs(SearchClient searchClient)
{
var jsonPath = Path.Combine(Directory.GetCurrentDirectory(), "HotelData.json");
// Read and parse hotel data
var json = await File.ReadAllTextAsync(jsonPath);
List<Hotel> hotels = new List<Hotel>();
try
{
using var doc = JsonDocument.Parse(json);
if (doc.RootElement.ValueKind != JsonValueKind.Array)
{
Console.WriteLine("HotelData.json root is not a JSON array.");
}
// Deserialize all hotel objects
hotels = doc.RootElement.EnumerateArray()
.Select(e => JsonSerializer.Deserialize<Hotel>(e.GetRawText()))
.Where(h => h != null)
.ToList();
}
catch (JsonException ex)
{
Console.WriteLine($"Failed to parse HotelData.json: {ex.Message}");
}
try
{
// Upload hotel documents to Azure Search
var result = await searchClient.UploadDocumentsAsync(hotels);
foreach (var r in result.Value.Results)
{
Console.WriteLine($"Key: {r.Key}, Succeeded: {r.Succeeded}");
}
}
catch (Exception ex)
{
Console.WriteLine("Failed to upload documents: " + ex);
}
}
代码通过 SearchClient(Azure.Search.Documents 包提供的主要对象)与 Azure AI Search service中托管的特定搜索索引进行交互。
SearchClient提供对索引操作的访问,例如:
数据引入:
UploadDocuments()、、MergeDocuments()DeleteDocuments()搜索操作:
Search()、Autocomplete()、Suggest()
查询索引
中的 VectorSearchExamples 查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
该方法 SearchSingleVector 演示了一个基本方案,其中你想要查找与矢量查询字符串非常匹配的文档说明。
VectorizedQuery 配置矢量搜索:
-
KNearestNeighborsCount根据矢量相似性限制返回的结果数。 -
Fields指定要搜索的向量字段。
public static async Task SearchSingleVector(SearchClient searchClient, ReadOnlyMemory<float> precalculatedVector)
{
SearchResults<Hotel> response = await searchClient.SearchAsync<Hotel>(
new SearchOptions
{
VectorSearch = new()
{
Queries = { new VectorizedQuery(precalculatedVector) { KNearestNeighborsCount = 5, Fields = { "DescriptionVector" } } }
},
Select = { "HotelId", "HotelName", "Description", "Category", "Tags" },
});
Console.WriteLine($"Single Vector Search Results:");
await foreach (SearchResult<Hotel> result in response.GetResultsAsync())
{
Hotel doc = result.Document;
Console.WriteLine($"Score: {result.Score}, HotelId: {doc.HotelId}, HotelName: {doc.HotelName}");
}
Console.WriteLine();
}
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。 此方法在字段 SearchSingleVectorWithFilter 处进行筛选,以过滤掉不提供免费 Wi-Fi 的酒店。
public static async Task SearchSingleVectorWithFilter(SearchClient searchClient, ReadOnlyMemory<float> precalculatedVector)
{
SearchResults<Hotel> responseWithFilter = await searchClient.SearchAsync<Hotel>(
new SearchOptions
{
VectorSearch = new()
{
Queries = { new VectorizedQuery(precalculatedVector) { KNearestNeighborsCount = 5, Fields = { "DescriptionVector" } } }
},
Filter = "Tags/any(tag: tag eq 'free wifi')",
Select = { "HotelId", "HotelName", "Description", "Category", "Tags" }
});
Console.WriteLine($"Single Vector Search With Filter Results:");
await foreach (SearchResult<Hotel> result in responseWithFilter.GetResultsAsync())
{
Hotel doc = result.Document;
Console.WriteLine($"Score: {result.Score}, HotelId: {doc.HotelId}, HotelName: {doc.HotelName}, Tags: {string.Join(String.Empty, doc.Tags)}");
}
Console.WriteLine();
}
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。 该SingleSearchWithGeoFilter 方法指定一个地理点(例如华盛顿特区,使用经度和纬度坐标),并返回在300公里范围内的酒店。 默认情况下,筛选器在矢量搜索后运行。
public static async Task SingleSearchWithGeoFilter(SearchClient searchClient, ReadOnlyMemory<float> precalculatedVector)
{
SearchResults<Hotel> responseWithGeoFilter = await searchClient.SearchAsync<Hotel>(
new SearchOptions
{
VectorSearch = new()
{
Queries = { new VectorizedQuery(precalculatedVector) { KNearestNeighborsCount = 5, Fields = { "DescriptionVector" } } }
},
Filter = "geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300",
Select = { "HotelId", "HotelName", "Description", "Address", "Category", "Tags" },
Facets = { "Address/StateProvince" },
});
Console.WriteLine($"Vector query with a geo filter:");
await foreach (SearchResult<Hotel> result in responseWithGeoFilter.GetResultsAsync())
{
Hotel doc = result.Document;
Console.WriteLine($"HotelId: {doc.HotelId}");
Console.WriteLine($"HotelName: {doc.HotelName}");
Console.WriteLine($"Score: {result.Score}");
Console.WriteLine($"City/State: {doc.Address.City}/{doc.Address.StateProvince}");
Console.WriteLine($"Description: {doc.Description}");
Console.WriteLine();
}
Console.WriteLine();
}
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。
SearchHybridVectorAndText 方法同时运行这两种查询类型,然后使用倒数排名融合 (RRF) 将结果合并到统一排名中。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
public static async Task<SearchResults<Hotel>> SearchHybridVectorAndText(SearchClient searchClient, ReadOnlyMemory<float> precalculatedVector)
{
SearchResults<Hotel> responseWithFilter = await searchClient.SearchAsync<Hotel>(
"historic hotel walk to restaurants and shopping",
new SearchOptions
{
VectorSearch = new()
{
Queries = { new VectorizedQuery(precalculatedVector) { KNearestNeighborsCount = 5, Fields = { "DescriptionVector" } } }
},
Select = { "HotelId", "HotelName", "Description", "Category", "Tags" },
Size = 5,
});
Console.WriteLine($"Hybrid search results:");
await foreach (SearchResult<Hotel> result in responseWithFilter.GetResultsAsync())
{
Hotel doc = result.Document;
Console.WriteLine($"Score: {result.Score}");
Console.WriteLine($"HotelId: {doc.HotelId}");
Console.WriteLine($"HotelName: {doc.HotelName}");
Console.WriteLine($"Description: {doc.Description}");
Console.WriteLine($"Category: {doc.Category}");
Console.WriteLine($"Tags: {string.Join(String.Empty, doc.Tags)}");
Console.WriteLine();
}
Console.WriteLine();
return responseWithFilter;
}
语义混合搜索
SearchHybridVectorAndSemantic 方法演示了 语义排名,该方法根据语言理解重新排列结果。
public static async Task SearchHybridVectorAndSemantic(SearchClient searchClient, ReadOnlyMemory<float> precalculatedVector)
{
SearchResults<Hotel> responseWithFilter = await searchClient.SearchAsync<Hotel>(
"historic hotel walk to restaurants and shopping",
new SearchOptions
{
IncludeTotalCount = true,
VectorSearch = new()
{
Queries = { new VectorizedQuery(precalculatedVector) { KNearestNeighborsCount = 5, Fields = { "DescriptionVector" } } }
},
Select = { "HotelId", "HotelName", "Description", "Category", "Tags" },
SemanticSearch = new SemanticSearchOptions
{
SemanticConfigurationName = "semantic-config"
},
QueryType = SearchQueryType.Semantic,
Size = 5
});
Console.WriteLine($"Hybrid search results:");
await foreach (SearchResult<Hotel> result in responseWithFilter.GetResultsAsync())
{
Hotel doc = result.Document;
Console.WriteLine($"Score: {result.Score}");
Console.WriteLine($"HotelId: {doc.HotelId}");
Console.WriteLine($"HotelName: {doc.HotelName}");
Console.WriteLine($"Description: {doc.Description}");
Console.WriteLine($"Category: {doc.Category}");
Console.WriteLine();
}
Console.WriteLine();
}
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
实际结果包含更多详细信息,包括语义说明和突出显示。 本快速入门修改了结果以提高可读性。 若要获取响应的完整结构,请使用 REST 运行请求。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
在本快速入门中,你将使用适用于 Java 的 Azure AI Search 客户端库创建、加载和查询 vector index。 Java 客户端库提供用于索引操作的 REST API 抽象。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-java-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-java-samples/quickstart-vector-search code .在
src/main/resources/application.properties中,将占位符值azure.search.endpoint替换为在 Get endpoint 中获取到的 URL。安装依赖项。
mvn clean dependency:copy-dependencies生成完成后,应会在project目录中看到一个
target/dependency文件夹。若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login
运行代码
创建矢量索引。
mvn compile exec:java "-Dexec.mainClass=com.example.search.CreateIndex"加载包含预计算嵌入的文档。
mvn compile exec:java "-Dexec.mainClass=com.example.search.UploadDocuments"运行矢量搜索查询。
mvn compile exec:java "-Dexec.mainClass=com.example.search.SearchSingle"(可选)运行其他查询变体。
mvn compile exec:java "-Dexec.mainClass=com.example.search.SearchSingleWithFilter" mvn compile exec:java "-Dexec.mainClass=com.example.search.SearchSingleWithFilterGeo" mvn compile exec:java "-Dexec.mainClass=com.example.search.SearchHybrid" mvn compile exec:java "-Dexec.mainClass=com.example.search.SearchSemanticHybrid"
输出
CreateIndex.java 的输出显示了索引名称和确认信息。
Using Azure Search endpoint: https://<search-service-name>.search.azure.cn
Using Azure Search index: hotels-vector-quickstart
Creating index...
hotels-vector-quickstart created
输出 UploadDocuments.java 显示每个索引文档的成功状态。
Uploading documents...
Key: 1, Succeeded: true, ErrorMessage: none
Key: 2, Succeeded: true, ErrorMessage: none
Key: 3, Succeeded: true, ErrorMessage: none
Key: 4, Succeeded: true, ErrorMessage: none
Key: 48, Succeeded: true, ErrorMessage: none
Key: 49, Succeeded: true, ErrorMessage: none
Key: 13, Succeeded: true, ErrorMessage: none
Waiting for indexing... Current count: 0
All documents indexed successfully.
SearchSingle.java 的输出显示了按相似性分数排列的矢量搜索结果。
Single Vector search found 5
- HotelId: 48, HotelName: Nordick's Valley Motel, Tags: ["continental breakfast","air conditioning","free wifi"], Score 0.6605852
- HotelId: 13, HotelName: Luxury Lion Resort, Tags: ["bar","concierge","restaurant"], Score 0.6333684
- HotelId: 4, HotelName: Sublime Palace Hotel, Tags: ["concierge","view","air conditioning"], Score 0.605672
- HotelId: 49, HotelName: Swirling Currents Hotel, Tags: ["air conditioning","laundry service","24-hour front desk service"], Score 0.6026341
- HotelId: 2, HotelName: Old Century Hotel, Tags: ["pool","free wifi","air conditioning","concierge"], Score 0.57902366
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。 以下代码 CreateIndex.java 创建索引架构,包括向量字段 DescriptionVector。
// Define fields
List<SearchField> fields = Arrays.asList(
new SearchField("HotelId", SearchFieldDataType.STRING)
.setKey(true)
.setFilterable(true),
new SearchField("HotelName", SearchFieldDataType.STRING)
.setSortable(true)
.setSearchable(true),
new SearchField("Description", SearchFieldDataType.STRING)
.setSearchable(true),
new SearchField("DescriptionVector",
SearchFieldDataType.collection(SearchFieldDataType.SINGLE))
.setSearchable(true)
.setVectorSearchDimensions(1536)
.setVectorSearchProfileName("my-vector-profile"),
new SearchField("Category", SearchFieldDataType.STRING)
.setSortable(true)
.setFilterable(true)
.setFacetable(true)
.setSearchable(true),
new SearchField("Tags", SearchFieldDataType.collection(
SearchFieldDataType.STRING))
.setSearchable(true)
.setFilterable(true)
.setFacetable(true),
// Additional fields: ParkingIncluded, LastRenovationDate, Rating, Address, Location
);
var searchIndex = new SearchIndex(indexName, fields);
// Define vector search configuration
var hnswParams = new HnswParameters()
.setM(16)
.setEfConstruction(200)
.setEfSearch(128);
var hnsw = new HnswAlgorithmConfiguration("hnsw-vector-config");
hnsw.setParameters(hnswParams);
var vectorProfile = new VectorSearchProfile(
"my-vector-profile",
"hnsw-vector-config");
var vectorSearch = new VectorSearch()
.setAlgorithms(Arrays.asList(hnsw))
.setProfiles(Arrays.asList(vectorProfile));
searchIndex.setVectorSearch(vectorSearch);
// Define semantic configuration
var prioritizedFields = new SemanticPrioritizedFields()
.setTitleField(new SemanticField("HotelName"))
.setContentFields(Arrays.asList(new SemanticField("Description")))
.setKeywordsFields(Arrays.asList(new SemanticField("Category")));
var semanticConfig = new SemanticConfiguration(
"semantic-config",
prioritizedFields);
var semanticSearch = new SemanticSearch()
.setConfigurations(Arrays.asList(semanticConfig));
searchIndex.setSemanticSearch(semanticSearch);
// Define suggesters
var suggester = new SearchSuggester("sg", Arrays.asList("HotelName"));
searchIndex.setSuggesters(Arrays.asList(suggester));
// Create the search index
SearchIndex result = searchIndexClient.createOrUpdateIndex(searchIndex);
要点:
通过创建字段列表来定义索引。
此特定索引支持多个搜索功能:
该值
setVectorSearchDimensions()必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。配置
VectorSearch定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为了简化流程,本快速入门指南提供了包含预计算向量的示例酒店文档。 在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
UploadDocuments.java中的以下代码将文档上传到您的搜索服务。
// Documents contain hotel data with 1536-dimension vectors for DescriptionVector
static final List<Map<String, Object>> DOCUMENTS = Arrays.asList(
new HashMap<>() {{
put("@search.action", "mergeOrUpload");
put("HotelId", "1");
put("HotelName", "Stay-Kay City Hotel");
put("Description", "This classic hotel is fully-refurbished...");
put("DescriptionVector", Arrays.asList(/* 1536 float values */));
put("Category", "Boutique");
put("Tags", Arrays.asList("view", "air conditioning", "concierge"));
// Additional fields...
}}
// Additional hotel documents
);
// Upload documents to the index
IndexDocumentsResult result = searchClient.uploadDocuments(DOCUMENTS);
for (IndexingResult r : result.getResults()) {
System.out.println("Key: %s, Succeeded: %s".formatted(r.getKey(), r.isSucceeded()));
}
代码通过 SearchClient(azure-search-documents 包提供的主要对象)与 Azure AI Search service中托管的特定搜索索引进行交互。
SearchClient 提供对操作的访问,例如:
数据引入:
uploadDocuments、、mergeDocumentsdeleteDocuments搜索操作:
search、autocomplete、suggest
查询索引
搜索文件中的查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
SearchSingle.java 演示了一个基本方案,其中你想要查找与矢量查询字符串非常匹配的文档说明。
VectorizedQuery 配置矢量搜索:
-
setKNearestNeighborsCount()根据矢量相似性限制返回的结果数。 -
setFields()指定要搜索的向量字段。
var vectorQuery = new VectorizedQuery(QueryVector.getVectorList())
.setKNearestNeighborsCount(5)
.setFields("DescriptionVector")
.setExhaustive(true);
var vectorSearchOptions = new VectorSearchOptions()
.setQueries(vectorQuery)
.setFilterMode(VectorFilterMode.POST_FILTER);
var searchOptions = new SearchOptions()
.setTop(7)
.setIncludeTotalCount(true)
.setSelect("HotelId", "HotelName", "Description", "Category", "Tags")
.setVectorSearchOptions(vectorSearchOptions);
var results = searchClient.search("*", searchOptions, Context.NONE);
for (SearchResult result : results) {
SearchDocument document = result.getDocument(SearchDocument.class);
System.out.println("HotelId: %s, HotelName: %s, Score: %s".formatted(
document.get("HotelId"), document.get("HotelName"), result.getScore()));
}
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。
SearchSingleWithFilter.java 字段上的 Tags 用于过滤掉不提供免费 Wi-Fi 的酒店。
var vectorQuery = new VectorizedQuery(QueryVector.getVectorList())
.setKNearestNeighborsCount(5)
.setFields("DescriptionVector")
.setExhaustive(true);
var vectorSearchOptions = new VectorSearchOptions()
.setQueries(vectorQuery)
.setFilterMode(VectorFilterMode.POST_FILTER);
// Add filter for "free wifi" tag
var searchOptions = new SearchOptions()
.setTop(7)
.setIncludeTotalCount(true)
.setSelect("HotelId", "HotelName", "Description", "Category", "Tags")
.setFilter("Tags/any(tag: tag eq 'free wifi')")
.setVectorSearchOptions(vectorSearchOptions);
var results = searchClient.search("*", searchOptions, Context.NONE);
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。
SearchSingleWithGeoFilter.java 指定地理点(华盛顿特区,使用经度和纬度坐标)并在 300 公里内返回酒店。 在setFilterMode上调用的VectorSearchOptions方法确定筛选器何时运行。 在这种情况下,POST_FILTER 在矢量搜索后运行筛选器。
var searchOptions = new SearchOptions()
.setTop(5)
.setIncludeTotalCount(true)
.setSelect("HotelId", "HotelName", "Category", "Description",
"Address/City", "Address/StateProvince")
.setFacets("Address/StateProvince")
.setFilter("geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300")
.setVectorSearchOptions(vectorSearchOptions);
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。
SearchHybrid.java 同时运行这两种查询类型,然后使用倒数排名融合(RRF)将结果合并到统一排名中。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
var vectorQuery = new VectorizedQuery(QueryVector.getVectorList())
.setKNearestNeighborsCount(5)
.setFields("DescriptionVector")
.setExhaustive(true);
var vectorSearchOptions = new VectorSearchOptions()
.setQueries(vectorQuery)
.setFilterMode(VectorFilterMode.POST_FILTER);
var searchOptions = new SearchOptions()
.setTop(5)
.setIncludeTotalCount(true)
.setSelect("HotelId", "HotelName", "Description", "Category", "Tags")
.setVectorSearchOptions(vectorSearchOptions);
// Pass both text query and vector search options
var results = searchClient.search(
"historic hotel walk to restaurants and shopping",
searchOptions, Context.NONE);
语义混合搜索
SearchSemanticHybrid.java演示了语义排序,该排序基于语言理解重新排序结果。
var vectorQuery = new VectorizedQuery(QueryVector.getVectorList())
.setKNearestNeighborsCount(5)
.setFields("DescriptionVector")
.setExhaustive(true);
var vectorSearchOptions = new VectorSearchOptions()
.setQueries(vectorQuery)
.setFilterMode(VectorFilterMode.POST_FILTER);
SemanticSearchOptions semanticSearchOptions = new SemanticSearchOptions()
.setSemanticConfigurationName("semantic-config");
var searchOptions = new SearchOptions()
.setTop(5)
.setIncludeTotalCount(true)
.setSelect("HotelId", "HotelName", "Category", "Description")
.setQueryType(QueryType.SEMANTIC)
.setSemanticSearchOptions(semanticSearchOptions)
.setVectorSearchOptions(vectorSearchOptions);
var results = searchClient.search(
"historic hotel walk to restaurants and shopping",
searchOptions, Context.NONE);
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
实际结果包含更多详细信息,包括语义说明和突出显示。 本快速入门修改了结果以提高可读性。 若要获取响应的完整结构,请使用 REST 运行请求。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
否则,请运行以下命令以删除在本快速入门中创建的索引。
mvn compile exec:java "-Dexec.mainClass=com.example.search.DeleteIndex"
在本快速入门中,你将使用适用于 JavaScript 的 Azure AI Search 客户端库创建、加载和查询 vector index。 JavaScript 客户端库为索引操作提供 REST API 的抽象。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
Node.js 20 LTS 或更高版本。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-javascript-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-javascript-samples/quickstart-vector-js code .在
sample.env中,将占位符值AZURE_SEARCH_ENDPOINT替换为在 Get endpoint 中获取到的 URL。将
sample.env重命名为.env。mv sample.env .env安装依赖项。
npm install安装完成后,应会在project目录中看到一个
node_modules文件夹。若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login
运行代码
创建矢量索引。
node -r dotenv/config src/createIndex.js加载包含预计算嵌入的文档。
node -r dotenv/config src/uploadDocuments.js运行矢量搜索查询。
node -r dotenv/config src/searchSingle.js(可选)运行其他查询变体。
node -r dotenv/config src/searchSingleWithFilter.js node -r dotenv/config src/searchSingleWithFilterGeo.js node -r dotenv/config src/searchHybrid.js node -r dotenv/config src/searchSemanticHybrid.js
输出
createIndex.js 的输出显示了索引名称和确认信息。
Using Azure Search endpoint: https://<search-service-name>.search.azure.cn
Using Azure Search index: hotels-vector-quickstart
Creating index...
hotels-vector-quickstart created
输出 uploadDocuments.js 显示每个索引文档的成功状态。
Uploading documents...
Key: 1, Succeeded: true, ErrorMessage: none
Key: 2, Succeeded: true, ErrorMessage: none
Key: 3, Succeeded: true, ErrorMessage: none
Key: 4, Succeeded: true, ErrorMessage: none
Key: 48, Succeeded: true, ErrorMessage: none
Key: 49, Succeeded: true, ErrorMessage: none
Key: 13, Succeeded: true, ErrorMessage: none
Waiting for indexing... Current count: 0
All documents indexed successfully.
searchSingle.js 的输出显示了按相似性分数排列的矢量搜索结果。
Single Vector search found 5
- HotelId: 48, HotelName: Nordick's Valley Motel, Tags: ["continental breakfast","air conditioning","free wifi"], Score 0.6605852
- HotelId: 13, HotelName: Luxury Lion Resort, Tags: ["bar","concierge","restaurant"], Score 0.6333684
- HotelId: 4, HotelName: Sublime Palace Hotel, Tags: ["concierge","view","air conditioning"], Score 0.605672
- HotelId: 49, HotelName: Swirling Currents Hotel, Tags: ["air conditioning","laundry service","24-hour front desk service"], Score 0.6026341
- HotelId: 2, HotelName: Old Century Hotel, Tags: ["pool","free wifi","air conditioning","concierge"], Score 0.57902366
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。 以下代码 createIndex.js 创建索引架构,包括向量字段 DescriptionVector。
const searchFields = [
{ name: "HotelId", type: "Edm.String", key: true, sortable: true, filterable: true, facetable: true },
{ name: "HotelName", type: "Edm.String", searchable: true, filterable: true },
{ name: "Description", type: "Edm.String", searchable: true },
{
name: "DescriptionVector",
type: "Collection(Edm.Single)",
searchable: true,
vectorSearchDimensions: 1536,
vectorSearchProfileName: "vector-profile"
},
{ name: "Category", type: "Edm.String", filterable: true, facetable: true },
{ name: "Tags", type: "Collection(Edm.String)", filterable: true },
// Additional fields: ParkingIncluded, LastRenovationDate, Rating, Address, Location
];
const vectorSearch = {
profiles: [
{
name: "vector-profile",
algorithmConfigurationName: "vector-search-algorithm"
}
],
algorithms: [
{
name: "vector-search-algorithm",
kind: "hnsw",
parameters: { m: 4, efConstruction: 400, efSearch: 1000, metric: "cosine" }
}
]
};
const semanticSearch = {
configurations: [
{
name: "semantic-config",
prioritizedFields: {
contentFields: [{ name: "Description" }],
keywordsFields: [{ name: "Category" }],
titleField: { name: "HotelName" }
}
}
]
};
const searchIndex = {
name: indexName,
fields: searchFields,
vectorSearch: vectorSearch,
semanticSearch: semanticSearch,
suggesters: [{ name: "sg", searchMode: "analyzingInfixMatching", sourceFields: ["HotelName"] }]
};
const result = await indexClient.createOrUpdateIndex(searchIndex);
要点:
通过创建字段列表来定义索引。
此特定索引支持多个搜索功能:
该
vectorSearchDimensions属性必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。配置
vectorSearch定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为了简化流程,本快速入门指南提供了包含预计算向量的示例酒店文档。 在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
uploadDocuments.js中的以下代码将文档上传到您的搜索服务。
const DOCUMENTS = [
// Array of hotel documents with embedded 1536-dimension vectors
// Each document contains: HotelId, HotelName, Description, DescriptionVector,
// Category, Tags, ParkingIncluded, LastRenovationDate, Rating, Address, Location
];
const searchClient = new SearchClient(searchEndpoint, indexName, credential);
const result = await searchClient.uploadDocuments(DOCUMENTS);
for (const r of result.results) {
console.log(`Key: ${r.key}, Succeeded: ${r.succeeded}`);
}
代码通过 SearchClient(@azure/search-documents 包提供的主要对象)与 Azure AI Search service中托管的特定搜索索引进行交互。
SearchClient提供对索引操作的访问,例如:
数据引入:
uploadDocuments、、mergeDocumentsdeleteDocuments搜索操作:
search、autocomplete、suggest
查询索引
搜索文件中的查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
searchSingle.js 演示了一个基本方案,其中你想要查找与矢量查询字符串非常匹配的文档说明。 该 vectorQuery 对象配置矢量搜索:
-
kNearestNeighborsCount根据矢量相似性限制返回的结果数。 -
fields指定要搜索的向量字段。
const vectorQuery = {
vector: vector,
kNearestNeighborsCount: 5,
fields: ["DescriptionVector"],
kind: "vector",
exhaustive: true
};
const searchOptions = {
top: 7,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"],
includeTotalCount: true,
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const results = await searchClient.search("*", searchOptions);
for await (const result of results.results) {
const doc = result.document;
console.log(`HotelId: ${doc.HotelId}, HotelName: ${doc.HotelName}, Score: ${result.score}`);
}
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。
searchSingleWithFilter.js 字段上的 Tags 用于过滤掉不提供免费 Wi-Fi 的酒店。
const searchOptions = {
top: 7,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"],
includeTotalCount: true,
filter: "Tags/any(tag: tag eq 'free wifi')", // Adding filter for "free wifi" tag
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const results = await searchClient.search("*", searchOptions);
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。
searchSingleWithGeoFilter.js 指定地理点(华盛顿特区,使用经度和纬度坐标)并在 300 公里内返回酒店。 该 filterMode 属性确定筛选器何时运行。 在这种情况下,postFilter 在矢量搜索后运行筛选器。
const searchOptions = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Category", "Description", "Address/City", "Address/StateProvince"],
facets: ["Address/StateProvince"],
filter: "geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300",
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。
searchHybrid.js 同时运行这两种查询类型,然后使用倒数排名融合(RRF)将结果合并到统一排名中。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
const vectorQuery = {
vector: vector,
kNearestNeighborsCount: 5,
fields: ["DescriptionVector"],
kind: "vector",
exhaustive: true
};
const searchOptions = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"],
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
// Use search text for keyword search (hybrid search = vector + keyword)
const searchText = "historic hotel walk to restaurants and shopping";
const results = await searchClient.search(searchText, searchOptions);
语义混合搜索
searchSemanticHybrid.js演示了语义排序,该排序基于语言理解重新排序结果。
const searchOptions = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Category", "Description"],
queryType: "semantic",
semanticSearchOptions: {
configurationName: "semantic-config"
},
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const searchText = "historic hotel walk to restaurants and shopping";
const results = await searchClient.search(searchText, searchOptions);
for await (const result of results.results) {
console.log(`Score: ${result.score}, Re-ranker Score: ${result.rerankerScore}`);
}
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
实际结果包含更多详细信息,包括语义说明和突出显示。 本快速入门修改了结果以提高可读性。 若要获取响应的完整结构,请使用 REST 运行请求。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
否则,请运行以下命令以删除在本快速入门中创建的索引。
node -r dotenv/config src/deleteIndex.js
在本快速入门中,使用适用于 Python 的 Azure AI Search 客户端库创建、加载和查询 vector index。 Python 客户端库为索引操作提供了 REST API 的抽象。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
Python 3.8 或更高版本。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-python-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-python-samples/Quickstart-Vector-Search code .在
sample.env中,将占位符值AZURE_SEARCH_ENDPOINT替换为在 Get endpoint 中获取到的 URL。将
sample.env重命名为.env。mv sample.env .env打开
vector-search-quickstart.ipynb。按 Ctrl+Shift+P,选择 笔记本:选择笔记本内核,然后按照提示创建虚拟环境。 为依赖项选择 requirements.txt 。
完成后,应会在project目录中看到
.venv文件夹。若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login
运行代码
Install packages and set variables运行单元以安装所需的包并加载环境变量。按顺序运行其余单元格,以创建矢量索引、上传文档并运行不同类型的矢量查询。
输出
每个代码单元将输出打印到笔记本。 下面的示例是输出 Single vector search,其中显示了按相似性分数排名的向量搜索结果。
Total results: 7
- HotelId: 48, HotelName: Nordick's Valley Motel, Category: Boutique
- HotelId: 13, HotelName: Luxury Lion Resort, Category: Luxury
- HotelId: 4, HotelName: Sublime Palace Hotel, Category: Boutique
- HotelId: 49, HotelName: Swirling Currents Hotel, Category: Suite
- HotelId: 2, HotelName: Old Century Hotel, Category: Boutique
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。
Create an index笔记本中的单元格创建索引架构,包括向量字段DescriptionVector。
fields = [
SimpleField(name="HotelId", type=SearchFieldDataType.String, key=True, filterable=True),
SearchableField(name="HotelName", type=SearchFieldDataType.String, sortable=True),
SearchableField(name="Description", type=SearchFieldDataType.String),
SearchField(
name="DescriptionVector",
type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
searchable=True,
vector_search_dimensions=1536,
vector_search_profile_name="my-vector-profile"
),
SearchableField(name="Category", type=SearchFieldDataType.String, sortable=True, filterable=True, facetable=True),
SearchField(name="Tags", type=SearchFieldDataType.Collection(SearchFieldDataType.String), searchable=True, filterable=True, facetable=True),
# Additional fields omitted for brevity
]
要点:
通过创建字段列表来定义索引。 每个字段都是使用定义字段类型和设置的帮助程序方法创建的。
此特定索引支持多个搜索功能:
该
vector_search_dimensions属性必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。配置
VectorSearch定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为了简化流程,本快速入门指南提供了包含预计算向量的示例酒店文档。 在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
Create documents payload和Upload the documents单元格将文档加载到索引中。
documents = [
# List of hotel documents with embedded 1536-dimension vectors
# Each document contains: HotelId, HotelName, Description, DescriptionVector,
# Category, Tags, ParkingIncluded, LastRenovationDate, Rating, Address, Location
]
search_client = SearchClient(
endpoint=search_endpoint,
index_name=index_name,
credential=credential
)
result = search_client.upload_documents(documents=documents)
for r in result:
print(f"Key: {r.key}, Succeeded: {r.succeeded}, ErrorMessage: {r.error_message}")
代码通过 SearchClient(azure-search-documents 包提供的主要对象)与 Azure AI Search service中托管的特定搜索索引进行交互。
SearchClient提供对索引操作的访问,例如:
数据引入:
upload_documents()、、merge_documents()delete_documents()搜索操作:
search()、autocomplete()、suggest()
查询索引
笔记本中的查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
该 Single vector search 单元格演示了一个基本方案,可在其中查找与矢量查询字符串非常匹配的文档说明。
VectorizedQuery 配置矢量搜索:
-
k_nearest_neighbors根据矢量相似性限制返回的结果数。 -
fields指定要搜索的向量字段。
vector_query = VectorizedQuery(
vector=vector,
k_nearest_neighbors=5,
fields="DescriptionVector",
kind="vector",
exhaustive=True
)
results = search_client.search(
vector_queries=[vector_query],
select=["HotelId", "HotelName", "Description", "Category", "Tags"],
top=5,
include_total_count=True
)
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。 字段 Single vector search with filter 上的 Tags 单元格筛选,筛选出任何不提供免费 Wi-Fi 的酒店。
# vector_query omitted for brevity
results = search_client.search(
vector_queries=[vector_query],
filter="Tags/any(tag: tag eq 'free wifi')",
select=["HotelId", "HotelName", "Description", "Category", "Tags"],
top=7,
include_total_count=True
)
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。 该 Single vector search with geo filter 单元格指定一个地理点(华盛顿特区,使用经度和纬度坐标)并返回在300公里范围内的酒店。 该 vector_filter_mode 参数确定筛选器何时运行。 在这种情况下,postFilter 在矢量搜索后运行筛选器。
# vector_query omitted for brevity
results = search_client.search(
include_total_count=True,
top=5,
select=[
"HotelId", "HotelName", "Category", "Description", "Address/City", "Address/StateProvince"
],
facets=["Address/StateProvince"],
filter="geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300",
vector_filter_mode="postFilter",
vector_queries=[vector_query]
)
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。 该 Hybrid search 单元同时运行这两种查询类型,然后使用倒数排名融合(RRF)将结果合并到统一排名中。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
# vector_query omitted for brevity
results = search_client.search(
search_text="historic hotel walk to restaurants and shopping",
vector_queries=[vector_query],
select=["HotelId", "HotelName", "Description", "Category", "Tags"],
top=5,
include_total_count=True
)
语义混合搜索
Semantic hybrid search 单元格演示了 语义排名,该排名基于语言理解重新排序结果。
# vector_query omitted for brevity
results = search_client.search(
search_text="historic hotel walk to restaurants and shopping",
vector_queries=[vector_query],
select=["HotelId", "HotelName", "Category", "Description"],
query_type="semantic",
semantic_configuration_name="my-semantic-config",
top=5,
include_total_count=True
)
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
实际结果包含更多详细信息,包括语义说明和突出显示。 本快速入门修改了结果以提高可读性。 若要获取响应的完整结构,请使用 REST 运行请求。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
否则,可以运行 Clean up 代码单元以删除在本快速入门中创建的索引。
在本快速入门中,你将使用适用于 JavaScript 的 Azure AI Search 客户端库(与 TypeScript 兼容)创建、加载和查询 vector 索引。 JavaScript 客户端库为索引操作提供 REST API 的抽象。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
Node.js 20 LTS 或更高版本来运行已编译的代码。
使用TypeScript 将 TypeScript 编译为 JavaScript。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-javascript-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-javascript-samples/quickstart-vector-ts code .在
sample.env中,将占位符值AZURE_SEARCH_ENDPOINT替换为在 Get endpoint 中获取到的 URL。将
sample.env重命名为.env。mv sample.env .env安装依赖项。
npm install安装完成后,应会在project目录中看到一个
node_modules文件夹。生成 TypeScript 文件。
npm run build若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login
运行代码
创建矢量索引。
node -r dotenv/config dist/createIndex.js加载包含预计算嵌入的文档。
node -r dotenv/config dist/uploadDocuments.js运行矢量搜索查询。
node -r dotenv/config dist/searchSingle.js(可选)运行其他查询变体。
node -r dotenv/config dist/searchSingleWithFilter.js node -r dotenv/config dist/searchSingleWithFilterGeo.js node -r dotenv/config dist/searchHybrid.js node -r dotenv/config dist/searchSemanticHybrid.js注意事项
这些命令从
.js文件夹中运行dist文件,因为你以前使用npm run build将 TypeScript 转为 JavaScript。
输出
createIndex.ts 的输出显示了索引名称和确认信息。
Using Azure Search endpoint: https://<search-service-name>.search.azure.cn
Using index name: hotels-vector-quickstart
Creating index...
hotels-vector-quickstart created
输出 uploadDocuments.ts 显示每个索引文档的成功状态。
Uploading documents...
Key: 1, Succeeded: true, ErrorMessage: none
Key: 2, Succeeded: true, ErrorMessage: none
Key: 3, Succeeded: true, ErrorMessage: none
Key: 4, Succeeded: true, ErrorMessage: none
Key: 48, Succeeded: true, ErrorMessage: none
Key: 49, Succeeded: true, ErrorMessage: none
Key: 13, Succeeded: true, ErrorMessage: none
All documents indexed successfully.
searchSingle.ts 的输出显示了按相似性分数排列的矢量搜索结果。
Single Vector search found 5
- HotelId: 48, HotelName: Nordick's Valley Motel, Tags: ["continental breakfast","air conditioning","free wifi"], Score 0.6605852
- HotelId: 13, HotelName: Luxury Lion Resort, Tags: ["bar","concierge","restaurant"], Score 0.6333684
- HotelId: 4, HotelName: Sublime Palace Hotel, Tags: ["concierge","view","air conditioning"], Score 0.605672
- HotelId: 49, HotelName: Swirling Currents Hotel, Tags: ["air conditioning","laundry service","24-hour front desk service"], Score 0.6026341
- HotelId: 2, HotelName: Old Century Hotel, Tags: ["pool","free wifi","air conditioning","concierge"], Score 0.57902366
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。 以下代码 createIndex.ts 创建索引架构,包括向量字段 DescriptionVector。
const searchFields: SearchField[] = [
{ name: "HotelId", type: "Edm.String", key: true, sortable: true, filterable: true, facetable: true },
{ name: "HotelName", type: "Edm.String", searchable: true, filterable: true },
{ name: "Description", type: "Edm.String", searchable: true },
{
name: "DescriptionVector",
type: "Collection(Edm.Single)",
searchable: true,
vectorSearchDimensions: 1536,
vectorSearchProfileName: "vector-profile"
},
{ name: "Category", type: "Edm.String", filterable: true, facetable: true },
{ name: "Tags", type: "Collection(Edm.String)", filterable: true },
// Additional fields: ParkingIncluded, LastRenovationDate, Rating, Address, Location
];
const vectorSearch: VectorSearch = {
profiles: [
{
name: "vector-profile",
algorithmConfigurationName: "vector-search-algorithm"
}
],
algorithms: [
{
name: "vector-search-algorithm",
kind: "hnsw",
parameters: { m: 4, efConstruction: 400, efSearch: 1000, metric: "cosine" }
}
]
};
const semanticSearch: SemanticSearch = {
configurations: [
{
name: "semantic-config",
prioritizedFields: {
contentFields: [{ name: "Description" }],
keywordsFields: [{ name: "Category" }],
titleField: { name: "HotelName" }
}
}
]
};
const searchIndex: SearchIndex = {
name: indexName,
fields: searchFields,
vectorSearch: vectorSearch,
semanticSearch: semanticSearch,
suggesters: [{ name: "sg", searchMode: "analyzingInfixMatching", sourceFields: ["HotelName"] }]
};
const result = await indexClient.createOrUpdateIndex(searchIndex);
要点:
通过创建字段列表来定义索引。
此特定索引支持多个搜索功能:
该
vectorSearchDimensions属性必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。配置
vectorSearch定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为了简化流程,本快速入门指南提供了包含预计算向量的示例酒店文档。 在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
uploadDocuments.ts中的以下代码将文档上传到您的搜索服务。
const DOCUMENTS = [
// Array of hotel documents with embedded 1536-dimension vectors
// Each document contains: HotelId, HotelName, Description, DescriptionVector,
// Category, Tags, ParkingIncluded, LastRenovationDate, Rating, Address, Location
];
const searchClient = new SearchClient(searchEndpoint, indexName, credential);
const result = await searchClient.uploadDocuments(DOCUMENTS);
for (const r of result.results) {
console.log(`Key: ${r.key}, Succeeded: ${r.succeeded}`);
}
代码通过 SearchClient(@azure/search-documents 包提供的主要对象)与 Azure AI Search service中托管的特定搜索索引进行交互。
SearchClient提供对索引操作的访问,例如:
数据引入:
uploadDocuments、、mergeDocumentsdeleteDocuments搜索操作:
search、autocomplete、suggest
查询索引
搜索文件中的查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
searchSingle.ts 演示了一个基本方案,其中你想要查找与矢量查询字符串非常匹配的文档说明。 该 VectorQuery 对象配置矢量搜索:
-
kNearestNeighborsCount根据矢量相似性限制返回的结果数。 -
fields指定要搜索的向量字段。
const vectorQuery: VectorQuery<HotelDocument> = {
vector: vector,
kNearestNeighborsCount: 5,
fields: ["DescriptionVector"],
kind: "vector",
exhaustive: true
};
const searchOptions: SearchOptions<HotelDocument> = {
top: 7,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"] as const,
includeTotalCount: true,
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const results: SearchDocumentsResult<HotelDocument> = await searchClient.search("*", searchOptions);
for await (const result of results.results) {
const doc = result.document;
console.log(`HotelId: ${doc.HotelId}, HotelName: ${doc.HotelName}, Score: ${result.score}`);
}
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。
searchSingleWithFilter.ts 字段上的 Tags 用于过滤掉不提供免费 Wi-Fi 的酒店。
const searchOptions: SearchOptions<HotelDocument> = {
top: 7,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"] as const,
includeTotalCount: true,
filter: "Tags/any(tag: tag eq 'free wifi')", // Adding filter for "free wifi" tag
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const results: SearchDocumentsResult<HotelDocument> = await searchClient.search("*", searchOptions);
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。
searchSingleWithGeoFilter.ts 指定地理点(华盛顿特区,使用经度和纬度坐标)并在 300 公里内返回酒店。 该 filterMode 属性确定筛选器何时运行。 在这种情况下,postFilter 在矢量搜索后运行筛选器。
const searchOptions: SearchOptions<HotelDocument> = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Category", "Description", "Address/City", "Address/StateProvince"] as const,
facets: ["Address/StateProvince"],
filter: "geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300",
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。
searchHybrid.ts 同时运行这两种查询类型,然后使用倒数排名融合(RRF)将结果合并到统一排名中。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
const vectorQuery: VectorQuery<HotelDocument> = {
vector: vector,
kNearestNeighborsCount: 5,
fields: ["DescriptionVector"],
kind: "vector",
exhaustive: true
};
const searchOptions: SearchOptions<HotelDocument> = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Description", "Category", "Tags"] as const,
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
// Use search text for keyword search (hybrid search = vector + keyword)
const searchText = "historic hotel walk to restaurants and shopping";
const results: SearchDocumentsResult<HotelDocument> = await searchClient.search(searchText, searchOptions);
语义混合搜索
searchSemanticHybrid.ts演示了语义排序,该排序基于语言理解重新排序结果。
const searchOptions: SearchOptions<HotelDocument> = {
top: 5,
includeTotalCount: true,
select: ["HotelId", "HotelName", "Category", "Description"] as const,
queryType: "semantic" as const,
semanticSearchOptions: {
configurationName: "semantic-config"
},
vectorSearchOptions: {
queries: [vectorQuery],
filterMode: "postFilter"
}
};
const searchText = "historic hotel walk to restaurants and shopping";
const results: SearchDocumentsResult<HotelDocument> = await searchClient.search(searchText, searchOptions);
for await (const result of results.results) {
console.log(`Score: ${result.score}, Re-ranker Score: ${result.rerankerScore}`);
}
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
实际结果包含更多详细信息,包括语义说明和突出显示。 本快速入门修改了结果以提高可读性。 若要获取响应的完整结构,请使用 REST 运行请求。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
否则,请运行以下命令以删除在本快速入门中创建的索引。
npm run build && node -r dotenv/config dist/deleteIndex.js
在本快速入门中,你将使用 Azure AI Search REST API 创建、加载和查询 vector index。
在Azure AI Search中,矢量索引具有一个索引架构,用于定义向量和非函数字段、用于创建嵌入空间的算法的矢量搜索配置,以及查询时计算的矢量字段定义设置。 索引 - 创建或更新 (REST API) 创建矢量索引。
小窍门
- 想立即开始吗? 在 GitHub 上下载 source code。
- 本快速入门省略矢量化步骤,并提供内联嵌入。 若要通过自己的内容 进行集成向量化 ,请尝试 导入数据(新) 向导。
先决条件
具有活动订阅的Azure帐户。 免费创建帐户。
Azure AI Search service。 你可以在本快速入门的大部分内容中使用免费层,但对于较大的数据文件,我们建议使用基本或更高级别的服务。
在您的搜索服务中为可选的语义混合查询启用语义排序器。
Git 克隆示例存储库。
使用 Microsoft Entra ID 进行免密身份验证的 Azure CLI。
配置访问
在开始之前,请确保你有权在Azure AI Search中访问内容和操作。 本快速入门使用 Microsoft Entra ID 进行身份验证,并通过基于角色的访问来执行授权。 必须是 Owner 或 User Access Administrator 才能分配角色。 如果角色设置不可行,请改用基于密钥的身份验证方式。
要配置建议的基于角色的访问权限:
将以下角色分配给 用户帐户。
搜索服务贡献者
搜索索引数据参与者
搜索索引数据读取者
获取端点
每个 Azure AI Search 服务都有一个 endpoint,这是一个唯一的 URL,用于标识服务并提供网络访问。 在后面的部分中,你会指定此终结点以通过编程连接到你的搜索服务。
若要获取端点,请执行以下步骤:
登录到 Azure portal 并选择您的 Search Service。
在左窗格中,选择“ 概述”。
记下终结点,该终结点应类似于
https://my-service.search.azure.cn。
设置环境
使用 Git 克隆示例存储库。
git clone https://github.com/Azure-Samples/azure-search-rest-samples导航到快速入门文件夹,并在 Visual Studio Code 中打开它。
cd azure-search-rest-samples/Quickstart-vectors code .在
az-search-quickstart-vectors.rest中,将占位符值@baseUrl替换为在 Get endpoint 中获取到的 URL。若要使用 Microsoft Entra ID 进行无密钥身份验证,请登录到Azure帐户。 如果有多个订阅,请选择包含 Azure AI Search service的订阅。
az login对于使用Microsoft Entra ID进行无密钥身份验证,请生成访问令牌。
az account get-access-token --scope https://search.azure.cn/.default --query accessToken -o tsv将占位符值
@token替换为上一步中的标记。
运行代码
在
### List existing indexes by name中选择发送请求以验证您的连接。相邻窗格中应该会显示响应。 如果有现有索引,则会列出它们。 否则,列表将为空。 如果 HTTP 状态码是
200 OK,则可以继续。按顺序发送剩余的请求,以创建矢量索引、上传文档并运行不同类型的矢量查询。
输出
每个查询请求返回 JSON 结果。 以下示例是请求的 ### Run a single vector query 输出,该输出显示按相似性分数排名的矢量搜索结果。
{
"@odata.count": 5,
"value": [
{
"@search.score": 0.6605852,
"HotelId": "48",
"HotelName": "Nordick's Valley Motel",
"Description": "Only 90 miles (about 2 hours) from the nation's city and nearby most everything the historic valley has to offer. Hiking? Wine Tasting? Exploring the caverns? It's all nearby and we have specially priced packages to help make our B&B your home base for fun while visiting the valley.",
"Category": "Boutique",
"Tags": [
"continental breakfast",
"air conditioning",
"free wifi"
]
},
{
"@search.score": 0.6333684,
"HotelId": "13",
"HotelName": "Luxury Lion Resort",
"Description": "Unmatched Luxury. Visit our downtown hotel to indulge in luxury accommodations. Moments from the stadium and transportation hubs, we feature the best in convenience and comfort.",
"Category": "Luxury",
"Tags": [
"bar",
"concierge",
"restaurant"
]
},
{
"@search.score": 0.605672,
"HotelId": "4",
"HotelName": "Sublime Palace Hotel",
"Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
"Category": "Boutique",
"Tags": [
"concierge",
"view",
"air conditioning"
]
},
{
"@search.score": 0.6026341,
"HotelId": "49",
"HotelName": "Swirling Currents Hotel",
"Description": "Spacious rooms, glamorous suites and residences, rooftop pool, walking access to shopping, dining, entertainment and the city center. Each room comes equipped with a microwave, a coffee maker and a minifridge. In-room entertainment includes complimentary W-Fi and flat-screen TVs.",
"Category": "Suite",
"Tags": [
"air conditioning",
"laundry service",
"24-hour front desk service"
]
},
{
"@search.score": 0.57902366,
"HotelId": "2",
"HotelName": "Old Century Hotel",
"Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
"Category": "Boutique",
"Tags": [
"pool",
"free wifi",
"air conditioning",
"concierge"
]
}
]
}
了解代码
注意事项
本部分中的代码片段可能已修改为可读性。 有关完整的工作示例,请参阅源代码。
运行代码后,让我们分解关键步骤:
创建矢量索引
在将内容添加到Azure AI Search之前,必须创建一个索引来定义内容的存储和结构化方式。 本快速入门调用Indexes - 创建(REST API)来在您的搜索服务上生成一个名为hotels-vector-quickstart的矢量索引及其物理数据结构。
索引架构围绕酒店内容进行组织。 示例数据由虚构酒店矢量和非矢量描述组成。 以下摘录显示了请求的关键 ### Create a new index 结构。
PUT {{baseUrl}}/indexes/hotels-vector-quickstart?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"name": "hotels-vector-quickstart",
"fields": [
{ "name": "HotelId", "type": "Edm.String", "key": true, "filterable": true },
{ "name": "HotelName", "type": "Edm.String", "searchable": true },
{ "name": "Description", "type": "Edm.String", "searchable": true },
{
"name": "DescriptionVector",
"type": "Collection(Edm.Single)",
"searchable": true,
"dimensions": 1536,
"vectorSearchProfile": "my-vector-profile"
},
{ "name": "Category", "type": "Edm.String", "filterable": true, "facetable": true },
{ "name": "Tags", "type": "Collection(Edm.String)", "filterable": true, "facetable": true }
// Additional fields omitted for brevity
],
"vectorSearch": {
"algorithms": [
{ "name": "hnsw-vector-config", "kind": "hnsw" }
],
"profiles": [
{ "name": "my-vector-profile", "algorithm": "hnsw-vector-config" }
]
},
"semantic": {
"configurations": [
{
"name": "semantic-config",
"prioritizedFields": {
"titleField": { "fieldName": "HotelName" },
"prioritizedContentFields": [{ "fieldName": "Description" }]
}
}
]
}
}
要点:
此特定索引支持多个搜索功能:
该
dimensions属性必须与嵌入模型的输出大小匹配。 本快速入门使用 1,536 个维度来匹配text-embedding-ada-002模型。该
vectorSearch部分定义近似近邻 (ANN) 算法。 支持的算法包括分层可导航小型世界(HNSW)和详尽的 K-近邻(KNN)。 有关详细信息,请参阅 矢量搜索中的相关性。
将文档上传到索引
新创建的索引为空。 若要填充索引并使其可搜索,必须上传符合索引架构的 JSON 文档。
在Azure AI Search中,文档既用作索引的输入,也充当查询的输出。 为简单起见,本快速入门以内联 JSON 形式提供示例酒店文档。 但是,在生产方案中,内容通常从连接的数据源中提取,并使用 索引器转换为 JSON。
本快速入门调用 Documents - Index (REST API) 将示例酒店文档添加到索引。 以下摘录显示了### Upload 7 documents请求的结构。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/index?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"value": [
{
"@search.action": "mergeOrUpload",
"HotelId": "1",
"HotelName": "Stay-Kay City Hotel",
"Description": "This classic hotel is ideally located on the main commercial artery of the city...",
"DescriptionVector": [-0.0347, 0.0289, ... ], // 1536 floats
"Category": "Boutique",
"Tags": ["view", "air conditioning", "concierge"],
"ParkingIncluded": false,
"Rating": 3.60,
"Address": { "City": "Beijing", "StateProvince": "NY" },
"Location": { "type": "Point", "coordinates": [-73.975403, 40.760586] }
}
// Additional documents omitted for brevity
]
}
要点:
数组中的每个
value文档都表示一个酒店,并包含与索引架构匹配的字段。 该@search.action参数指定要对每个文档执行的操作。 本快速入门使用mergeOrUpload,如果文档不存在,则添加文档;如果文档不存在,则更新文档。有效负载中的文档由索引架构中定义的字段组成。
查询索引
示例文件中的查询演示了不同的搜索模式。 示例矢量查询基于两个字符串:
全文搜索字符串:
"historic hotel walk to restaurants and shopping"矢量查询字符串:
"quintessential lodging near running trails, eateries, retail"(矢量化为数学表示形式)
矢量查询字符串在语义上类似于全文搜索字符串,但它包括索引中不存在的术语。 仅关键字搜索矢量查询字符串将返回零结果。 但是,矢量搜索根据含义而不是确切关键字查找相关的匹配项。
以下示例以基本矢量查询开头,并逐步添加筛选器、关键字搜索和语义重新调整。
单矢量搜索
该 ### Run a single vector query 请求演示了一个基本方案,你希望找到与矢量查询字符串非常匹配的文档说明。 该 vectorQueries 数组配置矢量搜索:
-
k根据矢量相似性限制返回的结果数。 -
fields指定要搜索的向量字段。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"count": true,
"select": "HotelId, HotelName, Description, Category, Tags",
"vectorQueries": [
{
"vector": [ ... ], // 1536-dimensional vector of "quintessential lodging near running trails, eateries, retail"
"k": 5,
"fields": "DescriptionVector",
"kind": "vector",
"exhaustive": true
}
]
}
使用筛选器进行单向量搜索
在 Azure AI Search 中,筛选器应用于索引中的非vector 字段。 请求 ### Run a vector query with a filter 会筛选字段 Tags 上的筛选器,以筛选出不提供免费 Wi-Fi 的任何酒店。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"count": true,
"select": "HotelId, HotelName, Description, Category, Tags",
"filter": "Tags/any(tag: tag eq 'free wifi')",
"vectorFilterMode": "postFilter",
"vectorQueries": [
{
"vector": [ ... ], // 1536-dimensional vector
"k": 7,
"fields": "DescriptionVector",
"kind": "vector",
"exhaustive": true
}
]
}
使用地理筛选器进行单向量搜索
可以指定 地理空间筛选器 ,以将结果限制为特定的地理区域。 该 ### Run a vector query with a geo filter 请求指定了一个地理点(华盛顿哥伦比亚特区,使用经度和纬度坐标),并返回距离该点 300 公里范围内的酒店。 该 vectorFilterMode 参数确定筛选器何时运行。 在这种情况下,postFilter 在矢量搜索后运行筛选器。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"count": true,
"select": "HotelId, HotelName, Address/City, Address/StateProvince, Description",
"filter": "geo.distance(Location, geography'POINT(-77.03241 38.90166)') le 300",
"vectorFilterMode": "postFilter",
"top": 5,
"facets": [ "Address/StateProvince"],
"vectorQueries": [
{
"vector": [ ... ], // 1536-dimensional vector
"k": 5,
"fields": "DescriptionVector",
"kind": "vector",
"exhaustive": true
}
]
}
混合搜索
混合搜索 在单个请求中合并全文和矢量查询。 请求 ### Run a hybrid query 同时运行这两种查询类型,然后使用 Reciprocal Rank Fusion(RRF)将结果合并为统一排名。 RRF 使用每个结果集中的结果排名反函数生成合并的排名。 请注意,混合搜索分数通常比单查询分数更小。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"count": true,
"search": "historic hotel walk to restaurants and shopping",
"select": "HotelId, HotelName, Category, Tags, Description",
"top": 5,
"vectorQueries": [
{
"vector": [ ... ], // 1536-dimensional vector
"k": 5,
"fields": "DescriptionVector",
"kind": "vector",
"exhaustive": true
}
]
}
语义混合搜索
### Run a hybrid query with semantic reranking 请求演示了 语义排名,该排名基于语言理解对结果进行重新排序。
POST {{baseUrl}}/indexes/hotels-vector-quickstart/docs/search?api-version={{api-version}} HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}
{
"count": true,
"search": "historic hotel walk to restaurants and shopping",
"select": "HotelId, HotelName, Category, Description",
"queryType": "semantic",
"semanticConfiguration": "semantic-config",
"top": 5,
"vectorQueries": [
{
"vector": [ ... ], // 1536-dimensional vector
"k": 7,
"fields": "DescriptionVector",
"kind": "vector",
"exhaustive": true
}
]
}
将这些结果与上一查询中的混合搜索结果进行比较。 如果未进行语义重排,则 Sublime Palace Hotel 排名第一,因为倒数排名融合 (RRF) 会结合文本和失量分数来生成合并结果。 语义重排序后,Swirling Currents酒店升至榜首。
语义排名器使用计算机理解模型来评估每个结果与查询意向匹配程度。 斯沃灵克伦茨酒店的描述提到 "walking access to shopping, dining, entertainment and the city center",这与搜索查询的 "walk to restaurants and shopping" 非常匹配。 对于附近餐饮和购物的语义匹配使其优于 Sublime 故宫酒店,而后者并未在其描述中强调步行可达的便利设施。
要点:
- 在混合搜索中,可以将矢量搜索与关键字的全文搜索相集成。 筛选器和语义排名仅适用于文本内容,而不适用于矢量。
清理资源
在您自己的订阅计划中工作时,最好通过删除不再需要的资源来完成项目。 持续运行的资源可能会产生费用。
在Azure portal中,从左窗格中选择“所有资源或resource 组以查找和管理资源。 可以单独删除资源,也可以删除资源组以一次性删除所有资源。
否则,可以发送 ### Delete an index 请求以删除在本快速入门中创建的索引。