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.
Observação
Pesquisa de IA do Azure está disponível por meio do portal Azure, APIs REST e SDKs do Azure. Ele também sustenta o IQ do Foundry, a camada de conhecimento gerenciado que transforma o conteúdo da empresa em bases de conhecimento reutilizáveis e com reconhecimento de permissão para agentes no portal do Microsoft Foundry.
Ao gerenciar Pesquisa de IA do Azure recursos, como índices e fontes de dados, é importante atualizar os recursos com segurança, especialmente se os recursos forem acessados simultaneamente por diferentes componentes do seu aplicativo.
- As operações de atualização de recurso podem não ser concluídas imediatamente. Por exemplo, atualizar um índice ou um indexador pode levar vários segundos para ser concluído. As atualizações de recursos são serializadas, o que significa que várias operações de atualização podem não ser executadas simultaneamente no mesmo recurso.
- Quando dois clientes atualizam simultaneamente um recurso sem coordenação, uma condição de corrida é possível. Um cliente pode iniciar uma operação de atualização enquanto o outro cliente recebe um erro de conflito. Para evitar isso, Pesquisa de IA do Azure dá suporte a um modelo de simultaneidade optimista. Não há nenhum bloqueio em um recurso. Em vez disso, há uma ETag para todos os recursos que identificam a versão do recurso. Assim, você pode criar solicitações que evitam substituições acidentais.
Como ele funciona
A simultaneidade otimista é implementada por meio de verificações de condição de acesso em chamadas à API que escrevem em índices, indexadores, fontes de dados, conjuntos de habilidades, bases de conhecimento e recursos synonymMap.
Todos os recursos tiverem uma marca da entidade (ETag) que fornece informações de versão do objeto. Verificando o ETag pela primeira vez, você pode evitar atualizações simultâneas em um fluxo de trabalho típico (obter, modificar localmente e atualizar), garantindo que a ETag do recurso coincida com sua cópia local.
A API REST usa um ETag no cabeçalho da solicitação.
O SDK Azure para .NET define a ETag por meio de uma classe accessCondition, definindo o If-Match | If-Match-None header no recurso. Objetos que usam ETags, como SynonymMap.ETag e SearchIndex.ETag, têm uma classe accessCondition.
Sempre que você atualizar um recurso, a ETag é alterada automaticamente. Quando você implementa o gerenciamento de simultaneidade, tudo o que você está fazendo é colocar uma pré-condição na solicitação de atualização que exige o recurso remoto com o mesmo ETag como a cópia do recurso que você modificou no cliente. Se outro processo alterar o recurso remoto, a ETag não corresponderá à pré-condição e a solicitação falhará com HTTP 412 ou 409. Se você estiver usando o SDK do .NET, essa falha será manifestada como uma exceção em que o método de extensão IsAccessConditionFailed() retornará true.
Observação
Há apenas um mecanismo para simultaneidade. Ele sempre é usado, independentemente de qual API ou SDK é usado para atualizações de recursos. A partir de 18 de julho de 2025, Pesquisa de IA do Azure começou a impor a serialização para operações de criação e atualização de índice para garantir a consistência e a confiabilidade.
Exemplo
O código a seguir demonstra a simultaneidade otimista para uma operação de atualização. A segunda atualização falha porque a ETag do objeto é alterada por uma atualização anterior. Mais especificamente, quando a ETag no cabeçalho da solicitação deixa de corresponder à ETag do objeto, o serviço de pesquisa retorna um código de status de 400 (solicitação incorreta) e a atualização falha.
using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using System;
using System.Net;
using System.Threading.Tasks;
namespace AzureSearch.SDKHowTo
{
class Program
{
// This sample shows how ETags work by performing conditional updates and deletes
// on an Azure Search index.
static void Main(string[] args)
{
string serviceName = "PLACEHOLDER FOR YOUR SEARCH SERVICE NAME";
string apiKey = "PLACEHOLDER FOR YOUR SEARCH SERVICE ADMIN API KEY";
// Create a SearchIndexClient to send create/delete index commands
Uri serviceEndpoint = new Uri($"https://{serviceName}.search.windows.net/");
AzureKeyCredential credential = new AzureKeyCredential(apiKey);
SearchIndexClient adminClient = new SearchIndexClient(serviceEndpoint, credential);
// Delete index if it exists
Console.WriteLine("Check for index and delete if it already exists...\n");
DeleteTestIndexIfExists(adminClient);
// Every top-level resource in Azure Search has an associated ETag that keeps track of which version
// of the resource you're working on. When you first create a resource such as an index, its ETag is
// empty.
SearchIndex index = DefineTestIndex();
Console.WriteLine(
$"Test searchIndex hasn't been created yet, so its ETag should be blank. ETag: '{index.ETag}'");
// Once the resource exists in Azure Search, its ETag is populated. Make sure to use the object
// returned by the SearchIndexClient. Otherwise, you will still have the old object with the
// blank ETag.
Console.WriteLine("Creating index...\n");
index = adminClient.CreateIndex(index);
Console.WriteLine($"Test index created; Its ETag should be populated. ETag: '{index.ETag}'");
// ETags prevent concurrent updates to the same resource. If another
// client tries to update the resource, it will fail as long as all clients are using the right
// access conditions.
SearchIndex indexForClientA = index;
SearchIndex indexForClientB = adminClient.GetIndex("test-idx");
Console.WriteLine("Simulating concurrent update. To start, clients A and B see the same ETag.");
Console.WriteLine($"ClientA ETag: '{indexForClientA.ETag}' ClientB ETag: '{indexForClientB.ETag}'");
// indexForClientA successfully updates the index.
indexForClientA.Fields.Add(new SearchField("a", SearchFieldDataType.Int32));
indexForClientA = adminClient.CreateOrUpdateIndex(indexForClientA);
Console.WriteLine($"Client A updates test-idx by adding a new field. The new ETag for test-idx is: '{indexForClientA.ETag}'");
// indexForClientB tries to update the index, but fails due to the ETag check.
try
{
indexForClientB.Fields.Add(new SearchField("b", SearchFieldDataType.Boolean));
adminClient.CreateOrUpdateIndex(indexForClientB);
Console.WriteLine("Whoops; This shouldn't happen");
Environment.Exit(1);
}
catch (RequestFailedException e) when (e.Status == 400)
{
Console.WriteLine("Client B failed to update the index, as expected.");
}
// Uncomment the next line to remove test-idx
//adminClient.DeleteIndex("test-idx");
Console.WriteLine("Complete. Press any key to end application...\n");
Console.ReadKey();
}
private static void DeleteTestIndexIfExists(SearchIndexClient adminClient)
{
try
{
if (adminClient.GetIndex("test-idx") != null)
{
adminClient.DeleteIndex("test-idx");
}
}
catch (RequestFailedException e) when (e.Status == 404)
{
//if an exception occurred and status is "Not Found", this is working as expected
Console.WriteLine("Failed to find index and this is because it's not there.");
}
}
private static SearchIndex DefineTestIndex() =>
new SearchIndex("test-idx", new[] { new SearchField("id", SearchFieldDataType.String) { IsKey = true } });
}
}
Padrão de design
Um padrão de design para implementar a simultaneidade otimista deve incluir um loop que repita a verificação da condição de acesso, um teste para essa condição e, opcionalmente, recuperar um recurso atualizado antes de tentar reaplicar as alterações.
Este snippet de código mostra a adição de um synonymMap para um índice que já existe.
O snippet obtém o índice de exemplo de hotéis, verifica a versão do objeto em uma operação de atualização, gera uma exceção se a condição falha e, em seguida, tenta novamente a operação (até três vezes), começando com a recuperação de índice do servidor para obter a versão mais recente.
private static void EnableSynonymsInHotelsIndexSafely(SearchIndexClient indexClient)
{
int MaxNumTries = 3;
for (int i = 0; i < MaxNumTries; ++i)
{
try
{
SearchIndex index = indexClient.GetIndex("hotels-sample");
index = AddSynonymMapsToFields(index);
// The onlyIfUnchangedcondition ensures that the index is updated only if the ETags match.
indexClient.CreateOrUpdateIndex(index, onlyIfUnchanged: true);
Console.WriteLine("Updated the index successfully.\n");
break;
}
catch (RequestFailedException e) when (e.Status == 412)
{
Console.WriteLine($"Index update failed : {e.Message}. Attempt({i}/{MaxNumTries}).\n");
}
}
}
private static SearchIndex AddSynonymMapsToFields(SearchIndex index)
{
index.Fields.First(f => f.Name == "category").SynonymMapNames.Add("desc-synonymmap");
index.Fields.First(f => f.Name == "tags").SynonymMapNames.Add("desc-synonymmap");
return index;
}
Confira também
- ETag Struct
- Propriedade SearchIndex.ETag
- Método SearchIndexClient.CreateOrUpdateIndex
- Códigos de status HTTP