@HeatherNakama 的另一个回答非常有帮助。我想补充一点,但首先是一个意译的摘要:
没有办法可靠地知道文档已准备好在所有副本上进行搜索,因此等待找到文档的自旋锁唯一可行的方法是使用单副本搜索服务。(注意:免费层级搜索服务不是单副本,您对此无能为力。)
考虑到这一点,我创建了一个包含 Azure 搜索集成测试的示例存储库,大致如下所示:
private readonly ISearchIndexClient _searchIndexClient;
private void WaitForIndexing(string id)
{
// For the free tier, or a service with multiple replicas, resort to this:
// Thread.Sleep(2000);
var wait = 25;
while (wait <= 2000)
{
Thread.Sleep(wait);
var result = fixture.SearchService.FilterForId(id);
if (result.Result.Results.Count == 1) return;
if (result.Result.Results.Count > 1) throw new Exception("Unexpected results");
wait *= 2;
}
throw new Exception("Found nothing after waiting a while");
}
public async Task<DocumentSearchResult<PersonDto>> FilterForId(string id)
{
if (string.IsNullOrWhiteSpace(id) || !Guid.TryParse(id, out var _))
{
throw new ArgumentException("Can only filter for guid-like strings", nameof(id));
}
var parameters = new SearchParameters
{
Top = 2, // We expect only one, but return max 2 so we can double check for errors
Skip = 0,
Facets = new string[] { },
HighlightFields = new string[] { },
Filter = $"id eq '{id}'",
OrderBy = new[] { "search.score() desc", "registeredAtUtc desc" },
};
var result = await _searchIndexClient.Documents.SearchAsync<PersonDto>("*", parameters);
if (result.Results.Count > 1)
{
throw new Exception($"Search filtering for id '{id}' unexpectedly returned more than 1 result. Are you sure you searched for an ID, and that it is unique?");
}
return result;
}
这可能会像这样使用:
[SerializePropertyNamesAsCamelCase]
public class PersonDto
{
[Key] [IsFilterable] [IsSearchable]
public string Id { get; set; } = Guid.NewGuid().ToString();
[IsSortable] [IsSearchable]
public string Email { get; set; }
[IsSortable]
public DateTimeOffset? RegisteredAtUtc { get; set; }
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(5)]
[InlineData(10)]
public async Task Can_index_and_then_find_person_many_times_in_a_row(int count)
{
await fixture.SearchService.RecreateIndex();
for (int i = 0; i < count; i++)
{
var guid = Guid.NewGuid().ToString().Replace("-", "");
var dto = new PersonDto { Email = $"{guid}@example.org" };
await fixture.SearchService.IndexAsync(dto);
WaitForIndexing(dto);
var searchResult = await fixture.SearchService.Search(dto.Id);
Assert.Single(searchResult.Results, p => p.Document.Id == dto.Id);
}
}
我已经测试并确认这在具有 1 个副本的基本层搜索服务上可靠地保持绿色,并且在免费层上间歇性地变为红色。