Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export endpoints #168

Merged
merged 18 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
36ded2f
Increase cronjob max allowed execution time. Add logging to index swi…
sarkikos Nov 8, 2024
b4dd24d
Merge pull request #162 from CSCfi/indexer-improvements2
sarkikos Nov 8, 2024
b38ea11
Experimental publication endpoint using Elasticsearch Search After fe…
sarkikos Sep 6, 2024
72afe41
Add export controller. Fix error in search after parameter handling.
sarkikos Sep 13, 2024
f72b71d
Modify query parameter handling in publication and funding-decision e…
sarkikos Sep 13, 2024
7300953
Add search after functionality in funding decision endpoint. Improve …
sarkikos Sep 16, 2024
4123999
Add export endpoints for Organization and Infrastucture. Unify servic…
sarkikos Sep 20, 2024
295c787
New endpoint structure. Update endpoint descriptions.
sarkikos Oct 29, 2024
781c01a
Modify response headers. Unify controller parameter documentation.
sarkikos Oct 30, 2024
0d15713
Do not use x-total response header with export endpoints, it would fa…
sarkikos Oct 30, 2024
fedb19c
In export endpoints change default page size to 50 and maximum page s…
sarkikos Oct 30, 2024
298e221
Disable Swagger UI syntax highlight to improve performance. Upgrade t…
sarkikos Nov 12, 2024
c8b5e48
Merge pull request #165 from CSCfi/CSCTTV-3986-3987-3988-3994-3995-39…
sarkikos Nov 15, 2024
ef45416
Merge branch 'qa' into devel
sarkikos Nov 15, 2024
e91f110
Merge pull request #163 from CSCfi/devel
sarkikos Nov 15, 2024
f7e1e70
Hide infrastructure and organization endpoints
sarkikos Nov 15, 2024
c2abead
Merge pull request #166 from CSCfi/hide-infrastucture-and-organizatio…
sarkikos Nov 15, 2024
c61fb85
Merge pull request #167 from CSCfi/devel
sarkikos Nov 15, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ objects:
failedJobsHistoryLimit: 2
jobTemplate:
spec:
activeDeadlineSeconds: 2400 # Can run for 40 minutes
activeDeadlineSeconds: 5400 # Can run for 90 minutes
template:
spec:
restartPolicy: Never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ objects:
failedJobsHistoryLimit: 2
jobTemplate:
spec:
activeDeadlineSeconds: 2400 # Can run for 40 minutes
activeDeadlineSeconds: 5400 # Can run for 90 minutes
template:
spec:
restartPolicy: Never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ objects:
failedJobsHistoryLimit: 2
jobTemplate:
spec:
activeDeadlineSeconds: 2400 # Can run for 40 minutes
activeDeadlineSeconds: 5400 # Can run for 90 minutes
template:
spec:
restartPolicy: Never
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
/// Query parameters for searching funding calls.
/// </summary>
/// <see cref="FundingCall"/>
public class GetFundingCallQueryParameters : PaginationQueryParameters
public class GetFundingCallQueryParameters
{
/// <summary>
/// One of the fields nameFi, nameSV, nameEn contains the full text.
/// </summary>
/// <see cref="FundingCall.NameFi"/>

Check warning on line 14 in aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has cref attribute 'NameFi' that could not be resolved
/// <see cref="FundingCall.NameSv"/>

Check warning on line 15 in aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has cref attribute 'NameSv' that could not be resolved
/// <see cref="FundingCall.NameEn"/>

Check warning on line 16 in aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has cref attribute 'NameEn' that could not be resolved
public string? Name { get; set; }

/// <summary>
/// One of the field foundation subfields nameFi, nameSV, nameEn contains the full text.
/// </summary>
/// <see cref="FundingCall.Foundations"/>

Check warning on line 22 in aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has cref attribute 'Foundations' that could not be resolved
/// <see cref="Foundation.NameFi"/>
/// <see cref="Foundation.NameSv"/>
/// <see cref="Foundation.NameEn"/>
Expand All @@ -28,7 +28,7 @@
/// <summary>
/// The field foundation.foundationBusinessId is exactly equal to the text.
/// </summary>
/// <see cref="FundingCall.Foundations"/>

Check warning on line 31 in aspnetcore/src/ApiModels/Query/GetFundingCallQueryParameters.cs

View workflow job for this annotation

GitHub Actions / build

XML comment has cref attribute 'Foundations' that could not be resolved
/// <see cref="Foundation.BusinessId"/>
public string? FoundationBusinessId { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ResearchFi.Query;
/// Query parameters for searching funding decisions.
/// </summary>
/// <see cref="FundingDecision"/>
public class GetFundingDecisionQueryParameters : PaginationQueryParameters
public class GetFundingDecisionQueryParameters
{
/// <summary>
/// One of the fields nameFi, nameSV, nameEn contains the full text.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// <summary>
/// Hakuparametrit infrastruktuurien hakemiseen.
/// </summary>
public class GetInfrastructuresQueryParameters : PaginationQueryParameters
public class GetInfrastructuresQueryParameters
{
/// <summary>
/// Infrastruktuurin nimi.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ResearchFi.Query;
/// Query parameters for searching publications.
/// </summary>
/// <see cref="Publication"/>
public class GetPublicationsQueryParameters : PaginationQueryParameters
public class GetPublicationsQueryParameters
{
/// <summary>
/// The field name contains text.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public int PageNumber
}

/// <summary>
/// Number of results on page. Optional. Default value 20. Maximum permissible value 100. Maximum possible result set of 10,000 results.
/// Number of results on page. Optional. Default value 20. Maximum permissible value 100. Maximum possible result set of 10000 results.
/// </summary>
public int PageSize
{
Expand Down
30 changes: 30 additions & 0 deletions aspnetcore/src/ApiModels/Query/SearchAfterQueryParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace ResearchFi.Query;

/// <summary>
/// Vientiin liittyvät tiedot.
/// </summary>
public class SearchAfterQueryParameters
{
private const int DefaultPageSize = 50;
private const int MaximumPageSize = 1000;
private int _pageSize = DefaultPageSize;
private long? _nextPageToken = null;

/// <summary>
/// Number of results on page. Optional. Default value 50. Maximum permissible value 1000.
/// </summary>
public int PageSize
{
get => _pageSize;
set => _pageSize = value < 1 ? DefaultPageSize : (value > MaximumPageSize ? MaximumPageSize : value);
}

/// <summary>
/// Value from previous query response header "x-next-page-token". Leave empty in the first query.
/// </summary>
public long? NextPageToken
{
get => _nextPageToken;
set => _nextPageToken = value;
}
}
6 changes: 4 additions & 2 deletions aspnetcore/src/ElasticService/ElasticSearchIndexService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public async Task IndexAsync(string indexName, List<object> entities, Type model
await IndexEntities(indexToCreate, entities, modelType);

// Switch indexes
await SwitchIndexes(indexName, indexToCreate, indexToDelete);
await SwitchIndexes(indexName, indexToCreate, indexToDelete, modelType.Name);

_logger.LogDebug("{EntityType:l}: Indexing to {IndexName:l} complete", modelType.Name, indexName);
}
Expand All @@ -43,8 +43,9 @@ public async Task IndexChunkAsync(string indexToCreate, List<object> entities, T
await IndexEntities(indexToCreate, entities, modelType);
}

public async Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete)
public async Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete, string modelTypeName)
{
_logger.LogInformation($"{modelTypeName}: Switch indexes start: indexName={indexName}, indexToCreate={indexToCreate}, indexToDelete={indexToDelete}");
// Wait for new index to be operational.
await _elasticClient.Cluster
.HealthAsync(selector: s => s
Expand All @@ -61,6 +62,7 @@ await _elasticClient.Indices.BulkAliasAsync(r => r

// Delete the old index if it exists.
await _elasticClient.Indices.DeleteAsync(indexToDelete, d => d.RequestConfiguration(x => x.AllowedStatusCodes(404)));
_logger.LogInformation($"{modelTypeName}: Switch indexes complete");
}

public async Task<(string indexToCreate, string indexToDelete)> GetIndexNames(string indexName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ namespace CSC.PublicApi.ElasticService.ElasticSearchQueryGenerators;
public interface IQueryGenerator<TIn, TOut> where TOut : class
{
Func<SearchDescriptor<TOut>, ISearchRequest> GenerateQuery(TIn searchParameters, int pageNumber, int pageSize);
Func<SearchDescriptor<TOut>, ISearchRequest> GenerateQuerySearchAfter(TIn searchParameters, int pageSize, long? searchAfter);
Func<SearchDescriptor<TOut>, ISearchRequest> GenerateSingleQuery(string id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ public Func<SearchDescriptor<TOut>, ISearchRequest> GenerateQuery(TIn searchPara
.Query(GenerateQueryForSearch(searchParameters));
}

public Func<SearchDescriptor<TOut>, ISearchRequest> GenerateQuerySearchAfter(TIn searchParameters, int pageSize, long? searchAfter)
{
var indexName = _configuration.GetIndexNameForType(typeof(TOut));

if (searchAfter == null) {
return descriptor => descriptor
.Index(indexName)
.Take(pageSize)
.Sort(sort => sort.Ascending(SortSpecialField.DocumentIndexOrder))
.Query(GenerateQueryForSearch(searchParameters));
}
else {
return descriptor => descriptor
.Index(indexName)
.Take(pageSize)
.Sort(sort => sort.Ascending(SortSpecialField.DocumentIndexOrder))
.Query(GenerateQueryForSearch(searchParameters))
.SearchAfter(searchAfter);
}
}

public Func<SearchDescriptor<TOut>, ISearchRequest> GenerateSingleQuery(string id)
{
var indexName = _configuration.GetIndexNameForType(typeof(TOut));
Expand Down
21 changes: 21 additions & 0 deletions aspnetcore/src/ElasticService/ElasticSearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ public ElasticSearchService(
return (searchResult.Documents, new SearchResult(pageNumber, pageSize, searchResult.HitsMetadata?.Total.Value));
}

public async Task<(IEnumerable<TOut>, SearchAfterResult)> SearchAfter(TIn parameters, int pageSize, long? searchAfter)
{
var query = _queryGenerator.GenerateQuerySearchAfter(parameters, pageSize, searchAfter);

var searchResult = await _elasticClient.SearchAsync(query);

if (Debugger.IsAttached)
{
// Enables seeing the query sent to elastic and the response in the log when debugging.
Console.WriteLine(searchResult.DebugInformation);
}

long? searchAfterValue = null;

if (searchResult.Hits.Count > 0) {
searchAfterValue = (long)searchResult.Hits.Last().Sorts.First();
}

return (searchResult.Documents, new SearchAfterResult(searchAfterValue, pageSize));
}

public async Task<TOut?> GetSingle(string id)
{
var query = _queryGenerator.GenerateSingleQuery(id);
Expand Down
3 changes: 2 additions & 1 deletion aspnetcore/src/ElasticService/IElasticSearchIndexService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public interface IElasticSearchIndexService
/// <param name="indexName"></param>
/// <param name="indexToCreate"></param>
/// <param name="indexToDelete"></param>
/// <param name="modelTypeName"></param>
/// <returns></returns>
Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete);
Task SwitchIndexes(string indexName, string indexToCreate, string indexToDelete, string modelTypeName);
}
2 changes: 1 addition & 1 deletion aspnetcore/src/ElasticService/ISearchService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
public interface ISearchService<TIn, TOut> where TOut : class
{
Task<(IEnumerable<TOut>, SearchResult)> Search(TIn searchParameters, int pageNumber, int pageSize);

Task<(IEnumerable<TOut>, SearchAfterResult)> SearchAfter(TIn searchParameters, int pageSize, long? searchAfter);
Task<TOut?> GetSingle(string id);
}
12 changes: 12 additions & 0 deletions aspnetcore/src/ElasticService/SearchAfterResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace CSC.PublicApi.ElasticService;

public class SearchAfterResult
{
public long? SearchAfter { get; }
public int PageSize { get; }
public SearchAfterResult(long? searchAfter, int pageSize)
{
SearchAfter = searchAfter;
PageSize = pageSize;
}
}
2 changes: 1 addition & 1 deletion aspnetcore/src/Indexer/Indexer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ private async Task IndexEntities(string indexName, IIndexRepository repository,
} while (numOfResults >= takeAmount - 1);

// Activate new index and delete old
await _indexService.SwitchIndexes(indexName, indexToCreate, indexToDelete);
await _indexService.SwitchIndexes(indexName, indexToCreate, indexToDelete, type.Name);
_logger.LogInformation("{EntityType:l}: Recreated index {IndexName:l}, {ElasticsearchDocumentCount} documents", type.Name, indexName, processedCount);
}
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public static void UseSwaggerAndSwaggerUI(this WebApplication app)
foreach (var description in app.Services.GetRequiredService<IApiVersionDescriptionProvider>().ApiVersionDescriptions)
{
options.SwaggerEndpoint($"{description.GroupName}/swagger.json", description.GroupName.ToUpperInvariant());
options.ConfigObject.AdditionalItems.Add("syntaxHighlight", false); // disable to improve performance with large responses
}
});
}
Expand Down
6 changes: 3 additions & 3 deletions aspnetcore/src/Interface/Controllers/FundingCallController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public FundingCallController(
/// <summary>
/// Endpoint for filtering funding calls using the specified query parameters.
/// </summary>
/// <param name="queryParameters">The query parameters for filtering the results.</param>
/// <param name="fundingCallQueryParameters">The query parameters for filtering the results.</param>
/// <returns>Paged search result as a collection of <see cref="FundingCall"/> objects.</returns>
/// <response code="200">Ok.</response>
/// <response code="401">Unauthorized.</response>
Expand All @@ -43,9 +43,9 @@ public FundingCallController(
[ProducesResponseType(typeof(IEnumerable<FundingCall>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)]
public async Task<IEnumerable<FundingCall>> Get([FromQuery] GetFundingCallQueryParameters queryParameters)
public async Task<IEnumerable<FundingCall>> Get([FromQuery] GetFundingCallQueryParameters fundingCallQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters)
{
var (fundingCalls, searchResult) = await _service.GetFundingCalls(queryParameters);
var (fundingCalls, searchResult) = await _service.GetFundingCalls(fundingCallQueryParameters, paginationQueryParameters);

ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using CSC.PublicApi.Interface.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ResearchFi.FundingCall;
using ResearchFi.Query;
using Serilog;

namespace CSC.PublicApi.Interface.Controllers;

[ApiController]
[ApiVersion(ApiConstants.ApiVersion1)]
[Route("v{version:apiVersion}/funding-calls-export")]
public class FundingCallExportController : ControllerBase
{
private readonly ILogger<FundingCallExportController> _logger;
private readonly IFundingCallService _service;
private readonly IDiagnosticContext _diagnosticContext;

public FundingCallExportController(
ILogger<FundingCallExportController> logger,
IFundingCallService service,
IDiagnosticContext diagnosticContext)
{
_logger = logger;
_service = service;
_diagnosticContext = diagnosticContext;
_diagnosticContext.Set(ApiConstants.LogResourceType_PropertyName, ApiConstants.LogResourceType_FundingCall);
}

/// <summary>
/// Endpoint for bypassing the limit of 10000 records for funding calls.
/// </summary>
/// <param name="fundingCallQueryParameters">The query parameters for filtering the results.</param>
/// <returns>Paged search result as a collection of <see cref="FundingCall"/> objects.</returns>
/// <response code="200">Ok.</response>
/// <response code="401">Unauthorized.</response>
/// <response code="403">Forbidden.</response>
[HttpGet(Name = "GetFundingCallExport")]
[MapToApiVersion(ApiConstants.ApiVersion1)]
[Authorize(Policy = ApiPolicies.FundingCall.Read)]
[Produces(ApiConstants.ContentTypeJson)]
[Consumes(ApiConstants.ContentTypeJson)]
[ProducesResponseType(typeof(IEnumerable<FundingCall>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)]
public async Task<IEnumerable<FundingCall>> Get([FromQuery] GetFundingCallQueryParameters fundingCallQueryParameters, [FromQuery] SearchAfterQueryParameters searchAfterQueryParameters)
{
var (fundingCalls, searchAfterResult) = await _service.GetFundingCallsSearchAfter(fundingCallQueryParameters, searchAfterQueryParameters);

ResponseHelper.AddPaginationResponseHeadersSearchAfter(HttpContext, searchAfterResult);

return fundingCalls;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public FundingDecisionController(
/// <summary>
/// Endpoint for filtering funding decisions using the specified query parameters.
/// </summary>
/// <param name="fundingDecisionQueryParameters">The query parameters for filtering the results.</param>
/// <returns>Paged search result as a collection of <see cref="FundingDecision"/> objects.</returns>
/// <response code="200">Ok.</response>
/// <response code="401">Unauthorized.</response>
Expand All @@ -44,9 +45,9 @@ public FundingDecisionController(
[ProducesResponseType(typeof(IEnumerable<FundingDecision>), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
[ProducesResponseType(typeof(void),StatusCodes.Status403Forbidden)]
public async Task<IEnumerable<FundingDecision>> Get([FromQuery] GetFundingDecisionQueryParameters queryParameters)
public async Task<IEnumerable<FundingDecision>> Get([FromQuery] GetFundingDecisionQueryParameters fundingDecisionQueryParameters, [FromQuery] PaginationQueryParameters paginationQueryParameters)
{
var (fundingDecisions, searchResult) = await _service.GetFundingDecisions(queryParameters);
var (fundingDecisions, searchResult) = await _service.GetFundingDecisions(fundingDecisionQueryParameters, paginationQueryParameters);

ResponseHelper.AddPaginationResponseHeaders(HttpContext, searchResult);

Expand Down
Loading
Loading