mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 08:13:31 +08:00
Merge pull request #22782 from OliBomby/optimise-search
Optimise carousel beatmap filter method
This commit is contained in:
commit
9479b7c19f
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
123
osu.Game.Benchmarks/BenchmarkCarouselFilter.cs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
using osu.Game.Screens.Select.Carousel;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkCarouselFilter : BenchmarkTest
|
||||||
|
{
|
||||||
|
private BeatmapInfo getExampleBeatmap() => new BeatmapInfo
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo
|
||||||
|
{
|
||||||
|
ShortName = "osu",
|
||||||
|
OnlineID = 0
|
||||||
|
},
|
||||||
|
StarRating = 4.0d,
|
||||||
|
Difficulty = new BeatmapDifficulty
|
||||||
|
{
|
||||||
|
ApproachRate = 5.0f,
|
||||||
|
DrainRate = 3.0f,
|
||||||
|
CircleSize = 2.0f,
|
||||||
|
},
|
||||||
|
Metadata = new BeatmapMetadata
|
||||||
|
{
|
||||||
|
Artist = "The Artist",
|
||||||
|
ArtistUnicode = "check unicode too",
|
||||||
|
Title = "Title goes here",
|
||||||
|
TitleUnicode = "Title goes here",
|
||||||
|
Author = { Username = "The Author" },
|
||||||
|
Source = "unit tests",
|
||||||
|
Tags = "look for tags too",
|
||||||
|
},
|
||||||
|
DifficultyName = "version as well",
|
||||||
|
Length = 2500,
|
||||||
|
BPM = 160,
|
||||||
|
BeatDivisor = 12,
|
||||||
|
Status = BeatmapOnlineStatus.Loved
|
||||||
|
};
|
||||||
|
|
||||||
|
private CarouselBeatmap carouselBeatmap = null!;
|
||||||
|
private FilterCriteria criteria1 = null!;
|
||||||
|
private FilterCriteria criteria2 = null!;
|
||||||
|
private FilterCriteria criteria3 = null!;
|
||||||
|
private FilterCriteria criteria4 = null!;
|
||||||
|
private FilterCriteria criteria5 = null!;
|
||||||
|
private FilterCriteria criteria6 = null!;
|
||||||
|
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
var beatmap = getExampleBeatmap();
|
||||||
|
beatmap.OnlineID = 20201010;
|
||||||
|
beatmap.BeatmapSet = new BeatmapSetInfo { OnlineID = 1535 };
|
||||||
|
carouselBeatmap = new CarouselBeatmap(beatmap);
|
||||||
|
criteria1 = new FilterCriteria();
|
||||||
|
criteria2 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { ShortName = "catch" }
|
||||||
|
};
|
||||||
|
criteria3 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||||
|
AllowConvertedBeatmaps = true,
|
||||||
|
BPM = new FilterCriteria.OptionalRange<double>
|
||||||
|
{
|
||||||
|
IsUpperInclusive = false,
|
||||||
|
Max = 160d
|
||||||
|
}
|
||||||
|
};
|
||||||
|
criteria4 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Ruleset = new RulesetInfo { OnlineID = 6 },
|
||||||
|
AllowConvertedBeatmaps = true,
|
||||||
|
SearchText = "an artist"
|
||||||
|
};
|
||||||
|
criteria5 = new FilterCriteria
|
||||||
|
{
|
||||||
|
Creator = new FilterCriteria.OptionalTextFilter { SearchTerm = "the author AND then something else" }
|
||||||
|
};
|
||||||
|
criteria6 = new FilterCriteria { SearchText = "20201010" };
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CarouselBeatmapFilter()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingSpecificRuleset()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingRangeMax()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingTerms()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingCreator()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria5);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void CriteriaMatchingBeatmapIDs()
|
||||||
|
{
|
||||||
|
carouselBeatmap.Filter(criteria6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -29,10 +29,21 @@ namespace osu.Game.Beatmaps
|
|||||||
return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim());
|
return new RomanisableString($"{metadata.GetPreferred(true)}".Trim(), $"{metadata.GetPreferred(false)}".Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] GetSearchableTerms(this IBeatmapInfo beatmapInfo) => new[]
|
public static List<string> GetSearchableTerms(this IBeatmapInfo beatmapInfo)
|
||||||
{
|
{
|
||||||
beatmapInfo.DifficultyName
|
var termsList = new List<string>(BeatmapMetadataInfoExtensions.MAX_SEARCHABLE_TERM_COUNT + 1);
|
||||||
}.Concat(beatmapInfo.Metadata.GetSearchableTerms()).Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
|
||||||
|
addIfNotNull(beatmapInfo.DifficultyName);
|
||||||
|
|
||||||
|
BeatmapMetadataInfoExtensions.CollectSearchableTerms(beatmapInfo.Metadata, termsList);
|
||||||
|
return termsList;
|
||||||
|
|
||||||
|
void addIfNotNull(string? s)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(s))
|
||||||
|
termsList.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
private static string getVersionString(IBeatmapInfo beatmapInfo) => string.IsNullOrEmpty(beatmapInfo.DifficultyName) ? string.Empty : $"[{beatmapInfo.DifficultyName}]";
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
@ -13,16 +13,31 @@ namespace osu.Game.Beatmaps
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// An array of all searchable terms provided in contained metadata.
|
/// An array of all searchable terms provided in contained metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo) => new[]
|
public static string[] GetSearchableTerms(this IBeatmapMetadataInfo metadataInfo)
|
||||||
{
|
{
|
||||||
metadataInfo.Author.Username,
|
var termsList = new List<string>(MAX_SEARCHABLE_TERM_COUNT);
|
||||||
metadataInfo.Artist,
|
CollectSearchableTerms(metadataInfo, termsList);
|
||||||
metadataInfo.ArtistUnicode,
|
return termsList.ToArray();
|
||||||
metadataInfo.Title,
|
}
|
||||||
metadataInfo.TitleUnicode,
|
|
||||||
metadataInfo.Source,
|
internal const int MAX_SEARCHABLE_TERM_COUNT = 7;
|
||||||
metadataInfo.Tags
|
|
||||||
}.Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
internal static void CollectSearchableTerms(IBeatmapMetadataInfo metadataInfo, IList<string> termsList)
|
||||||
|
{
|
||||||
|
addIfNotNull(metadataInfo.Author.Username);
|
||||||
|
addIfNotNull(metadataInfo.Artist);
|
||||||
|
addIfNotNull(metadataInfo.ArtistUnicode);
|
||||||
|
addIfNotNull(metadataInfo.Title);
|
||||||
|
addIfNotNull(metadataInfo.TitleUnicode);
|
||||||
|
addIfNotNull(metadataInfo.Source);
|
||||||
|
addIfNotNull(metadataInfo.Tags);
|
||||||
|
|
||||||
|
void addIfNotNull(string s)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(s))
|
||||||
|
termsList.Add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A user-presentable display title representing this metadata.
|
/// A user-presentable display title representing this metadata.
|
||||||
|
@ -26,6 +26,11 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
{
|
{
|
||||||
base.Filter(criteria);
|
base.Filter(criteria);
|
||||||
|
|
||||||
|
Filtered.Value = !checkMatch(criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool checkMatch(FilterCriteria criteria)
|
||||||
|
{
|
||||||
bool match =
|
bool match =
|
||||||
criteria.Ruleset == null ||
|
criteria.Ruleset == null ||
|
||||||
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
|
BeatmapInfo.Ruleset.ShortName == criteria.Ruleset.ShortName ||
|
||||||
@ -34,8 +39,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
|
if (BeatmapInfo.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
|
||||||
{
|
{
|
||||||
// only check ruleset equality or convertability for selected beatmap
|
// only check ruleset equality or convertability for selected beatmap
|
||||||
Filtered.Value = !match;
|
return match;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
match &= !criteria.StarDifficulty.HasFilter || criteria.StarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||||
@ -49,18 +53,38 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
|
match &= !criteria.BeatDivisor.HasFilter || criteria.BeatDivisor.IsInRange(BeatmapInfo.BeatDivisor);
|
||||||
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
|
match &= !criteria.OnlineStatus.HasFilter || criteria.OnlineStatus.IsInRange(BeatmapInfo.Status);
|
||||||
|
|
||||||
|
if (!match) return false;
|
||||||
|
|
||||||
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
|
match &= !criteria.Creator.HasFilter || criteria.Creator.Matches(BeatmapInfo.Metadata.Author.Username);
|
||||||
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
|
match &= !criteria.Artist.HasFilter || criteria.Artist.Matches(BeatmapInfo.Metadata.Artist) ||
|
||||||
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
|
criteria.Artist.Matches(BeatmapInfo.Metadata.ArtistUnicode);
|
||||||
|
|
||||||
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
match &= !criteria.UserStarDifficulty.HasFilter || criteria.UserStarDifficulty.IsInRange(BeatmapInfo.StarRating);
|
||||||
|
|
||||||
if (match && criteria.SearchTerms.Length > 0)
|
if (!match) return false;
|
||||||
|
|
||||||
|
if (criteria.SearchTerms.Length > 0)
|
||||||
{
|
{
|
||||||
string[] terms = BeatmapInfo.GetSearchableTerms();
|
var terms = BeatmapInfo.GetSearchableTerms();
|
||||||
|
|
||||||
foreach (string criteriaTerm in criteria.SearchTerms)
|
foreach (string criteriaTerm in criteria.SearchTerms)
|
||||||
match &= terms.Any(term => term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase));
|
{
|
||||||
|
bool any = false;
|
||||||
|
|
||||||
|
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
|
||||||
|
foreach (string term in terms)
|
||||||
|
{
|
||||||
|
if (!term.Contains(criteriaTerm, StringComparison.InvariantCultureIgnoreCase)) continue;
|
||||||
|
|
||||||
|
any = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (any) continue;
|
||||||
|
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
// if a match wasn't found via text matching of terms, do a second catch-all check matching against online IDs.
|
||||||
// this should be done after text matching so we can prioritise matching numbers in metadata.
|
// this should be done after text matching so we can prioritise matching numbers in metadata.
|
||||||
@ -71,13 +95,14 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match)
|
if (!match) return false;
|
||||||
|
|
||||||
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
match &= criteria.CollectionBeatmapMD5Hashes?.Contains(BeatmapInfo.MD5Hash) ?? true;
|
||||||
|
|
||||||
if (match && criteria.RulesetCriteria != null)
|
if (match && criteria.RulesetCriteria != null)
|
||||||
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
match &= criteria.RulesetCriteria.Matches(BeatmapInfo);
|
||||||
|
|
||||||
Filtered.Value = !match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int CompareTo(FilterCriteria criteria, CarouselItem other)
|
public override int CompareTo(FilterCriteria criteria, CarouselItem other)
|
||||||
|
Loading…
Reference in New Issue
Block a user