Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Uwaga
Wyszukiwanie AI platformy Azure jest dostępna za pośrednictwem portalu Azure, interfejsów API REST i Azure SDKs. Jest także podstawą Foundry IQ — zarządzanej warstwy wiedzy, która przekształca treści przedsiębiorstwa w bazy wiedzy wielokrotnego użytku z uwzględnieniem uprawnień dla agentów w portalu Microsoft Foundry.
Podczas zarządzania zasobami Wyszukiwanie AI platformy Azure, takimi jak indeksy i źródła danych, ważne jest, aby bezpiecznie aktualizować zasoby, zwłaszcza jeśli zasoby są dostępne współbieżnie przez różne składniki aplikacji.
- Operacje aktualizacji zasobów mogą nie zostać ukończone natychmiast. Na przykład zaktualizowanie indeksu lub indeksatora może potrwać kilka sekund. Aktualizacje zasobów są serializowane, co oznacza, że wiele operacji aktualizacji może nie być uruchamianych jednocześnie w tym samym zasobie.
- Gdy dwaj klienci jednocześnie aktualizują zasób bez koordynacji, możliwy jest warunek wyścigu . Jeden klient może rozpocząć operację aktualizacji, podczas gdy drugi klient otrzymuje błąd konfliktu. Aby temu zapobiec, Wyszukiwanie AI platformy Azure obsługuje model współbieżności optymistyczny. Zasób nie ma blokad. Zamiast tego istnieje element ETag dla każdego zasobu, który identyfikuje wersję zasobu, dzięki czemu można sformułować żądania, które unikają przypadkowego zastąpienia.
Jak to działa
Optymistyczna współbieżność jest implementowana za pomocą sprawdzania warunków dostępu w wywołaniach interfejsu API zapisywania do indeksów, indeksatorów, źródeł danych, zestawów umiejętności, baz wiedzy i map zasobów synonimów.
Wszystkie zasoby mają tag jednostki (ETag), który udostępnia informacje o wersji obiektu. Sprawdzając najpierw ETag, można uniknąć współbieżnych aktualizacji w typowym przepływie pracy (pobierz, zmodyfikuj lokalnie, aktualizuj), zapewniając zgodność ETag zasobu z kopią lokalną.
Interfejs API REST używa ETag w nagłówku żądania.
Pakiet SDK Azure dla .NET ustawia wartość ETag za pośrednictwem klasy accessCondition, ustawiając nagłówek If-Match | If-Match-None na zasobie. Obiekty używające elementów ETag, takich jak SynonymMap.ETag i SearchIndex.ETag mają klasę accessCondition.
Za każdym razem, gdy aktualizujesz zasób, jego element ETag zmienia się automatycznie. Podczas implementowania zarządzania współbieżnością wszystko, co robisz, to wprowadzenie warunku wstępnego dla żądania aktualizacji, które wymaga, aby zasób zdalny miał ten sam element ETag co kopia zasobu zmodyfikowanego na kliencie. Jeśli inny proces zmieni zasób zdalny, element ETag nie jest zgodny z warunkiem wstępnym, a żądanie zakończy się niepowodzeniem z protokołem HTTP 412 lub 409. Jeśli używasz zestawu SDK .NET, ten błąd manifestuje się jako wyjątek, w którym metoda rozszerzenia IsAccessConditionFailed() zwraca wartość true.
Uwaga
Istnieje tylko jeden mechanizm współbieżności. Jest ona zawsze używana niezależnie od tego, który interfejs API lub zestaw SDK jest używany do aktualizacji zasobów. Od 18 lipca 2025 r. Wyszukiwanie AI platformy Azure rozpoczęła wymuszanie serializacji na potrzeby operacji tworzenia indeksów i aktualizacji w celu zapewnienia spójności i niezawodności.
Przykład
Poniższy kod demonstruje optymistyczną współbieżność dla operacji aktualizacji. Druga aktualizacja kończy się niepowodzeniem, ponieważ element ETag obiektu został zmieniony przez poprzednią aktualizację. Mówiąc dokładniej, gdy etykieta ETag w nagłówku żądania nie pasuje już do etykiety ETag obiektu, usługa wyszukiwania zwraca kod stanu 400 (nieprawidłowe żądanie), a aktualizacja kończy się niepowodzeniem.
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 } });
}
}
Wzorzec projektowania
Wzorzec projektu dla implementacji optymistycznej współbieżności powinien zawierać pętlę, która ponawia sprawdzanie warunku dostępu, test warunku dostępu oraz opcjonalnie pobiera zaktualizowany zasób przed próbą ponownego wprowadzenia zmian.
Ten fragment kodu pokazuje dodanie schematu synonimów do istniejącego indeksu.
Fragment kodu pobiera indeks hotels-sample, sprawdza wersję obiektu w operacji aktualizacji, zgłasza wyjątek w przypadku niepowodzenia warunku, a następnie ponawia próbę operacji (do trzech razy), począwszy od pobierania indeksu z serwera w celu uzyskania najnowszej wersji.
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;
}