Azure Machine Learning - 使用.NET创建和管理AI搜索功能

本文介绍了如何在 Azure SDK for .NET 中使用 C# 和 Azure.Search.Documents客户端库来创建和管理搜索对象。

关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。

file

.NET 的 Azure SDK 库

用于 .NET 的 Azure SDK 包含 Azure SDK 团队提供的一个新的 [Azure.Search.Documents]客户端库,该客户端库的功能等同于上一个 [Microsoft.Azure.Search]客户端库。 版本 11 在 Azure 可编程性方面更加一致。

你可以使用此库来执行以下操作:

  • 创建和管理搜索索引、数据源、索引器、技能组和同义词映射
  • 在索引中加载和管理搜索文档
  • 执行查询,这些查询全都无需处理 HTTP 和 JSON 的详细信息
  • 调用和管理 AI 扩充(技能组)和输出

此库作为单个 Azure.Search.Documents NuGet 包进行分发,其中包括用于以编程方式访问搜索服务的所有 API。

客户端库会定义 SearchIndexSearchFieldSearchDocument 之类的类,还会定义 SearchIndexClientSearchClient 类中的 SearchIndexClient.CreateIndexSearchClient.Search 之类的操作。

Azure.Search.Documents(版本 11)面向 2020-06-30 搜索服务规范。

SDK 要求

  • Visual Studio 2019 或更高版本。

  • 自己的 Azure AI 搜索服务。 要使用 SDK,需要服务的名称以及一个或多个 API 密钥。 [在门户中创建一个服务]。

  • 在 Visual Studio 中使用“工具”>“NuGet 包管理器”>“管理解决方案的 NuGet 包…”下载 Azure.Search.Documents 包。 搜索包名称 Azure.Search.Documents

用于 .NET 的 Azure SDK 符合 [.NET Standard 2.0]。

示例应用程序

本文“通过示例进行讲授”,依赖于 GitHub 上的 DotNetHowTo 代码示例来说明 Azure AI 搜索中的基本概念,尤其是如何创建、加载和查询搜索索引。

对于本文的其余部分,假定有一个名为“hotels”的新索引,该索引中通过对结果进行匹配的多个查询填充了一些文档。

下面是展示总体流程的主程序:

// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");IConfigurationRoot configuration = builder.Build();SearchIndexClient indexClient = CreateSearchIndexClient(configuration);string indexName = configuration["SearchIndexName"];Console.WriteLine("{0}", "Deleting index...\n");DeleteIndexIfExists(indexName, indexClient);Console.WriteLine("{0}", "Creating index...\n");CreateIndex(indexName, indexClient);SearchClient searchClient = indexClient.GetSearchClient(indexName);Console.WriteLine("{0}", "Uploading documents...\n");UploadDocuments(searchClient);SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);Console.WriteLine("{0}", "Run queries...\n");RunQueries(indexClientForQueries);Console.WriteLine("{0}", "Complete.  Press any key to end application...\n");Console.ReadKey();
}

接下来是输出的部分屏幕截图,假设你使用有效的服务名称和 API 密钥运行此应用程序:
file

客户端类型

客户端库使用三种客户端类型执行各种操作:[SearchIndexClient]用于创建、更新或删除索引;[SearchClient]用于加载或查询索引;[SearchIndexerClient]用于处理索引器和技能组。 本文重点介绍了前两种类型。

所有客户端都至少需要服务名称或终结点,以及一个 API 密钥。 通常在配置文件中提供此信息,它类似于在 DotNetHowTo 示例应用程序的 appsettings.json 文件中找到的内容。 若要从配置文件中读取数据,请将 using Microsoft.Extensions.Configuration; 添加到程序。

下面的语句创建用于创建、更新或删除索引的索引客户端。 它接受服务终结点和管理 API 密钥。

private static SearchIndexClient CreateSearchIndexClient(IConfigurationRoot configuration)
{string searchServiceEndPoint = configuration["SearchServiceEndPoint"];string adminApiKey = configuration["SearchServiceAdminApiKey"];SearchIndexClient indexClient = new SearchIndexClient(new Uri(searchServiceEndPoint), new AzureKeyCredential(adminApiKey));return indexClient;
}

