Files
ZelWiki/ZelWiki.Engine.Implementation/Helpers.cs
2025-02-23 18:47:21 +08:00

139 lines
4.9 KiB
C#

using DuoVia.FuzzyStrings;
using NTDLS.Helpers;
using ZelWiki.Caching;
using ZelWiki.Engine.Library;
using ZelWiki.Engine.Library.Interfaces;
using ZelWiki.Library.Interfaces;
using ZelWiki.Models.DataModels;
using ZelWiki.Repository;
namespace ZelWiki.Engine.Implementation
{
/// <summary>
///
/// </summary>
public class Helpers
{
/// <summary>
/// 更新页面 如果Id为0则新增页面
/// </summary>
/// <param name="wikifier"></param>
/// <param name="page"></param>
/// <param name="sessionState"></param>
/// <returns></returns>
public static int UpsertPage(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
{
var isNewlyCreated = page.Id == 0;
page.Id = PageRepository.SavePage(page);
RefreshPageMetadata(wikifier, page, sessionState);
if (isNewlyCreated)
PageRepository.UpdateSinglePageReference(page.Navigation, page.Id);
return page.Id;
}
/// <summary>
/// 重建页面并将所有方面写入数据库
/// </summary>
/// <param name="wikifier"></param>
/// <param name="page"></param>
/// <param name="sessionState"></param>
public static void RefreshPageMetadata(IZelEngine wikifier, Page page, ISessionState? sessionState = null)
{
var state = wikifier.Transform(sessionState, page, null,
[Constants.WikiMatchType.StandardFunction]);
PageRepository.UpdatePageTags(page.Id, state.Tags);
PageRepository.UpdatePageProcessingInstructions(page.Id, state.ProcessingInstructions);
var pageTokens = ParsePageTokens(state).Select(o =>
new PageToken
{
PageId = page.Id,
Token = o.Token,
DoubleMetaphone = o.DoubleMetaphone,
Weight = o.Weight
}).ToList();
PageRepository.SavePageSearchTokens(pageTokens);
PageRepository.UpdatePageReferences(page.Id, state.OutgoingLinks);
WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [page.Id]));
WikiCache.ClearCategory(WikiCacheKey.Build(WikiCache.Category.Page, [page.Navigation]));
}
#region Private
/// <summary>
///
/// </summary>
/// <param name="state"></param>
/// <returns></returns>
private static List<AggregatedSearchToken> ParsePageTokens(IZelEngineState state)
{
var parsedTokens = new List<WeightedSearchToken>();
parsedTokens.AddRange(ComputeParsedPageTokens(state.HtmlResult, 1));
parsedTokens.AddRange(ComputeParsedPageTokens(state.Page.Description, 1.2));
parsedTokens.AddRange(ComputeParsedPageTokens(string.Join(" ", state.Tags), 1.4));
parsedTokens.AddRange(ComputeParsedPageTokens(state.Page.Name, 1.6));
var aggregatedTokens = parsedTokens.GroupBy(o => o.Token).Select(o => new AggregatedSearchToken
{
Token = o.Key,
DoubleMetaphone = o.Key.ToDoubleMetaphone(),
Weight = o.Sum(g => g.Weight)
}).ToList();
return aggregatedTokens;
}
private static List<WeightedSearchToken> ComputeParsedPageTokens(string content, double weightMultiplier)
{
var searchConfig = ConfigurationRepository.GetConfigurationEntryValuesByGroupName("Search");
var exclusionWords = searchConfig?.Value<string>("Word Exclusions")?
.Split([',', ';'], StringSplitOptions.RemoveEmptyEntries).Distinct() ?? new List<string>();
var strippedContent = Html.StripHtml(content);
var tokens = strippedContent.Split([' ', '\n', '\t', '-', '_']).ToList();
if (searchConfig?.Value<bool>("Split Camel Case") == true)
{
var allSplitTokens = new List<string>();
foreach (var token in tokens)
{
var splitTokens = Text.SplitCamelCase(token);
if (splitTokens.Count > 1)
{
splitTokens.ForEach(t => allSplitTokens.Add(t));
}
}
tokens.AddRange(allSplitTokens);
}
tokens = tokens.ConvertAll(d => d.ToLowerInvariant());
tokens.RemoveAll(o => exclusionWords.Contains(o));
var searchTokens = (from w in tokens
group w by w
into g
select new WeightedSearchToken
{
Token = g.Key,
Weight = g.Count() * weightMultiplier
}).ToList();
return searchTokens.Where(o => string.IsNullOrWhiteSpace(o.Token) == false).ToList();
}
#endregion
}
}