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)
......@@ -7,9 +7,7 @@ using Coscine.SemanticSearch.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Coscine.Api.Search.Controllers
......@@ -45,7 +43,7 @@ namespace Coscine.Api.Search.Controllers
/// <summary>
/// Search
/// Search Elasticsearch
/// </summary>
/// <param name="query">Elasticsearch query</param>
/// <param name="user">Specify user or only public metadata records could be found</param>
......@@ -63,18 +61,10 @@ namespace Coscine.Api.Search.Controllers
try
{
var files = await Searchers.SearchForFilesAsync(currentUser.Id, query, adv, includePrivateRecords: user, _connector, _searchClient, languages.ToList());
var projectsToAppend = files.Where(f => f.ProjectId is not null).Select(f => f.ProjectId).Distinct().ToList();
var resourcesToAppend = files.Where(f => f.ProjectId is not null).Select(f => f.ResourceId).Distinct().ToList();
// Advanced query looks like so: (vvm.txt) + (belongsToProject: "https://purl.org/coscine/projects/1a6cf186-12cb-4710-81c6-edb981f77761")
var formattedQueryMatch = Regex.Match(query, @"(?<=\().+?(?=\))");
var formattedQuery = formattedQueryMatch.Success ? formattedQueryMatch.Value : query;
var items = await Searchers.SearchForItemsAsync(currentUser.Id, query, adv, includePrivateRecords: user, _connector, _searchClient, languages.ToList());
var res = new SearchResult()
{
Projects = Searchers.SearchForProjects(currentUser.Id, formattedQuery, projectsToAppend: projectsToAppend),
Resources = Searchers.SearchForResources(currentUser.Id, formattedQuery, resourcesToAppend: resourcesToAppend),
Files = files,
Items = items,
};
return res;
}
......
using Coscine.Api.Search.Models;
using Coscine.Database.DataModel;
using Coscine.Database.Models;
using Coscine.Database.ReturnObjects;
using Coscine.Database.Util;
using Coscine.SemanticSearch;
using Coscine.SemanticSearch.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Coscine.Api.Search.Helpers;
......@@ -28,158 +23,12 @@ public class Searchers
/// <param name="searchClient"></param>
/// <param name="languages"></param>
/// <returns>Found files</returns>
public static async Task<IEnumerable<FileSearchResult>> SearchForFilesAsync(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)
{
string userIdentifier = includePrivateRecords ? userId.ToString() : null;
var mapper = new RdfSearchMapper(connector, searchClient, languages, GetPublicVisibilityId());
var mapper = new RdfSearchMapper(connector, searchClient, languages);
var results = await mapper.SearchAsync(searchQuery, userIdentifier, advancedSearch);
return FileSearchResult.ParseResultsToList(results);
return ItemSearchResult.ParseResultsToList(results);
}
/// <summary>
/// This method searches through projects
/// </summary>
/// <param name="userId">ID of the user</param>
/// <param name="searchQuery">Search query</param>
/// <param name="showSubProjects">Shows subprojects</param>
/// <param name="projectsToAppend">List of project IDs to include in the result</param>
/// <returns>Found projects</returns>
public static IEnumerable<ProjectObject> SearchForProjects(Guid userId, string searchQuery, bool showSubProjects = false, List<string> projectsToAppend = null)
{
if (string.IsNullOrEmpty(searchQuery) || searchQuery == "*")
{
searchQuery = "";
}
if (projectsToAppend is null)
{
projectsToAppend = new List<string>();
}
var projectModel = new ProjectModel();
return DatabaseConnection.ConnectToDatabase((db) =>
{
var allSubProjects = (from sp in db.SubProjects select sp.SubProjectId).ToList();
var allSubProjectsList = new List<Guid>();
allSubProjectsList.AddRange(allSubProjects);
return (from p in db.Projects
join pr in db.ProjectRoles on p.Id equals pr.ProjectId into joinedPr
from jpr in joinedPr.DefaultIfEmpty()
join v in db.Visibilities on p.VisibilityId equals v.Id into joinedV
from jv in joinedV.DefaultIfEmpty()
join pd in db.ProjectDisciplines on p.Id equals pd.ProjectId into joinedPd
from jpd in joinedPd.DefaultIfEmpty()
join d in db.Disciplines on jpd.DisciplineId equals d.Id into joinedD
from jd in joinedD.DefaultIfEmpty()
join pi in db.ProjectInstitutes on p.Id equals pi.ProjectId into joinedPi
from jpi in joinedPi.DefaultIfEmpty()
where p.Deleted == false &&
((!showSubProjects && !allSubProjectsList.Contains(p.Id)) ||
(showSubProjects && allSubProjectsList.Contains(p.Id))) &&
(jpr.UserId == userId || jv.DisplayName == "Public") &&
(searchQuery == "" ||
p.ProjectName.Contains(searchQuery) ||
p.Description.Contains(searchQuery) ||
p.Keywords.Contains(searchQuery) ||
p.DisplayName.Contains(searchQuery) ||
p.PrincipleInvestigators.Contains(searchQuery) ||
p.GrantId.Contains(searchQuery) ||
jv.DisplayName.Contains(searchQuery) ||
jd.Url.Contains(searchQuery) ||
jd.DisplayNameDe.Contains(searchQuery) ||
jd.DisplayNameEn.Contains(searchQuery)) ||
projectsToAppend.Contains(p.Id.ToString())
select projectModel.CreateReturnObjectFromDatabaseObject(p)).ToList().OrderBy(element => element.DisplayName).DistinctBy(p => p.Id).ToList();
});
}
/// <summary>
/// This method searches through resources
/// </summary>
/// <param name="userId">ID of the user</param>
/// <param name="searchQuery">Search Query</param>
/// <param name="resourcesToAppend">List of resource IDs to include in the result</param>
/// <returns>Found resources</returns>
public static IEnumerable<ResourceSearchResult> SearchForResources(Guid userId, string searchQuery, List<string> resourcesToAppend = null)
{
if (string.IsNullOrEmpty(searchQuery) || searchQuery == "*")
{
searchQuery = "";
}
if (resourcesToAppend is null)
{
resourcesToAppend = new List<string>();
}
var resourceModel = new ResourceModel();
var resourceObjects = DatabaseConnection.ConnectToDatabase((db) =>
{
var resourceObjects = (from r in db.Resources
join pres in db.ProjectResources on r.Id equals pres.ResourceId into joinedPres
from jpres in joinedPres.DefaultIfEmpty()
join p in db.Projects on jpres.ProjectId equals p.Id into joinedP
from jp in joinedP.DefaultIfEmpty()
join pr in db.ProjectRoles on jp.Id equals pr.ProjectId into joinedPr
from jpr in joinedPr.DefaultIfEmpty()
join v in db.Visibilities on r.VisibilityId equals v.Id into joinedV
from jv in joinedV.DefaultIfEmpty()
join rd in db.ResourceDisciplines on r.Id equals rd.ResourceId into joinedRd
from jrd in joinedRd.DefaultIfEmpty()
join d in db.Disciplines on jrd.DisciplineId equals d.Id into joinedD
from jd in joinedD.DefaultIfEmpty()
join l in db.Licenses on r.LicenseId equals l.Id into joinedL
from jl in joinedL.DefaultIfEmpty()
join rt in db.ResourceTypes on r.TypeId equals rt.Id into joinedRt
from jrt in joinedRt.DefaultIfEmpty()
where jp.Deleted == false &&
(jpr.UserId == userId || jv.DisplayName == "Public") &&
(searchQuery == "" ||
r.ResourceName.Contains(searchQuery) ||
r.DisplayName.Contains(searchQuery) ||
r.ResourceName.Contains(searchQuery) ||
r.Keywords.Contains(searchQuery) ||
r.UsageRights.Contains(searchQuery) ||
r.Description.Contains(searchQuery) ||
r.ApplicationProfile.Contains(searchQuery) ||
jrt.DisplayName.Contains(searchQuery) ||
jl.DisplayName.Contains(searchQuery) ||
jd.DisplayNameDe.Contains(searchQuery) ||
jd.DisplayNameEn.Contains(searchQuery)) ||
resourcesToAppend.Contains(r.Id.ToString())
select resourceModel.CreateReturnObjectFromDatabaseObject(r)).ToList().OrderBy(element => element.DisplayName).DistinctBy(r => r.Id).ToList();
// Remove fixed values
foreach (var resource in resourceObjects)
{
resource.FixedValues = null;
}
return resourceObjects;
});
var projectResourceModel = new ProjectResourceModel();
var parentProjects = projectResourceModel.GetAll();
static Guid? getParentId(ProjectResource projectObject = null)
{
if (projectObject is not null)
{
return projectObject.ProjectId;
}
return null;
}
var result = new List<ResourceSearchResult>(resourceObjects.Count);
result.AddRange(resourceObjects.Select(i => new ResourceSearchResult(i, getParentId(parentProjects.FirstOrDefault(p => p.ResourceId.Equals(i.Id))))));
return result;
}
private static Guid GetPublicVisibilityId()
{
var visibilityModel = new VisibilityModel();
return visibilityModel.GetWhere(v => v.DisplayName.ToLower().Contains("public")).Id; // Handle null.Id case?
}
}
......@@ -2,14 +2,13 @@
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Coscine.Api.Search.Models;
/// <summary>
/// File Search Result Object
/// Item Search Result Object
/// </summary>
public class FileSearchResult
public class ItemSearchResult
{
/// <summary>
/// Graph Name
......@@ -18,16 +17,10 @@ public class FileSearchResult
public Uri GraphName { get; set; }
/// <summary>
/// ID of Project containing the file
/// </summary>
[JsonProperty("projectId")]
public string ProjectId { get; set; }
/// <summary>
/// ID of Resource containing the file
/// Graph Name
/// </summary>
[JsonProperty("resourceId")]
public string ResourceId { get; set; }
[JsonProperty("type")]
public ItemType Type { get; set; } = ItemType.Metadata;
/// <summary>
/// Search result fields
......@@ -39,13 +32,10 @@ public class FileSearchResult
/// Constructor
/// </summary>
/// <param name="key">Search result entry key containing the resource id</param>
/// <param name="projectValue">URI containing the project id</param>
/// <param name="value">Search result</param>
public FileSearchResult(string key, string projectValue, JObject value)
public ItemSearchResult(string key, JObject value)
{
GraphName = new Uri(key);
ProjectId = GetGuid(projectValue);
ResourceId = GetGuid(key);
Source = value;
}
......@@ -54,21 +44,31 @@ public class FileSearchResult
/// </summary>
/// <param name="results"></param>
/// <returns></returns>
public static IEnumerable<FileSearchResult> ParseResultsToList(IDictionary<string, JObject> results)
public static IEnumerable<ItemSearchResult> ParseResultsToList(IDictionary<string, JObject> results)
{
var output = new List<FileSearchResult>();
var output = new List<ItemSearchResult>();
foreach (var entry in results)
{
var searchResult = new FileSearchResult(entry.Key, (string)entry.Value["belongsToProject"], entry.Value);
var searchResult = new ItemSearchResult(entry.Key, entry.Value);
if (entry.Value.ContainsKey("structureType"))
{
var type = (string) entry.Value["structureType"];
if (type == "https://purl.org/coscine/terms/structure#Metadata")
{
searchResult.Type = ItemType.Metadata;
}
else if (type == "https://purl.org/coscine/terms/structure#Project")
{
searchResult.Type = ItemType.Project;
}
else if (type == "https://purl.org/coscine/terms/structure#Resource")
{
searchResult.Type = ItemType.Resource;
}
}
output.Add(searchResult);
}
return output;
}
private static string GetGuid(string value)
{
var regex = new Regex(@"[({]?[a-fA-F0-9]{8}[-]?([a-fA-F0-9]{4}[-]?){3}[a-fA-F0-9]{12}[})]?", RegexOptions.IgnoreCase);
var match = regex.Match(value);
return match.Success ? match.Value : null;
}
}
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Coscine.Api.Search.Models
{
[JsonConverter(typeof(StringEnumConverter))]
public enum ItemType
{
Metadata,
Project,
Resource,
}
}
using Coscine.Database.ReturnObjects;
using System;
namespace Coscine.Api.Search.Models;
public class ResourceSearchResult : ResourceObject
{
public ResourceSearchResult(ResourceObject resourceObject, Guid? parentProjectId) : base(resourceObject.Id, resourceObject.DisplayName, resourceObject.ResourceName, resourceObject.Description, resourceObject.Keywords, resourceObject.UsageRights, resourceObject.Type, resourceObject.Disciplines, resourceObject.Visibility, resourceObject.License, resourceObject.ResourceTypeOption, resourceObject.ApplicationProfile, null, resourceObject.Creator, resourceObject.Archived)
{
ProjectId = parentProjectId;
}
public Guid? ProjectId { get; set; }
}
using Coscine.Database.ReturnObjects;
using System.Collections.Generic;
using System.Collections.Generic;
namespace Coscine.Api.Search.Models
{
......@@ -8,17 +7,9 @@ namespace Coscine.Api.Search.Models
/// </summary>
public class SearchResult
{
/// <summary>
/// Search result projects
/// </summary>
public IEnumerable<ProjectObject> Projects { get; set; }
/// <summary>
/// Search result resources
/// </summary>
public IEnumerable<ResourceSearchResult> Resources { get; set; }
/// <summary>
/// Search result files
/// </summary>
public IEnumerable<FileSearchResult> Files { get; set; }
public IEnumerable<ItemSearchResult> Items { get; set; }
}
}
......@@ -5,7 +5,7 @@
<AssemblyName>Coscine.Api.Search</AssemblyName>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TargetFramework>net6.0</TargetFramework>
<Version>1.4.0</Version>
<Version>1.5.0</Version>
</PropertyGroup>
<PropertyGroup>
<Authors>RWTH Aachen University</Authors>
......