diff --git a/src/ApiGenerator/Configuration/CodeConfiguration.cs b/src/ApiGenerator/Configuration/CodeConfiguration.cs index 00cd565c42..67c203f206 100644 --- a/src/ApiGenerator/Configuration/CodeConfiguration.cs +++ b/src/ApiGenerator/Configuration/CodeConfiguration.cs @@ -47,6 +47,7 @@ public static class CodeConfiguration new("dangling_indices.*"), new("indices.{delete,exists,get,put}_index_template"), + new("indices.stats"), new("ingest.*"), new("nodes.*"), diff --git a/src/ApiGenerator/Configuration/Overrides/Endpoints/IndicesStatsOverrides.cs b/src/ApiGenerator/Configuration/Overrides/Endpoints/IndicesStatsOverrides.cs deleted file mode 100644 index bb14a30b68..0000000000 --- a/src/ApiGenerator/Configuration/Overrides/Endpoints/IndicesStatsOverrides.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -*/ -/* -* Modifications Copyright OpenSearch Contributors. See -* GitHub history for details. -* -* Licensed to Elasticsearch B.V. under one or more contributor -* license agreements. See the NOTICE file distributed with -* this work for additional information regarding copyright -* ownership. Elasticsearch B.V. licenses this file to you under -* the Apache License, Version 2.0 (the "License"); you may -* not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, -* software distributed under the License is distributed on an -* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -* KIND, either express or implied. See the License for the -* specific language governing permissions and limitations -* under the License. -*/ - -using System.Collections.Generic; - -namespace ApiGenerator.Configuration.Overrides.Endpoints -{ - // ReSharper disable once UnusedMember.Global - public class IndicesStatsOverrides : EndpointOverridesBase - { - public override IEnumerable SkipQueryStringParams => new[] - { - "types" - }; - } -} diff --git a/src/OpenSearch.Client/ApiUrlsLookup.cs b/src/OpenSearch.Client/ApiUrlsLookup.cs index 8937a41d24..69dd3f37bf 100644 --- a/src/OpenSearch.Client/ApiUrlsLookup.cs +++ b/src/OpenSearch.Client/ApiUrlsLookup.cs @@ -96,7 +96,6 @@ internal static partial class ApiUrlsLookups internal static ApiUrls IndicesShardStores = new ApiUrls(new[]{"_shard_stores", "{index}/_shard_stores"}); internal static ApiUrls IndicesShrink = new ApiUrls(new[]{"{index}/_shrink/{target}"}); internal static ApiUrls IndicesSplit = new ApiUrls(new[]{"{index}/_split/{target}"}); - internal static ApiUrls IndicesStats = new ApiUrls(new[]{"_stats", "_stats/{metric}", "{index}/_stats", "{index}/_stats/{metric}"}); internal static ApiUrls IndicesBulkAlias = new ApiUrls(new[]{"_aliases"}); internal static ApiUrls IndicesValidateQuery = new ApiUrls(new[]{"_validate/query", "{index}/_validate/query"}); internal static ApiUrls NoNamespaceRootNodeInfo = new ApiUrls(new[]{""}); diff --git a/src/OpenSearch.Client/Indices/Stats/IndicesStatsRequest.cs b/src/OpenSearch.Client/Indices/Stats/IndicesStatsRequest.cs new file mode 100644 index 0000000000..906beed0f3 --- /dev/null +++ b/src/OpenSearch.Client/Indices/Stats/IndicesStatsRequest.cs @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +namespace OpenSearch.Client; + +[MapsApi("indices.stats")] +[ReadAs(typeof(IndicesStatsRequest))] +public partial interface IIndicesStatsRequest +{ +} + +public partial class IndicesStatsRequest +{ +} + +public partial class IndicesStatsDescriptor +{ +} diff --git a/src/OpenSearch.Client/Indices/Stats/IndicesStatsResponse.cs b/src/OpenSearch.Client/Indices/Stats/IndicesStatsResponse.cs new file mode 100644 index 0000000000..545df60e18 --- /dev/null +++ b/src/OpenSearch.Client/Indices/Stats/IndicesStatsResponse.cs @@ -0,0 +1,244 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System.Collections.Generic; +using System.Runtime.Serialization; +using OpenSearch.Net; +using OpenSearch.Net.Utf8Json; + +namespace OpenSearch.Client; + +[DataContract] +public class IndicesStatsResponse : ResponseBase +{ + [DataMember(Name = "_all")] + public AllIndicesStats All { get; internal set; } + + [DataMember(Name = "_shards")] + public ShardStatistics Shards { get; internal set; } + + [DataMember(Name = "indices")] + public IndicesStatsDictionary Indices { get; internal set; } +} + +[JsonFormatter(typeof(Converter))] +public class IndicesStatsDictionary : ResolvableDictionaryProxy +{ + private IndicesStatsDictionary(IConnectionConfigurationValues s, IReadOnlyDictionary d) + : base(s, d) { } + + private class Converter : ResolvableDictionaryFormatterBase + { + protected override IndicesStatsDictionary Create(IConnectionSettingsValues s, Dictionary d) => new(s, d); + } +} + +[DataContract] +public class AllIndicesStats +{ + [DataMember(Name = "primaries")] + public IndexStats Primaries { get; internal set; } + + [DataMember(Name = "total")] + public IndexStats Total { get; internal set; } +} + +[DataContract] +public class IndicesStats +{ + [DataMember(Name = "uuid")] + public string Uuid { get; internal set; } + + [DataMember(Name = "primaries")] + public IndexStats Primaries { get; internal set; } + + [DataMember(Name = "total")] + public IndexStats Total { get; internal set; } + + [DataMember(Name = "shards")] + public IReadOnlyDictionary> Shards { get; internal set; } +} + +[DataContract] +public abstract class IndexStatsBase +{ + [DataMember(Name = "docs")] + public DocStats Documents { get; internal set; } + + [DataMember(Name = "store")] + public StoreStats Store { get; internal set; } + + [DataMember(Name = "indexing")] + public IndexingStats Indexing { get; internal set; } + + [DataMember(Name = "get")] + public GetStats Get { get; internal set; } + + [DataMember(Name = "search")] + public SearchStats Search { get; internal set; } + + [DataMember(Name = "merges")] + public MergesStats Merges { get; internal set; } + + [DataMember(Name = "refresh")] + public RefreshStats Refresh { get; internal set; } + + [DataMember(Name = "flush")] + public FlushStats Flush { get; internal set; } + + [DataMember(Name = "warmer")] + public WarmerStats Warmer { get; internal set; } + + [DataMember(Name = "query_cache")] + public QueryCacheStats QueryCache { get; internal set; } + + [DataMember(Name = "fielddata")] + public FielddataStats Fielddata { get; internal set; } + + [DataMember(Name = "completion")] + public CompletionStats Completion { get; internal set; } + + [DataMember(Name = "segments")] + public SegmentsStats Segments { get; internal set; } + + [DataMember(Name = "translog")] + public TranslogStats Translog { get; internal set; } + + [DataMember(Name = "request_cache")] + public RequestCacheStats RequestCache { get; internal set; } + + [DataMember(Name = "recovery")] + public RecoveryStats Recovery { get; internal set; } +} + +[DataContract] +public class IndexStats : IndexStatsBase +{ + +} + +[DataContract] +public class IndexShardStats : IndexStatsBase +{ + [DataMember(Name = "routing")] + public ShardRouting Routing { get; internal set; } + + [DataMember(Name = "commit")] + public ShardCommitStats Commit { get; internal set; } + + [DataMember(Name = "seq_no")] + public ShardSequenceNumberStats SequenceNumber { get; internal set; } + + [DataMember(Name = "retention_leases")] + public ShardRetentionLeasesStats RetentionLeases { get; internal set; } + + [DataMember(Name = "shard_path")] + public ShardPath ShardPath { get; internal set; } +} + +[DataContract] +public class ShardRouting +{ + [DataMember(Name = "state")] + public ShardRoutingState State { get; internal set; } + + [DataMember(Name = "primary")] + public bool Primary { get; internal set; } + + [DataMember(Name = "node")] + public string Node { get; internal set; } + + [DataMember(Name = "relocating_node")] + public string RelocatingNode { get; internal set; } +} + +[StringEnum] +public enum ShardRoutingState +{ + [EnumMember(Value = "INITIALIZING")] + Initializing, + + [EnumMember(Value = "RELOCATING")] + Relocating, + + [EnumMember(Value = "STARTED")] + Started, + + [EnumMember(Value = "UNASSIGNED")] + Unassigned +} + +[DataContract] +public class ShardCommitStats +{ + [DataMember(Name = "id")] + public string Id { get; internal set; } + + [DataMember(Name = "generation")] + public long Generation { get; internal set; } + + [DataMember(Name = "num_docs")] + public int NumDocs { get; internal set; } + + [DataMember(Name = "user_data")] + public IReadOnlyDictionary UserData { get; internal set; } +} + +[DataContract] +public class ShardSequenceNumberStats +{ + [DataMember(Name = "max_seq_no")] + public long MaxSequenceNumber { get; internal set; } + + [DataMember(Name = "local_checkpoint")] + public long LocalCheckpoint { get; internal set; } + + [DataMember(Name = "global_checkpoint")] + public long GlobalCheckpoint { get; internal set; } +} + +[DataContract] +public class ShardRetentionLeasesStats +{ + [DataMember(Name = "primary_term")] + public long PrimaryTerm { get; internal set; } + + [DataMember(Name = "version")] + public long Version { get; internal set; } + + [DataMember(Name = "leases")] + public IReadOnlyCollection Leases { get; internal set; } +} + +[DataContract] +public class ShardRetentionLease +{ + [DataMember(Name = "id")] + public string Id { get; internal set; } + + [DataMember(Name = "retaining_seq_no")] + public long RetainingSequenceNumber { get; internal set; } + + [DataMember(Name = "timestamp")] + public long Timestamp { get; internal set; } + + [DataMember(Name = "source")] + public string Source { get; internal set; } +} + +[DataContract] +public class ShardPath +{ + [DataMember(Name = "state_path")] + public string StatePath { get; internal set; } + + [DataMember(Name = "data_path")] + public string DataPath { get; internal set; } + + [DataMember(Name = "is_custom_data_path")] + public bool IsCustomDataPath { get; internal set; } +} diff --git a/src/OpenSearch.Client/_Generated/ApiUrlsLookup.cs b/src/OpenSearch.Client/_Generated/ApiUrlsLookup.cs index cb20f45805..e1ecc5f08b 100644 --- a/src/OpenSearch.Client/_Generated/ApiUrlsLookup.cs +++ b/src/OpenSearch.Client/_Generated/ApiUrlsLookup.cs @@ -186,6 +186,9 @@ internal static partial class ApiUrlsLookups internal static readonly ApiUrls IndicesPutComposableTemplate = new(new[] { "_index_template/{name}" }); + internal static readonly ApiUrls IndicesStats = + new(new[] { "_stats", "{index}/_stats", "{index}/_stats/{metric}", "_stats/{metric}" }); + internal static readonly ApiUrls IngestDeletePipeline = new(new[] { "_ingest/pipeline/{id}" }); diff --git a/src/OpenSearch.Client/_Generated/Descriptors.Indices.cs b/src/OpenSearch.Client/_Generated/Descriptors.Indices.cs index 6e49115199..b50f662d3e 100644 --- a/src/OpenSearch.Client/_Generated/Descriptors.Indices.cs +++ b/src/OpenSearch.Client/_Generated/Descriptors.Indices.cs @@ -241,4 +241,108 @@ public PutComposableIndexTemplateDescriptor Create(bool? create = true) => public PutComposableIndexTemplateDescriptor MasterTimeout(Time mastertimeout) => Qs("master_timeout", mastertimeout); } + + /// Descriptor for Stats https://opensearch.org/docs/latest + public partial class IndicesStatsDescriptor + : RequestDescriptorBase< + IndicesStatsDescriptor, + IndicesStatsRequestParameters, + IIndicesStatsRequest + >, + IIndicesStatsRequest + { + internal override ApiUrls ApiUrls => ApiUrlsLookups.IndicesStats; + + /// /_stats + public IndicesStatsDescriptor() + : base() { } + + /// /{index}/_stats + /// Optional, accepts null + public IndicesStatsDescriptor(Indices index) + : base(r => r.Optional("index", index)) { } + + /// /{index}/_stats/{metric} + /// Optional, accepts null + /// Optional, accepts null + public IndicesStatsDescriptor(Indices index, Metrics metric) + : base(r => r.Optional("index", index).Optional("metric", metric)) { } + + /// /_stats/{metric} + /// Optional, accepts null + public IndicesStatsDescriptor(Metrics metric) + : base(r => r.Optional("metric", metric)) { } + + // values part of the url path + Indices IIndicesStatsRequest.Index => Self.RouteValues.Get("index"); + Metrics IIndicesStatsRequest.Metric => Self.RouteValues.Get("metric"); + + /// A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices. + public IndicesStatsDescriptor Index(Indices index) => + Assign(index, (a, v) => a.RouteValues.Optional("index", v)); + + /// a shortcut into calling Index(typeof(TOther)) + public IndicesStatsDescriptor Index() + where TOther : class => + Assign(typeof(TOther), (a, v) => a.RouteValues.Optional("index", (Indices)v)); + + /// A shortcut into calling Index(Indices.All) + public IndicesStatsDescriptor AllIndices() => Index(Indices.All); + + /// Limit the information returned the specific metrics. + public IndicesStatsDescriptor Metric(Metrics metric) => + Assign(metric, (a, v) => a.RouteValues.Optional("metric", v)); + + // Request parameters + /// Comma-separated list or wildcard expressions of fields to include in fielddata and suggest statistics. + public IndicesStatsDescriptor CompletionFields(Fields completionfields) => + Qs("completion_fields", completionfields); + + /// Comma-separated list or wildcard expressions of fields to include in fielddata and suggest statistics. + public IndicesStatsDescriptor CompletionFields( + params Expression>[] fields + ) + where T : class => Qs("completion_fields", fields?.Select(e => (Field)e)); + + /// Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard expressions match hidden data streams. Supports comma-separated values, such as `open,hidden`. + public IndicesStatsDescriptor ExpandWildcards(ExpandWildcards? expandwildcards) => + Qs("expand_wildcards", expandwildcards); + + /// Comma-separated list or wildcard expressions of fields to include in fielddata statistics. + public IndicesStatsDescriptor FielddataFields(Fields fielddatafields) => + Qs("fielddata_fields", fielddatafields); + + /// Comma-separated list or wildcard expressions of fields to include in fielddata statistics. + public IndicesStatsDescriptor FielddataFields( + params Expression>[] fields + ) + where T : class => Qs("fielddata_fields", fields?.Select(e => (Field)e)); + + /// Comma-separated list or wildcard expressions of fields to include in the statistics. + public IndicesStatsDescriptor Fields(Fields fields) => Qs("fields", fields); + + /// Comma-separated list or wildcard expressions of fields to include in the statistics. + public IndicesStatsDescriptor Fields(params Expression>[] fields) + where T : class => Qs("fields", fields?.Select(e => (Field)e)); + + /// If true, statistics are not collected from closed indices. + public IndicesStatsDescriptor ForbidClosedIndices(bool? forbidclosedindices = true) => + Qs("forbid_closed_indices", forbidclosedindices); + + /// Comma-separated list of search groups to include in the search statistics. + public IndicesStatsDescriptor Groups(params string[] groups) => Qs("groups", groups); + + /// If true, the call reports the aggregated disk usage of each one of the Lucene index files (only applies if segment stats are requested). + public IndicesStatsDescriptor IncludeSegmentFileSizes( + bool? includesegmentfilesizes = true + ) => Qs("include_segment_file_sizes", includesegmentfilesizes); + + /// If true, the response includes information from segments that are not loaded into memory. + public IndicesStatsDescriptor IncludeUnloadedSegments( + bool? includeunloadedsegments = true + ) => Qs("include_unloaded_segments", includeunloadedsegments); + + /// Indicates whether statistics are aggregated at the cluster, index, or shard level. + public IndicesStatsDescriptor Level(Level? level) => Qs("level", level); + } } diff --git a/src/OpenSearch.Client/_Generated/OpenSearchClient.Indices.cs b/src/OpenSearch.Client/_Generated/OpenSearchClient.Indices.cs index 35b4191243..84a8454f10 100644 --- a/src/OpenSearch.Client/_Generated/OpenSearchClient.Indices.cs +++ b/src/OpenSearch.Client/_Generated/OpenSearchClient.Indices.cs @@ -232,6 +232,44 @@ Task PutComposableTemplateAsync( IPutComposableIndexTemplateRequest request, CancellationToken ct = default ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + IndicesStatsResponse Stats( + Indices index = null, + Func selector = null + ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + Task StatsAsync( + Indices index = null, + Func selector = null, + CancellationToken ct = default + ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + IndicesStatsResponse Stats(IIndicesStatsRequest request); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + Task StatsAsync( + IIndicesStatsRequest request, + CancellationToken ct = default + ); } /// @@ -489,5 +527,56 @@ public Task PutComposableTemplateAsync( request.RequestParameters, ct ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + public IndicesStatsResponse Stats( + Indices index = null, + Func selector = null + ) => Stats(selector.InvokeOrDefault(new IndicesStatsDescriptor().Index(index: index))); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + public Task StatsAsync( + Indices index = null, + Func selector = null, + CancellationToken ct = default + ) => + StatsAsync( + selector.InvokeOrDefault(new IndicesStatsDescriptor().Index(index: index)), + ct + ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + public IndicesStatsResponse Stats(IIndicesStatsRequest request) => + DoRequest( + request, + request.RequestParameters + ); + + /// + /// GET request to the indices.stats API, read more about this API online: + /// + /// https://opensearch.org/docs/latest + /// + public Task StatsAsync( + IIndicesStatsRequest request, + CancellationToken ct = default + ) => + DoRequestAsync( + request, + request.RequestParameters, + ct + ); } } diff --git a/src/OpenSearch.Client/_Generated/Requests.Indices.cs b/src/OpenSearch.Client/_Generated/Requests.Indices.cs index 8b3c196a4b..11508b9ac1 100644 --- a/src/OpenSearch.Client/_Generated/Requests.Indices.cs +++ b/src/OpenSearch.Client/_Generated/Requests.Indices.cs @@ -317,4 +317,117 @@ public Time MasterTimeout set => Q("master_timeout", value); } } + + [InterfaceDataContract] + public partial interface IIndicesStatsRequest : IRequest + { + [IgnoreDataMember] + Indices Index { get; } + + [IgnoreDataMember] + Metrics Metric { get; } + } + + /// Request for Stats https://opensearch.org/docs/latest + public partial class IndicesStatsRequest + : PlainRequestBase, + IIndicesStatsRequest + { + protected IIndicesStatsRequest Self => this; + internal override ApiUrls ApiUrls => ApiUrlsLookups.IndicesStats; + + /// /_stats + public IndicesStatsRequest() + : base() { } + + /// /{index}/_stats + /// Optional, accepts null + public IndicesStatsRequest(Indices index) + : base(r => r.Optional("index", index)) { } + + /// /{index}/_stats/{metric} + /// Optional, accepts null + /// Optional, accepts null + public IndicesStatsRequest(Indices index, Metrics metric) + : base(r => r.Optional("index", index).Optional("metric", metric)) { } + + /// /_stats/{metric} + /// Optional, accepts null + public IndicesStatsRequest(Metrics metric) + : base(r => r.Optional("metric", metric)) { } + + // values part of the url path + [IgnoreDataMember] + Indices IIndicesStatsRequest.Index => Self.RouteValues.Get("index"); + + [IgnoreDataMember] + Metrics IIndicesStatsRequest.Metric => Self.RouteValues.Get("metric"); + + // Request parameters + /// Comma-separated list or wildcard expressions of fields to include in fielddata and suggest statistics. + public Fields CompletionFields + { + get => Q("completion_fields"); + set => Q("completion_fields", value); + } + + /// + /// Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard + /// expressions match hidden data streams. Supports comma-separated values, such as `open,hidden`. + /// + public ExpandWildcards? ExpandWildcards + { + get => Q("expand_wildcards"); + set => Q("expand_wildcards", value); + } + + /// Comma-separated list or wildcard expressions of fields to include in fielddata statistics. + public Fields FielddataFields + { + get => Q("fielddata_fields"); + set => Q("fielddata_fields", value); + } + + /// Comma-separated list or wildcard expressions of fields to include in the statistics. + public Fields Fields + { + get => Q("fields"); + set => Q("fields", value); + } + + /// If true, statistics are not collected from closed indices. + public bool? ForbidClosedIndices + { + get => Q("forbid_closed_indices"); + set => Q("forbid_closed_indices", value); + } + + /// Comma-separated list of search groups to include in the search statistics. + public string[] Groups + { + get => Q("groups"); + set => Q("groups", value); + } + + /// If true, the call reports the aggregated disk usage of each one of the Lucene index files (only applies if segment stats are requested). + public bool? IncludeSegmentFileSizes + { + get => Q("include_segment_file_sizes"); + set => Q("include_segment_file_sizes", value); + } + + /// If true, the response includes information from segments that are not loaded into memory. + public bool? IncludeUnloadedSegments + { + get => Q("include_unloaded_segments"); + set => Q("include_unloaded_segments", value); + } + + /// Indicates whether statistics are aggregated at the cluster, index, or shard level. + public Level? Level + { + get => Q("level"); + set => Q("level", value); + } + } } diff --git a/src/OpenSearch.Net/Api/RequestParameters/RequestParameters.Indices.cs b/src/OpenSearch.Net/Api/RequestParameters/RequestParameters.Indices.cs index 64ccb1bf5e..7c400b400d 100644 --- a/src/OpenSearch.Net/Api/RequestParameters/RequestParameters.Indices.cs +++ b/src/OpenSearch.Net/Api/RequestParameters/RequestParameters.Indices.cs @@ -1642,75 +1642,6 @@ public string WaitForActiveShards } } - ///Request options for Stats https://opensearch.org/docs/latest/opensearch/stats-api/ - public class IndicesStatsRequestParameters : RequestParameters - { - public override HttpMethod DefaultHttpMethod => HttpMethod.GET; - public override bool SupportsBody => false; - ///A comma-separated list of fields for `fielddata` and `suggest` index metric (supports wildcards) - public string[] CompletionFields - { - get => Q("completion_fields"); - set => Q("completion_fields", value); - } - - ///Whether to expand wildcard expression to concrete indices that are open, closed or both. - public ExpandWildcards? ExpandWildcards - { - get => Q("expand_wildcards"); - set => Q("expand_wildcards", value); - } - - ///A comma-separated list of fields for `fielddata` index metric (supports wildcards) - public string[] FielddataFields - { - get => Q("fielddata_fields"); - set => Q("fielddata_fields", value); - } - - ///A comma-separated list of fields for `fielddata` and `completion` index metric (supports wildcards) - public string[] Fields - { - get => Q("fields"); - set => Q("fields", value); - } - - ///If set to false stats will also collected from closed indices if explicitly specified or if expand_wildcards expands to closed indices - public bool? ForbidClosedIndices - { - get => Q("forbid_closed_indices"); - set => Q("forbid_closed_indices", value); - } - - ///A comma-separated list of search groups for `search` index metric - public string[] Groups - { - get => Q("groups"); - set => Q("groups", value); - } - - ///Whether to report the aggregated disk usage of each one of the Lucene index files (only applies if segment stats are requested) - public bool? IncludeSegmentFileSizes - { - get => Q("include_segment_file_sizes"); - set => Q("include_segment_file_sizes", value); - } - - ///If set to true segment stats will include stats for segments that are not currently loaded into memory - public bool? IncludeUnloadedSegments - { - get => Q("include_unloaded_segments"); - set => Q("include_unloaded_segments", value); - } - - ///Return stats aggregated at cluster, index or shard level - public Level? Level - { - get => Q("level"); - set => Q("level", value); - } - } - ///Request options for BulkAlias https://opensearch.org/docs/latest/opensearch/rest-api/alias/ public class BulkAliasRequestParameters : RequestParameters { diff --git a/src/OpenSearch.Net/OpenSearchLowLevelClient.Indices.cs b/src/OpenSearch.Net/OpenSearchLowLevelClient.Indices.cs index e815d6af01..c13c95a284 100644 --- a/src/OpenSearch.Net/OpenSearchLowLevelClient.Indices.cs +++ b/src/OpenSearch.Net/OpenSearchLowLevelClient.Indices.cs @@ -725,50 +725,6 @@ public TResponse Split(string index, string target, PostData body, Sp [MapsApi("indices.split", "index, target, body")] public Task SplitAsync(string index, string target, PostData body, SplitIndexRequestParameters requestParameters = null, CancellationToken ctx = default) where TResponse : class, IOpenSearchResponse, new() => DoRequestAsync(PUT, Url($"{index:index}/_split/{target:target}"), ctx, body, RequestParams(requestParameters)); - ///GET on /_stats https://opensearch.org/docs/latest/opensearch/stats-api/ - ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse StatsForAll(IndicesStatsRequestParameters requestParameters = null) - where TResponse : class, IOpenSearchResponse, new() => DoRequest(GET, "_stats", null, RequestParams(requestParameters)); - ///GET on /_stats https://opensearch.org/docs/latest/opensearch/stats-api/ - ///Request specific configuration such as querystring parameters & request specific connection settings. - [MapsApi("indices.stats", "")] - public Task StatsForAllAsync(IndicesStatsRequestParameters requestParameters = null, CancellationToken ctx = default) - where TResponse : class, IOpenSearchResponse, new() => DoRequestAsync(GET, "_stats", ctx, null, RequestParams(requestParameters)); - ///GET on /_stats/{metric} https://opensearch.org/docs/latest/opensearch/stats-api/ - ///Limit the information returned the specific metrics. - ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse StatsForAll(string metric, IndicesStatsRequestParameters requestParameters = null) - where TResponse : class, IOpenSearchResponse, new() => DoRequest(GET, Url($"_stats/{metric:metric}"), null, RequestParams(requestParameters)); - ///GET on /_stats/{metric} https://opensearch.org/docs/latest/opensearch/stats-api/ - ///Limit the information returned the specific metrics. - ///Request specific configuration such as querystring parameters & request specific connection settings. - [MapsApi("indices.stats", "metric")] - public Task StatsForAllAsync(string metric, IndicesStatsRequestParameters requestParameters = null, CancellationToken ctx = default) - where TResponse : class, IOpenSearchResponse, new() => DoRequestAsync(GET, Url($"_stats/{metric:metric}"), ctx, null, RequestParams(requestParameters)); - ///GET on /{index}/_stats https://opensearch.org/docs/latest/opensearch/stats-api/ - ///A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices - ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse Stats(string index, IndicesStatsRequestParameters requestParameters = null) - where TResponse : class, IOpenSearchResponse, new() => DoRequest(GET, Url($"{index:index}/_stats"), null, RequestParams(requestParameters)); - ///GET on /{index}/_stats https://opensearch.org/docs/latest/opensearch/stats-api/ - ///A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices - ///Request specific configuration such as querystring parameters & request specific connection settings. - [MapsApi("indices.stats", "index")] - public Task StatsAsync(string index, IndicesStatsRequestParameters requestParameters = null, CancellationToken ctx = default) - where TResponse : class, IOpenSearchResponse, new() => DoRequestAsync(GET, Url($"{index:index}/_stats"), ctx, null, RequestParams(requestParameters)); - ///GET on /{index}/_stats/{metric} https://opensearch.org/docs/latest/opensearch/stats-api/ - ///A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices - ///Limit the information returned the specific metrics. - ///Request specific configuration such as querystring parameters & request specific connection settings. - public TResponse Stats(string index, string metric, IndicesStatsRequestParameters requestParameters = null) - where TResponse : class, IOpenSearchResponse, new() => DoRequest(GET, Url($"{index:index}/_stats/{metric:metric}"), null, RequestParams(requestParameters)); - ///GET on /{index}/_stats/{metric} https://opensearch.org/docs/latest/opensearch/stats-api/ - ///A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices - ///Limit the information returned the specific metrics. - ///Request specific configuration such as querystring parameters & request specific connection settings. - [MapsApi("indices.stats", "index, metric")] - public Task StatsAsync(string index, string metric, IndicesStatsRequestParameters requestParameters = null, CancellationToken ctx = default) - where TResponse : class, IOpenSearchResponse, new() => DoRequestAsync(GET, Url($"{index:index}/_stats/{metric:metric}"), ctx, null, RequestParams(requestParameters)); ///POST on /_aliases https://opensearch.org/docs/latest/opensearch/rest-api/alias/ ///The definition of `actions` to perform ///Request specific configuration such as querystring parameters & request specific connection settings. diff --git a/src/OpenSearch.Net/_Generated/Api/RequestParameters/RequestParameters.Indices.cs b/src/OpenSearch.Net/_Generated/Api/RequestParameters/RequestParameters.Indices.cs index e3a2850b14..cf2e13ba8a 100644 --- a/src/OpenSearch.Net/_Generated/Api/RequestParameters/RequestParameters.Indices.cs +++ b/src/OpenSearch.Net/_Generated/Api/RequestParameters/RequestParameters.Indices.cs @@ -216,4 +216,78 @@ public TimeSpan MasterTimeout set => Q("master_timeout", value); } } + + /// Request options for Stats https://opensearch.org/docs/latest + public partial class IndicesStatsRequestParameters + : RequestParameters + { + public override HttpMethod DefaultHttpMethod => HttpMethod.GET; + public override bool SupportsBody => false; + + /// Comma-separated list or wildcard expressions of fields to include in fielddata and suggest statistics. + public string[] CompletionFields + { + get => Q("completion_fields"); + set => Q("completion_fields", value); + } + + /// + /// Type of index that wildcard patterns can match. If the request can target data streams, this argument determines whether wildcard + /// expressions match hidden data streams. Supports comma-separated values, such as `open,hidden`. + /// + public ExpandWildcards? ExpandWildcards + { + get => Q("expand_wildcards"); + set => Q("expand_wildcards", value); + } + + /// Comma-separated list or wildcard expressions of fields to include in fielddata statistics. + public string[] FielddataFields + { + get => Q("fielddata_fields"); + set => Q("fielddata_fields", value); + } + + /// Comma-separated list or wildcard expressions of fields to include in the statistics. + public string[] Fields + { + get => Q("fields"); + set => Q("fields", value); + } + + /// If true, statistics are not collected from closed indices. + public bool? ForbidClosedIndices + { + get => Q("forbid_closed_indices"); + set => Q("forbid_closed_indices", value); + } + + /// Comma-separated list of search groups to include in the search statistics. + public string[] Groups + { + get => Q("groups"); + set => Q("groups", value); + } + + /// If true, the call reports the aggregated disk usage of each one of the Lucene index files (only applies if segment stats are requested). + public bool? IncludeSegmentFileSizes + { + get => Q("include_segment_file_sizes"); + set => Q("include_segment_file_sizes", value); + } + + /// If true, the response includes information from segments that are not loaded into memory. + public bool? IncludeUnloadedSegments + { + get => Q("include_unloaded_segments"); + set => Q("include_unloaded_segments", value); + } + + /// Indicates whether statistics are aggregated at the cluster, index, or shard level. + public Level? Level + { + get => Q("level"); + set => Q("level", value); + } + } } diff --git a/src/OpenSearch.Net/_Generated/OpenSearchLowLevelClient.Indices.cs b/src/OpenSearch.Net/_Generated/OpenSearchLowLevelClient.Indices.cs index a9a60148f7..1811e068c4 100644 --- a/src/OpenSearch.Net/_Generated/OpenSearchLowLevelClient.Indices.cs +++ b/src/OpenSearch.Net/_Generated/OpenSearchLowLevelClient.Indices.cs @@ -228,5 +228,126 @@ public Task PutComposableTemplateForAllAsync( body, RequestParams(requestParameters) ); + + /// GET on /_stats https://opensearch.org/docs/latest + /// Request specific configuration such as querystring parameters & request specific connection settings. + public TResponse StatsForAll( + IndicesStatsRequestParameters requestParameters = null + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequest(GET, "_stats", null, RequestParams(requestParameters)); + + /// GET on /_stats https://opensearch.org/docs/latest + /// Request specific configuration such as querystring parameters & request specific connection settings. + [MapsApi("indices.stats", "")] + public Task StatsForAllAsync( + IndicesStatsRequestParameters requestParameters = null, + CancellationToken ctx = default + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequestAsync(GET, "_stats", ctx, null, RequestParams(requestParameters)); + + /// GET on /{index}/_stats https://opensearch.org/docs/latest + /// A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices. + /// Request specific configuration such as querystring parameters & request specific connection settings. + public TResponse Stats( + string index, + IndicesStatsRequestParameters requestParameters = null + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequest( + GET, + Url($"{index:index}/_stats"), + null, + RequestParams(requestParameters) + ); + + /// GET on /{index}/_stats https://opensearch.org/docs/latest + /// A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices. + /// Request specific configuration such as querystring parameters & request specific connection settings. + [MapsApi("indices.stats", "index")] + public Task StatsAsync( + string index, + IndicesStatsRequestParameters requestParameters = null, + CancellationToken ctx = default + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequestAsync( + GET, + Url($"{index:index}/_stats"), + ctx, + null, + RequestParams(requestParameters) + ); + + /// GET on /{index}/_stats/{metric} https://opensearch.org/docs/latest + /// A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices. + /// Limit the information returned the specific metrics. + /// Request specific configuration such as querystring parameters & request specific connection settings. + public TResponse Stats( + string index, + string metric, + IndicesStatsRequestParameters requestParameters = null + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequest( + GET, + Url($"{index:index}/_stats/{metric:metric}"), + null, + RequestParams(requestParameters) + ); + + /// GET on /{index}/_stats/{metric} https://opensearch.org/docs/latest + /// A comma-separated list of index names; use the special string `_all` or Indices.All to perform the operation on all indices. + /// Limit the information returned the specific metrics. + /// Request specific configuration such as querystring parameters & request specific connection settings. + [MapsApi("indices.stats", "index, metric")] + public Task StatsAsync( + string index, + string metric, + IndicesStatsRequestParameters requestParameters = null, + CancellationToken ctx = default + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequestAsync( + GET, + Url($"{index:index}/_stats/{metric:metric}"), + ctx, + null, + RequestParams(requestParameters) + ); + + /// GET on /_stats/{metric} https://opensearch.org/docs/latest + /// Limit the information returned the specific metrics. + /// Request specific configuration such as querystring parameters & request specific connection settings. + public TResponse StatsForAll( + string metric, + IndicesStatsRequestParameters requestParameters = null + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequest( + GET, + Url($"_stats/{metric:metric}"), + null, + RequestParams(requestParameters) + ); + + /// GET on /_stats/{metric} https://opensearch.org/docs/latest + /// Limit the information returned the specific metrics. + /// Request specific configuration such as querystring parameters & request specific connection settings. + [MapsApi("indices.stats", "metric")] + public Task StatsForAllAsync( + string metric, + IndicesStatsRequestParameters requestParameters = null, + CancellationToken ctx = default + ) + where TResponse : class, IOpenSearchResponse, new() => + DoRequestAsync( + GET, + Url($"_stats/{metric:metric}"), + ctx, + null, + RequestParams(requestParameters) + ); } } diff --git a/tests/Tests/Indices/Stats/IndicesStatsApiTests.cs b/tests/Tests/Indices/Stats/IndicesStatsApiTests.cs new file mode 100644 index 0000000000..e0984d8608 --- /dev/null +++ b/tests/Tests/Indices/Stats/IndicesStatsApiTests.cs @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System; +using FluentAssertions; +using OpenSearch.Client; +using OpenSearch.Net; +using Tests.Core.Extensions; +using Tests.Core.ManagedOpenSearch.Clusters; +using Tests.Domain; +using Tests.Framework.EndpointTests; +using Tests.Framework.EndpointTests.TestState; + +namespace Tests.Indices.Stats; + +public class IndicesStatsApiTests + : ApiIntegrationTestBase +{ + private static readonly IndexName ProjectIndex = Infer.Index(); + + public IndicesStatsApiTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage) { } + + protected override bool ExpectIsValid => true; + protected override int ExpectStatusCode => 200; + protected override HttpMethod HttpMethod => HttpMethod.GET; + + protected override IndicesStatsRequest Initializer => new (ProjectIndex, IndicesStatsMetric.Docs | IndicesStatsMetric.Segments); + + protected override Func Fluent => + d => d.Metric(IndicesStatsMetric.Docs | IndicesStatsMetric.Segments); + + protected override string UrlPath => "/project/_stats/docs%2Csegments"; + + protected override LazyResponses ClientUsage() => Calls( + (client, f) => client.Indices.Stats(typeof(Project), f), + (client, f) => client.Indices.StatsAsync(typeof(Project), f), + (client, r) => client.Indices.Stats(r), + (client, r) => client.Indices.StatsAsync(r) + ); + + protected override void ExpectResponse(IndicesStatsResponse response) + { + response.ShouldBeValid(); + + response.Indices.Should().NotBeNull(); + response.Indices.Count.Should().BeGreaterThan(0); + + var projectIndex = response.Indices[ProjectIndex]; + projectIndex.Should().NotBeNull(); + + var primaries = projectIndex.Primaries; + primaries.Should().NotBeNull(); + + var documents = primaries.Documents; + documents.Should().NotBeNull(); + documents.Count.Should().BeGreaterThan(0); + + var segments = primaries.Segments; + segments.Should().NotBeNull(); + segments.MemoryInBytes.Should().BeGreaterThan(0); + } +} diff --git a/tests/Tests/Indices/Stats/IndicesStatsUrlsTests.cs b/tests/Tests/Indices/Stats/IndicesStatsUrlsTests.cs new file mode 100644 index 0000000000..473ea0700b --- /dev/null +++ b/tests/Tests/Indices/Stats/IndicesStatsUrlsTests.cs @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +using System.Threading.Tasks; +using OpenSearch.OpenSearch.Xunit.XunitPlumbing; +using OpenSearch.Client; +using OpenSearch.Net; +using Tests.Framework.EndpointTests; +using static Tests.Framework.EndpointTests.UrlTester; + +namespace Tests.Indices.Stats; + +public class IndexStatsUrlsTests +{ + [U] public async Task Urls() + { + // "_stats", "{index}/_stats", "{index}/_stats/{metric}", "_stats/{metric}" + const string index = "test_index_1"; + const IndicesStatsMetric metrics = IndicesStatsMetric.Docs | IndicesStatsMetric.Segments; + + await GET("/_stats") + .Fluent(c => c.Indices.Stats()) + .Request(c => c.Indices.Stats(new IndicesStatsRequest())) + .FluentAsync(c => c.Indices.StatsAsync()) + .RequestAsync(c => c.Indices.StatsAsync(new IndicesStatsRequest())); + + await GET("/_stats/docs%2Csegments") + .Fluent(c => c.Indices.Stats(null, d => d.Metric(metrics))) + .Request(c => c.Indices.Stats(new IndicesStatsRequest(metrics))) + .FluentAsync(c => c.Indices.StatsAsync(null, d => d.Metric(metrics))) + .RequestAsync(c => c.Indices.StatsAsync(new IndicesStatsRequest(metrics))); + + await GET($"/{index}/_stats") + .Fluent(c => c.Indices.Stats(index, d => d)) + .Request(c => c.Indices.Stats(new IndicesStatsRequest(index))) + .FluentAsync(c => c.Indices.StatsAsync(index, d => d)) + .RequestAsync(c => c.Indices.StatsAsync(new IndicesStatsRequest(index))); + + await GET($"/{index}/_stats/docs%2Csegments") + .Fluent(c => c.Indices.Stats(index, d => d.Metric(metrics))) + .Request(c => c.Indices.Stats(new IndicesStatsRequest(index, metrics))) + .FluentAsync(c => c.Indices.StatsAsync(index, d => d.Metric(metrics))) + .RequestAsync(c => c.Indices.StatsAsync(new IndicesStatsRequest(index, metrics))); + } +}