下一个语句创建用于加载文档或运行查询的搜索客户端。 SearchClient 需要一个索引。 你将需要一个管理 API 密钥来加载文档,但可以使用查询 API 密钥来运行查询。

string indexName = configuration["SearchIndexName"];private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{string searchServiceEndPoint = configuration["SearchServiceEndPoint"];string queryApiKey = configuration["SearchServiceQueryApiKey"];SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));return searchClient;
}

备注

如果为导入操作提供了无效的密钥(例如,在其中需要管理密钥的查询密钥),则首次调用 SearchClient 上的操作方法时,它会引发 CloudException 并显示错误消息“已禁用”。 如果遇到此情况,请仔细检查 API 密钥。

删除索引

在早期开发阶段,你可能希望包括一个 [DeleteIndex]语句来删除正在执行的索引,以便可以使用更新后的定义重新创建它。 Azure AI 搜索的示例代码通常包含一个删除步骤,以便你可以重新运行该示例。

下面的行调用 DeleteIndexIfExists

Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, indexClient);

此方法使用给定的 SearchIndexClient 来检查索引是否存在,如果存在,则删除该索引:

private static void DeleteIndexIfExists(string indexName, SearchIndexClient indexClient)
{try{if (indexClient.GetIndex(indexName) != null){indexClient.DeleteIndex(indexName);}}catch (RequestFailedException e) when (e.Status == 404){// Throw an exception if the index name isn't foundConsole.WriteLine("The index doesn't exist. No deletion occurred.");

创建索引

你可以使用 [SearchIndexClient]来创建索引。

以下方法使用 [SearchField]对象的列表创建一个新的 [SearchIndex]对象,这些对象定义新索引的架构。 每个字段都有名称、数据类型和数个属性(定义其搜索行为)。

可以使用 [FieldBuilder]通过模型类来定义字段。 FieldBuilder 类通过检查给定 Hotel 模型类的公共属性和特性,使用反射来为索引创建 SearchField 对象的列表。 我们会在以后详细地查看 Hotel 类。

private static void CreateIndex(string indexName, SearchIndexClient indexClient)
{FieldBuilder fieldBuilder = new FieldBuilder();var searchFields = fieldBuilder.Build(typeof(Hotel));var definition = new SearchIndex(indexName, searchFields);indexClient.CreateOrUpdateIndex(definition);
}

除了字段之外,还可以向索引添加计分配置文件、建议器或 CORS 选项(为简洁起见,示例中省略了这些参数)。 可在 [SearchIndex]属性列表以及 [REST API 参考]中找到有关 SearchIndex 对象及其组成部分的详细信息。

备注

如果需要,始终可以直接创建 Field 对象的列表,而不是使用 FieldBuilder。 例如,你可能不想使用模型类,或者可能需要使用不希望通过添加属性来进行修改的现有模型类。

在 Main() 中调用 CreateIndex

Main 通过调用以上方法创建新的“hotels”索引:

Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, indexClient);

使用模型类来表示数据

DotNetHowTo 示例为 Hotel、Address 和 Room 数据结构使用了模型类。 Hotel 引用了 Address(一个单一级别的复杂类型,多部件字段)和 Room(多部件字段的集合)。

你可以使用这些类型来创建和加载索引,以及构建查询的响应:

// Use-case: <Hotel> in a field definition
FieldBuilder fieldBuilder = new FieldBuilder();
var searchFields = fieldBuilder.Build(typeof(Hotel));// Use-case: <Hotel> in a response
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{foreach (SearchResult<Hotel> result in searchResults.GetResults()){Console.WriteLine(result.Document);}Console.WriteLine();
}

另一种方法是直接向索引添加字段。 以下示例只显示了几个字段。

 SearchIndex index = new SearchIndex(indexName){Fields ={new SimpleField("hotelId", SearchFieldDataType.String) { IsKey = true, IsFilterable = true, IsSortable = true },new SearchableField("hotelName") { IsFilterable = true, IsSortable = true },new SearchableField("hotelCategory") { IsFilterable = true, IsSortable = true },new SimpleField("baseRate", SearchFieldDataType.Int32) { IsFilterable = true, IsSortable = true },new SimpleField("lastRenovationDate", SearchFieldDataType.DateTimeOffset) { IsFilterable = true, IsSortable = true }}};

字段定义

.NET 中的数据模型及其相应的索引架构应该支持面向最终用户的搜索体验。 .NET 中的每个顶级对象(例如搜索索引中的搜索文档)对应于在用户界面中显示的搜索结果。 例如,在酒店搜索应用程序中,最终用户可能想要按酒店名称、酒店特色或特定客房的特征进行搜索。

在每个类中,都为字段定义了数据类型和属性,属性决定了如何使用该字段。 每个类中的每个公共属性的名称会映射到索引定义中的同名字段。

请看下面的代码片段,该代码片段从 Hotel 类中拉取多个字段定义。 请注意,Address 和 Rooms 是 C# 类型,具有自己的类定义(如果要查看它们,请参阅示例代码)。 这两者都是复杂类型。 有关详细信息,请参阅[如何为复杂类型建模]。

public partial class Hotel
{[SimpleField(IsKey = true, IsFilterable = true)]public string HotelId { get; set; }[SearchableField(IsSortable = true)]public string HotelName { get; set; }[SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]public string Description { get; set; }[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]public string Category { get; set; }[JsonIgnore]public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;[SearchableField]public Address Address { get; set; }public Room[] Rooms { get; set; }
选择字段类

定义字段时,你可以使用 [SearchField]基类,也可以使用充当“模板”的派生帮助程序模型并使用预配置的属性。

索引中必须恰好有一个字段充当文档键 (IsKey = true)。 它必须是字符串,并且必须唯一标识每个文档。 它还需要具有 IsHidden = true,这意味着它在搜索结果中不可见。

添加字段属性

请注意每个字段如何通过属性(例如 IsFilterableIsSortableIsKeyAnalyzerName)进行修饰。 这些属性直接映射到 [Azure AI 搜索索引中的相应字段属性]。 FieldBuilder 类使用这些属性来构造索引的字段定义。

字段类型映射

属性的 .NET 类型映射到它们在索引定义中的等效字段类型。 例如,Category 字符串属性映射到 Edm.String 类型的 category 字段。 bool?Edm.BooleanDateTimeOffset?Edm.DateTimeOffset 等之间存在类似的类型映射。

你是否注意到了 SmokingAllowed 属性?

[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;

此属性的 JsonIgnore 特性告知 FieldBuilder 不要将其序列化为字段形式的索引。 这是创建可在应用程序中用作帮助器的客户端计算属性的极佳方法。 在这种情况下,SmokingAllowed 属性将反映 Rooms 集合中的任何 Room 是否允许吸烟。 如果全部为 false,则表示整个酒店不允许吸烟。

加载索引

Main 中的下一步会填充新创建的“hotels”索引。 此索引填充操作是通过以下方法完成的:(为方便演示,某些代码已替换为“…”。有关完整的数据填充代码,请参阅完整的示例解决方案。)

private static void UploadDocuments(SearchClient searchClient)
{IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(IndexDocumentsAction.Upload(new Hotel(){HotelId = "1",HotelName = "Secret Point Motel",...Address = new Address(){StreetAddress = "677 5th Ave",...},Rooms = new Room[]{new Room(){Description = "Budget Room, 1 Queen Bed (Cityside)",...},new Room(){Description = "Budget Room, 1 King Bed (Mountain View)",...},new Room(){Description = "Deluxe Room, 2 Double Beds (City View)",...}}}),IndexDocumentsAction.Upload(new Hotel(){HotelId = "2",HotelName = "Twin Dome Motel",...{StreetAddress = "140 University Town Center Dr",...},Rooms = new Room[]{new Room(){Description = "Suite, 2 Double Beds (Mountain View)",...},new Room(){Description = "Standard Room, 1 Queen Bed (City View)",...},new Room(){Description = "Budget Room, 1 King Bed (Waterfront View)",...}}}),IndexDocumentsAction.Upload(new Hotel(){HotelId = "3",HotelName = "Triple Landscape Hotel",...Address = new Address(){StreetAddress = "3393 Peachtree Rd",...},Rooms = new Room[]{new Room(){Description = "Standard Room, 2 Queen Beds (Amenities)",...},new Room (){Description = "Standard Room, 2 Double Beds (Waterfront View)",...},new Room(){Description = "Deluxe Room, 2 Double Beds (Cityside)",...}}}};try{IndexDocumentsResult result = searchClient.IndexDocuments(batch);}catch (Exception){// Sometimes when your Search service is under load, indexing will fail for some of the documents in// the batch. Depending on your application, you can take compensating actions like delaying and// retrying. For this simple demo, we just log the failed document keys and continue.Console.WriteLine("Failed to index some of the documents: {0}");}Console.WriteLine("Waiting for documents to be indexed...\n");Thread.Sleep(2000);

此方法有四个部分。 第一个部分创建包含 3 个 Hotel 对象的数组,其中每个对象包含 3 个用作要上传到索引的输入数据的 Room 对象。 为简单起见,此数据是硬编码的。 在实际应用中,数据有可能会来自 SQL 数据库等外部数据源。

第二部分创建包含文档的 [IndexDocumentsBatch]。 创建 Batch 时,指定要应用到 Batch 的操作,在这种情况下应调用 [IndexDocumentsAction.Upload]。 然后,使用 [IndexDocuments]方法将批处理上传到 Azure AI 搜索索引。

此方法的第三部分是处理索引重要错误情况的 catch 块。 如果你的搜索服务无法为批中的某些文档编制索引,则会引发 RequestFailedException。 如果在服务负载过大时为文档编制索引,可能会发生异常。 强烈建议在代码中显式处理这种情况。 可以延迟为失败的文档编制索引,并重试,也可以像此示例一样记录并继续执行,还可以执行其他操作,具体取决于应用程序对数据一致性的要求。 另一种方法是使用 [SearchIndexingBufferedSender]为失败的索引操作进行智能批处理、自动刷新和重试。 请参阅此示例,以了解更多上下文。

最后,UploadDocuments 方法延迟了两秒钟。 编制索引在搜索服务中异步进行,因此,示例应用程序需要等待很短时间,以确保文档可用于搜索。 此类延迟通常仅在演示、测试和示例应用程序中是必需的。

在 Main() 中调用 UploadDocuments

下面的代码片段使用 indexClient 的 [GetSearchClient]方法设置 [SearchClient]的实例。 IndexClient 在其请求上使用管理 API 密钥,这是加载或刷新文档所必需的。

另一种方法是直接调用 SearchClient ,并在 AzureKeyCredential 上传入管理 API 密钥。

SearchClient searchClient = indexClient.GetSearchClient(indexName);Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(searchClient);

运行查询

首先,设置从 appsettings.json 读取服务终结点和查询 API 密钥的 SearchClient

private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{string searchServiceEndPoint = configuration["SearchServiceEndPoint"];string queryApiKey = configuration["SearchServiceQueryApiKey"];SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));return searchClient;
}

其次,定义发送查询请求的方法。

此方法在每次执行查询时都创建一个新的 [SearchOptions]对象。 此对象用于为查询指定其他选项,如排序、筛选、分页和分面。 在此方法中,我们为不同的查询设置 FilterSelectOrderBy 属性。 有关搜索查询表达式语法的详细信息,请参阅[简单查询语法]。

下一步是查询执行。 使用 SearchClient.Search 方法运行搜索。 对于每个查询,请以字符串形式传递要使用的搜索文本(或 "*",如果没有搜索文本),以及先前创建的搜索选项。 此外,我们指定 Hotel 作为 SearchClient.Search 的类型参数,这指示 SDK 将搜索结果中的文档反序列化为类型为 Hotel 的对象。

private static void RunQueries(SearchClient searchClient)
{SearchOptions options;SearchResults<Hotel> results;Console.WriteLine("Query 1: Search for 'motel'. Return only the HotelName in results:\n");options = new SearchOptions();options.Select.Add("HotelName");results = searchClient.Search<Hotel>("motel", options);WriteDocuments(results);Console.Write("Query 2: Apply a filter to find hotels with rooms cheaper than $100 per night, ");Console.WriteLine("returning the HotelId and Description:\n");options = new SearchOptions(){Filter = "Rooms/any(r: r/BaseRate lt 100)"};options.Select.Add("HotelId");options.Select.Add("Description");results = searchClient.Search<Hotel>("*", options);WriteDocuments(results);Console.Write("Query 3: Search the entire index, order by a specific field (lastRenovationDate) ");Console.Write("in descending order, take the top two results, and show only hotelName and ");Console.WriteLine("lastRenovationDate:\n");options =new SearchOptions(){Size = 2};options.OrderBy.Add("LastRenovationDate desc");options.Select.Add("HotelName");options.Select.Add("LastRenovationDate");results = searchClient.Search<Hotel>("*", options);WriteDocuments(results);Console.WriteLine("Query 4: Search the HotelName field for the term 'hotel':\n");options = new SearchOptions();options.SearchFields.Add("HotelName");//Adding details to select, because "Location" isn't supported yet when deserializing search result to "Hotel"options.Select.Add("HotelId");options.Select.Add("HotelName");options.Select.Add("Description");options.Select.Add("Category");options.Select.Add("Tags");options.Select.Add("ParkingIncluded");options.Select.Add("LastRenovationDate");options.Select.Add("Rating");options.Select.Add("Address");options.Select.Add("Rooms");results = searchClient.Search<Hotel>("hotel", options);WriteDocuments(results);
}

第三,定义编写响应的方法,将每个文档输出到控制台:

private static void WriteDocuments(SearchResults<Hotel> searchResults)
{foreach (SearchResult<Hotel> result in searchResults.GetResults()){Console.WriteLine(result.Document);}Console.WriteLine();
}

在 Main() 中调用 RunQueries

SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);Console.WriteLine("{0}", "Running queries...\n");
RunQueries(indexClientForQueries);

探究查询构造

让我们依次仔细查看每个查询。 下面是用于执行第一个查询的代码:

options = new SearchOptions();
options.Select.Add("HotelName");results = searchClient.Search<Hotel>("motel", options);WriteDocuments(results);

在本例中,我们将在任何可搜索字段中搜索“motel”一词的整个索引,并且我们只检索 Select 选项指定的酒店名称。 结果如下:

Name: Secret Point MotelName: Twin Dome Motel

在第二个查询中,使用筛选器来选择每晚费用低于 $100 的房间。 在结果中仅返回酒店 ID 和说明:

options = new SearchOptions()
{Filter = "Rooms/any(r: r/BaseRate lt 100)"
};
options.Select.Add("HotelId");
options.Select.Add("Description");results = searchClient.Search<Hotel>("*", options);

以上查询使用 OData $filter 表达式 Rooms/any(r: r/BaseRate lt 100) 来筛选索引中的文档。 这会使用 [any 运算符]将“BaseRate lt 100”应用到 Rooms 集合中的每个项。 有关详细信息,请参阅 [OData 筛选器语法]。

在第三个查询中,查找最近翻修的前两个酒店,并显示酒店名称和上次翻修日期。 代码如下:

options =new SearchOptions(){Size = 2};
options.OrderBy.Add("LastRenovationDate desc");
options.Select.Add("HotelName");
options.Select.Add("LastRenovationDate");results = searchClient.Search<Hotel>("*", options);WriteDocuments(results);

在最后一个查询中,查找与“motel”一词匹配的所有酒店名称:

options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Description");
options.Select.Add("Category");
options.Select.Add("Tags");
options.Select.Add("ParkingIncluded");
options.Select.Add("LastRenovationDate");
options.Select.Add("Rating");
options.Select.Add("Address");
options.Select.Add("Rooms");results = searchClient.Search<Hotel>("hotel", options);WriteDocuments(results);

本部分总结了对 .NET SDK 的介绍,但请不要在这里停止。 下一节推荐了一些其他资源,便于你详细了解如何使用 Azure AI 搜索进行编程。

关注TechLead,分享AI全维度知识。作者拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,同济本复旦硕,复旦机器人智能实验室成员,阿里云认证的资深架构师,项目管理专业人士,上亿营收AI产品研发负责人。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/191703.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【DPDK】Trace Library

概述 跟踪是一种用于了解运行中的软件系统中发生了什么的技术。用于跟踪的软件被称为跟踪器&#xff0c;在概念上类似于磁带记录器。记录时&#xff0c;放置在软件源代码中的特定检测点会生成保存在巨大磁带上的事件&#xff1a;跟踪文件。稍后可以在跟踪查看器中打开跟踪文件…

java学习part29线程通信

139-多线程-线程间的通信机制与生产者消费者案例_哔哩哔哩_bilibili 1.等待唤醒 类似于golang的channel&#xff0c; 1.1用法 类似于go的wait()&#xff0c; 1.sleep和wait的一个重大区别是&#xff0c;sleep不会让线程失去同步监视器&#xff0c;而wait会释放 2.wait必须tr…

【vSphere 8 自签名 VMCA 证书】企业 CA 签名证书替换 vSphere VMCA CA 证书Ⅱ—— 创建和添加证书模板

目录 3. 使用 Microsoft 证书颁发机构创建 VMCA 证书模板3.1 打开 Certificate Template Console3.2 复制模板修改 Compatibility 选项卡修改 General 选项卡修改 Extensions 选项卡确认新模板 4. 将新模板添加到证书模板4.1 打开 Certificate Console4.2 创建证书模板 关联博文…

【论文阅读】Bayes’ Rays:神经辐射场的不确定性量化

【论文阅读】Bayes’ Rays&#xff1a;神经辐射场的不确定性量化 1. Introduction2. Related work3. Background3.2. Neural Laplace Approximations 4. Method4.1. Intuition4.2. Modeling perturbations4.3. Approximating H4.4. Spatial uncertainty 5. Experiments & A…

【数据结构】最短路径(Dijskra算法)

一.引例 计算机网络传输的问题&#xff1a; 怎样找到一种最经济的方式&#xff0c;从一台计算机向网上所有其他计算机发送一条消息。 抽象为&#xff1a; 给定带权有向图G&#xff08;V&#xff0c;E&#xff09;和源点v&#xff0c;求从v到G中其余各顶点的最短路径。 即&…

【C语言】【字符串函数的模拟实现】strcpy,strcat,strcmp,strncpy,strncat,strstr

1.strcpy char* strcpy(char*destination,const char* source)源字符串必须以’\0’结尾会将原字符串中的‘\0’拷贝到目标字符串中目标空间必须足够大&#xff0c;能放得下源字符串 模拟实现&#xff1a; char *my_strcpy(char* des,const char *sour) {char* retdes;asser…

【开源存储】minio对象存储部署实践

文章目录 一、前言1、介绍说明2、部署方式3、冗余模式4、约束限制4.1、规格参数4.2、API支持a、minio不支持的Amazon S3 Bucket APIb、minio不支持的Amazon S3 Object API 二、部署说明1、软件安装2、minio单机部署3、minio分布式部署3.1、前置条件3.2、开始运行3.3、操作说明 …

【面试经典 150 | 二分查找】搜索插入位置

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;二分查找闭区间左闭右开区间开区间总结 知识总结写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c…

CAP BASE理论

CAP & BASE理论详解 CAP 理论 简介 CAP 也就是 Consistency&#xff08;一致性&#xff09;、Availability&#xff08;可用性&#xff09;、Partition Tolerance&#xff08;分区容错性&#xff09; 这三个单词首字母组合。 CAP 理论的提出者布鲁尔在提出 CAP 猜想的时…

VMware17 下载、安装、成功安装效果、完整卸载

VMware17 下载、安装、卸载 下载 VMware17 安装 更改安装路径 去掉这两个复选框&#xff0c;点击安装。 安装结束&#xff0c;点击许可证。 输入序列号&#xff0c;点击【输入】 序列号&#xff1a;MC60H-DWHD5-H80U9-6V85M-8280D 点击完成 测试安装效果 永不过期&am…

Hdoop学习笔记(HDP)-Part.06 安装OracleJDK

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

RocketMQ(四):重复消费、消息重试、死信消息的解决方案

RocketMQ系列文章 RocketMQ(一)&#xff1a;基本概念和环境搭建 RocketMQ(二)&#xff1a;原生API快速入门 RocketMQ(三)&#xff1a;集成SpringBoot RocketMQ(四)&#xff1a;重复消费、消息重试、死信消息的解决方案 目录 一、重复消费1、消息重复的情况2、MySql唯一索引…

Docker Compose及Docker 知识点整理

目录 1、Docker Compose 简介 2、为什么要使用Docker Compose 3、Docker Compose安装使用&#xff08;Linux&#xff09; 3.1 下载 3.2 mkdir docker 文件夹目录 3.3 上传docker-compose到docker文件夹 3.4 移动到 /usr/local/bin 目录下 3.5 添加执行权限 3.6 修改文…

华为云之快速部署FTP站点

华为云之快速部署FTP站点 一、本次实践介绍1.1 实践环境简介1.2 本次实践目的 二、vsftpd介绍2.1 vsftpd简介2.2 vsftpd特点 三、环境准备工作3.1 预置实验环境3.2 查看预置环境信息3.3 登录华为云3.4 查看弹性云服务器状态3.5 查看弹性公网IP地址3.6 ssh登录弹性云服务器3.6 查…

基于c#+mysql+winform学生成绩管理系统-实践作业

基于c#mysqlwinform学生成绩管理系统-实践作业 一、系统介绍二、功能展示四、其它1.其他系统实现五.获取源码 一、系统介绍 分老师与学生两个界面&#xff1b; 老师能查看学生信息并评价&#xff0c;添加&#xff0c;删除学生&#xff1b; 老师能查看学生成绩并修改&#xff0…

整数分频,奇偶分频。

实验目标&#xff1a; 实现任意整数奇偶分频。 /* 二分频电路就是用同一个时钟信号通过一定的电路结构转变成不同频率的时钟信号。 二分频就是通过有分频作用的电路结构&#xff0c;在时钟每触发2个周期时&#xff0c;电路输出1个周期信号。 比如用一个脉冲时钟触发一个计…

Kubernetes入门学习(上)

文章目录 Kubernetes入门学习&#xff08;上&#xff09;介绍云原生 Kubernetes架构基础概念Kubernetes架构控制平面组件Node组件 组件关系 安装Kubernetes基本对象和操作Pod&#xff08;容器集&#xff09;Deployment(部署)与ReplicaSet(副本集)Service&#xff08;服务&#…

第一百八十七回 DropdownButton组件

文章目录 1. 概念介绍2. 使用方法2.1 DropdownButton2.2 DropdownMenuItem 3. 示例代码4. 内容总结5. 经验分享 我们在 上一章回中介绍了"DropdownMenu组件"相关的内容&#xff0c;本章回中将介绍 DropdownButton组件.闲话休提&#xff0c;让我们一起Talk Flutter吧…

使用 kubeadm 部署 Kubernetes 集群(三)kubeadm 初始化 k8s 证书过期解决方案

一、延长k8s证书时间 查看 apiserver 证书有效时间&#xff1a;默认是一年的有效期 [rootxuegod63 ~]# openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text |grep Not 延长证书过期时间 1.把 update-kubeadm-cert.sh 文件上传到 xuegod63 节点 vim update-…

Unity 下载网络图片的方法,并把图片赋值给UI和物体的方法

Unity 下载网络图片的方法&#xff0c;可使用WWW类或UnityWebRequest类&#xff0c;其中UnityWebRequest是新版的方法。 通常我们下载图片都会转成Texture&#xff0c;然后赋值给UI或者物体。 具体实现方法&#xff1a; using System.Collections; using System.Collections…