Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • coscine/backend/apis/search
1 result
Show changes
Commits on Source (4)
......@@ -4,11 +4,14 @@ using Coscine.ApiCommons;
using Coscine.Configuration;
using Coscine.SemanticSearch.Clients;
using Coscine.SemanticSearch.Core;
using Coscine.SemanticSearch.Util.QueryObjects;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
......@@ -49,38 +52,77 @@ namespace Coscine.Api.Search.Controllers
/// <param name="searchParameters"></param>
/// <returns>Search results</returns>
[HttpGet("[controller]/")]
public async Task<ActionResult<IEnumerable<ItemSearchResult>>> SearchAsync([FromQuery] SearchParameters searchParameters = null)
public async Task<ActionResult<IEnumerable<ItemSearchResult>>> SearchAsync([FromQuery] SearchParameters? searchParameters = null)
{
if (searchParameters is null)
{
searchParameters = new SearchParameters();
}
if (searchParameters.SearchQuery is null)
{
searchParameters.SearchQuery = "";
}
var currentUser = _authenticator.GetUser();
if (searchParameters.IncludedLanguages is null || !searchParameters.IncludedLanguages.Any())
if (searchParameters.IncludedLanguages?.Any() != true)
{
searchParameters.IncludedLanguages = _defaultLanguages;
}
try
{
var items = await Searchers.SearchForItemsAsync(currentUser.Id, searchParameters.SearchQuery, searchParameters.UseAdvancedSyntax, includePrivateRecords: searchParameters.IncludeUsers, _connector, _searchClient, searchParameters.IncludedLanguages.ToList());
var categoryCounts = new List<Category>();
foreach (CategoryFilter category in Enum.GetValues(typeof(CategoryFilter)))
{
var count = await Searchers.CountForItemsAsync(
currentUser.Id,
searchParameters.SearchQuery,
searchParameters.UseAdvancedSyntax,
includePrivateRecords: searchParameters.IncludeUsers,
_connector,
_searchClient,
searchParameters.IncludedLanguages.ToList(),
category);
var res = PagedList<ItemSearchResult>.ToPagedList(items, searchParameters.PageNumber, searchParameters.PageSize);
categoryCounts.Add(new Category(category, category.ToString(), count));
}
// The total count for the pagination depends on the selected category
var totalCount = categoryCounts
.First(x => x.Id == searchParameters.CategoryFilter)
.Count;
var items = await Searchers.SearchForItemsAsync(
currentUser.Id,
searchParameters.SearchQuery,
searchParameters.UseAdvancedSyntax,
includePrivateRecords: searchParameters.IncludeUsers,
_connector,
_searchClient,
searchParameters.IncludedLanguages.ToList(),
searchParameters.PageSize,
searchParameters.PageNumber - 1,
searchParameters.OrderBy,
searchParameters.CategoryFilter);
var response = new PagedList<ItemSearchResult>(items, totalCount, searchParameters.PageNumber, searchParameters.PageSize);
var metadata = new
{
res.TotalCount,
res.PageSize,
res.CurrentPage,
res.TotalPages,
res.HasNext,
res.HasPrevious
response.TotalCount,
response.PageSize,
response.CurrentPage,
response.TotalPages,
response.HasNext,
response.HasPrevious,
Categories = categoryCounts
};
Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(metadata));
return res;
return response;
}
catch (Exception e)
{
......@@ -88,4 +130,6 @@ namespace Coscine.Api.Search.Controllers
}
}
}
internal record Category(CategoryFilter Id, string Name, int Count);
}
\ No newline at end of file
using Coscine.Api.Search.Models;
using Coscine.SemanticSearch;
using Coscine.SemanticSearch.Core;
using Coscine.SemanticSearch.Util.QueryObjects;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
......@@ -12,23 +13,48 @@ namespace Coscine.Api.Search.Helpers;
/// </summary>
public class Searchers
{
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="searchQuery"></param>
/// <param name="advancedSearch"></param>
/// <param name="includePrivateRecords"></param>
/// <param name="connector"></param>
/// <param name="searchClient"></param>
/// <param name="languages"></param>
/// <returns>Found files</returns>
public static async Task<IEnumerable<ItemSearchResult>> SearchForItemsAsync(Guid userId, string searchQuery, bool advancedSearch, bool includePrivateRecords, IRdfConnector connector, ISearchClient searchClient, List<string> languages)
public static async Task<IEnumerable<ItemSearchResult>> SearchForItemsAsync(Guid userId, string searchQuery, bool advancedSearch, bool includePrivateRecords, IRdfConnector connector, ISearchClient searchClient, List<string> languages, int pageSize, int page, OrderBy orderBy, CategoryFilter categoryFilter)
{
string userIdentifier = includePrivateRecords ? userId.ToString() : null;
var userIdentifier = includePrivateRecords ? userId.ToString() : null;
var mapper = new RdfSearchMapper(connector, searchClient, languages);
var results = await mapper.SearchAsync(searchQuery, userIdentifier, advancedSearch);
Sort? sort = null;
switch (orderBy)
{
case OrderBy.Date_Created_Asc:
sort = new Sort { DateCreated = new DateCreated { Order = "asc" } };
break;
case OrderBy.Date_Created_Desc:
sort = new Sort { DateCreated = new DateCreated { Order = "desc" } };
break;
case OrderBy.Score_Asc:
sort = new Sort { Score = new SortElement { Order = "asc" } };
break;
case OrderBy.Score_Desc:
sort = new Sort { Score = new SortElement { Order = "desc" } };
break;
case OrderBy.Title_Asc:
sort = new Sort { Title = new SortElement { Order = "asc" } };
break;
case OrderBy.Title_Desc:
sort = new Sort { Title = new SortElement { Order = "desc" } };
break;
}
var results = await mapper.SearchAsync(searchQuery, userIdentifier, advancedSearch, pageSize, pageSize * page, sort, categoryFilter);
return ItemSearchResult.ParseResultsToList(results);
}
}
public static async Task<int> CountForItemsAsync(Guid userId, string searchQuery, bool advancedSearch, bool includePrivateRecords, IRdfConnector connector, ISearchClient searchClient, List<string> languages, CategoryFilter categoryFilter = CategoryFilter.None)
{
var userIdentifier = includePrivateRecords ? userId.ToString() : null;
var mapper = new RdfSearchMapper(connector, searchClient, languages);
return await mapper.CountAsync(searchQuery, userIdentifier, advancedSearch, categoryFilter);
}
}
\ No newline at end of file
......@@ -52,7 +52,7 @@ public class ItemSearchResult
var searchResult = new ItemSearchResult(entry.Key, entry.Value);
if (entry.Value.ContainsKey("structureType"))
{
var type = (string) entry.Value["structureType"];
var type = entry.Value["structureType"]?.ToString();
if (type == "https://purl.org/coscine/terms/structure#Metadata")
{
searchResult.Type = ItemType.Metadata;
......@@ -70,5 +70,4 @@ public class ItemSearchResult
}
return output;
}
}
}
\ No newline at end of file
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.ComponentModel.DataAnnotations;
namespace Coscine.Api.Search.Models
{
public enum OrderBy
{
Date_Created_Asc,
Date_Created_Desc,
Score_Asc,
Score_Desc,
Title_Asc,
Title_Desc,
}
}
\ No newline at end of file
using System.Collections.Generic;
using Coscine.SemanticSearch.Util.QueryObjects;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Coscine.Api.Search.Models
{
......@@ -25,6 +29,20 @@ namespace Coscine.Api.Search.Models
/// <summary>
/// Set the used languages
/// </summary>
public IEnumerable<string> IncludedLanguages { get; set; }
public IEnumerable<string>? IncludedLanguages { get; set; }
/// <summary>
/// Set the category filter
/// </summary>
[EnumDataType(typeof(CategoryFilter))]
[JsonConverter(typeof(StringEnumConverter))]
public CategoryFilter CategoryFilter { get; set; } = CategoryFilter.None;
/// <summary>
/// Set the order for sorting
/// </summary>
[EnumDataType(typeof(OrderBy))]
[JsonConverter(typeof(StringEnumConverter))]
public OrderBy OrderBy { get; set; } = OrderBy.Score_Desc;
}
}
\ No newline at end of file
......@@ -5,21 +5,23 @@
<AssemblyName>Coscine.Api.Search</AssemblyName>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TargetFramework>net6.0</TargetFramework>
<Version>1.6.0</Version>
<Version>1.7.0</Version>
<Nullable>enable</Nullable>
<NoWarn>1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<Authors>RWTH Aachen University</Authors>
<Company>IT Center, RWTH Aachen University</Company>
<Copyright>2022 IT Center, RWTH Aachen University</Copyright>
<Copyright>2023 IT Center, RWTH Aachen University</Copyright>
<Description>Search is a part of the Coscine group.</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://git.rwth-aachen.de/coscine/backend/apis/Search</PackageProjectUrl>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Coscine.ApiCommons" Version="2.*-*" />
<PackageReference Include="Coscine.Database" Version="2.*-*" />
<PackageReference Include="Coscine.SemanticSearch" Version="1.*-*" />
<PackageReference Include="Coscine.ApiCommons" Version="*-*" />
<PackageReference Include="Coscine.Database" Version="*-*" />
<PackageReference Include="Coscine.SemanticSearch" Version="*-*" />
<PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.2.9" />
</ItemGroup>
</Project>
using Coscine.ApiCommons;
using Microsoft.Extensions.DependencyInjection;
namespace Coscine.Api.Search
{
/// <summary>
/// Standard Startup class.
/// </summary>
......@@ -14,7 +13,6 @@ namespace Coscine.Api.Search
/// </summary>
public Startup()
{
}
}
}
}
\ No newline at end of file