From a39856db9c84652f11a997a5ed28c568aaed3ff4 Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 11 Sep 2026 15:44:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96es=20idx=20404?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/TrackCenter.Repository/ES/EsExtensions.cs | 70 +++++++++++++++- .../Repositories/TrackDetailsEsRepository.cs | 81 ++++++++++++++----- 2 files changed, 129 insertions(+), 22 deletions(-) diff --git a/src/TrackCenter.Repository/ES/EsExtensions.cs b/src/TrackCenter.Repository/ES/EsExtensions.cs index cbc9bf06..2b0e1578 100644 --- a/src/TrackCenter.Repository/ES/EsExtensions.cs +++ b/src/TrackCenter.Repository/ES/EsExtensions.cs @@ -1,5 +1,5 @@ -using TrackCenter.Repository.ES; using Nest; +using TrackCenter.Domain.Consts; using TrackCenter.Domain.SeedWork; namespace TrackCenter.Repository.ES; @@ -9,12 +9,74 @@ namespace TrackCenter.Repository.ES; /// public static class EsExtensions { + /// + /// 轨迹明细实际写入月度索引 track_details-yyyy.MM;读请求走通配符, + /// 无匹配索引时返回空结果(首次部署 / 尚未 Migrate 别名)。 + /// + public static SearchDescriptor UseTrackDetailsIndex(this SearchDescriptor descriptor) where T : class + { + return descriptor + .Index($"{GlobalConst.TrackDetailsIndex}-*") + .IgnoreUnavailable() + .AllowNoIndices(); + } + + /// + /// 轨迹明细按查询更新:目标索引不存在时视为无匹配文档。 + /// + public static UpdateByQueryDescriptor UseTrackDetailsIndex(this UpdateByQueryDescriptor descriptor) + where T : class + { + return descriptor + .Index($"{GlobalConst.TrackDetailsIndex}-*") + .IgnoreUnavailable() + .AllowNoIndices(); + } + + public static DeleteByQueryDescriptor UseTrackDetailsIndex(this DeleteByQueryDescriptor descriptor) + where T : class + { + return descriptor + .Index($"{GlobalConst.TrackDetailsIndex}-*") + .IgnoreUnavailable() + .AllowNoIndices(); + } + + /// + /// 索引/别名不存在(含 NEST 对 404 的包装错误)。 + /// + public static bool IsIndexUnavailable(this IResponse response) + { + if (response.IsValid) + return false; + + if (response.ApiCall?.HttpStatusCode == 404) + return true; + + if (IsIndexNotFoundType(response.ServerError?.Error?.Type) + || IsIndexNotFoundType(response.ServerError?.Error?.CausedBy?.Type)) + return true; + + var rootCauses = response.ServerError?.Error?.RootCause; + if (rootCauses != null && rootCauses.Any(x => IsIndexNotFoundType(x.Type))) + return true; + + // NEST: Invalid NEST response built from a successful (404) low level call on POST: /track_details/_search + var debug = response.DebugInformation; + if (!string.IsNullOrEmpty(debug) + && (debug.Contains("index_not_found_exception", StringComparison.OrdinalIgnoreCase) + || debug.Contains("successful (404)", StringComparison.OrdinalIgnoreCase))) + return true; + + return false; + } + + private static bool IsIndexNotFoundType(string? type) => + string.Equals(type, "index_not_found_exception", StringComparison.OrdinalIgnoreCase); + /// /// return list with id /// - /// - /// - /// public static List ToIdList(this ISearchResponse response) where T : IdBaseIndex { var dtos = new List(); diff --git a/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs b/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs index e1582145..6402cc23 100644 --- a/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs +++ b/src/TrackCenter.Repository/Repositories/TrackDetailsEsRepository.cs @@ -25,7 +25,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(s => s - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Source() .Version() .Size(SafelyLimit) @@ -39,7 +39,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(s => s - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Source(s2 => s2.Includes(fd => fd .Field(f => f.IndexName) @@ -60,6 +60,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException( $"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCode:{trackCode},原因:{r.DebugInformation}。"); } @@ -126,7 +129,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Query(q => q.Bool(b => b .Should(musts) @@ -137,7 +140,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Query(q => q.Bool(b => b .Must(musts) @@ -148,6 +151,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>(); + throw new InvalidOperationException($"运输预警明细查询失败,原因:{r.DebugInformation}。"); } @@ -159,7 +165,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>> GetTrackStatusEarliestDictAsync(HashSet orderIds) { var response = await Context.SearchAsync(s => s - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Size(0) // 不需要实际文档,只需要聚合结果 .Query(q => q .Terms(t => t @@ -191,6 +197,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract>(); + throw new InvalidOperationException( $"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],原因:{response.DebugInformation}。"); } @@ -226,7 +235,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetLatestDictAsync(HashSet orderIds) { var r = await Context.SearchAsync(s => s - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Size(0) // 不需要实际文档,只需要聚合结果 .Query(q => q .Terms(t => t @@ -253,6 +262,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException( $"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],原因:{r.DebugInformation}。"); } @@ -281,7 +293,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Source(s => s.Includes(fd => fd .Field(f => f.TrackEnContent) .Field(f => f.TrackContent) @@ -335,6 +347,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException( $"最新轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{r.DebugInformation}。"); } @@ -345,7 +360,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract AnyAsync(int orderId, string originTrackDataHash) { var r = await Context.SearchAsync(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Source(s => s.Includes(fd => fd.Field(f => f.TrackCode))) .Query(q => q.Term(f => f.OrderId, orderId) @@ -355,6 +370,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(u => u - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Query(q => q .Ids(t => t.Values(indexes.Select(x => x.Id))) ) @@ -465,7 +483,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract Context.BulkAsync(desc), successValidator: response => { - if (response.IsValid) // 认为成功 + if (response.IsValid || response.IsIndexUnavailable()) // 认为成功或索引不存在 return true; if (response.ServerError.Status == 409) //版本冲突认为失败,则重试 @@ -620,7 +638,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Source() .Version() .Query(q => @@ -637,6 +655,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException( $"轨迹查询失败,orderType:{orderType},orderNos:{orderNos},原因:{r.DebugInformation}。"); } @@ -647,7 +668,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetListAsync(int orderId) { var r = await Context.SearchAsync(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Query(q => q.Term(t => t.OrderId, orderId) @@ -660,6 +681,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException($"轨迹查询失败,orderId:{orderId},原因:{r.DebugInformation}。"); } @@ -686,7 +710,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Query(_ => query) .Size(SafelyLimit) @@ -697,6 +721,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException($"轨迹查询失败,orderIds:[{string.Join(',', orderIds)}],原因:{r.DebugInformation}。"); } @@ -720,7 +747,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Source(s => s.Includes(fd => fd .Field(f => f.IndexName) @@ -736,6 +763,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException( $"轨迹查询失败,orderIds:[{orderIds.JoinAsString(", ")}],trackCodes:[{trackCodes.JoinAsString(", ")}],原因:{search.DebugInformation}。"); } @@ -774,12 +804,15 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract esIds) { var r = await Context.DeleteByQueryAsync(x => x - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Query(q => q.Ids(i => i.Values(esIds))) ); if (!r.IsValid) { + if (r.IsIndexUnavailable()) + return; + throw new InvalidOperationException($"轨迹删除失败,ids:[{string.Join(", ", esIds)}],原因:{r.DebugInformation}。"); } } @@ -787,7 +820,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract> GetDataByIds(string[] ids) { var r = await Context.SearchAsync(m => m - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Version() .Query( q => q.Ids(i => i.Values(ids)) @@ -795,6 +828,9 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract(); + throw new InvalidOperationException($"轨迹查询失败,ids:[{string.Join(", ", ids)}],原因:{r.DebugInformation}。"); } @@ -804,7 +840,7 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract GetDetailAsync(string orderNo, string trackCode, TrackOrderType orderType, string appKey, DateTime trackTime) { var res = await Context.SearchAsync(s => s - .Index(GlobalConst.TrackDetailsIndex) + .UseTrackDetailsIndex() .Query(q => q .Bool(b => b .Must(mu => mu @@ -832,6 +868,15 @@ public class TrackDetailsEsRepository : ElasticSearchContextAbstract