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 { /// /// /// public class Helpers { /// /// 更新页面 如果Id为0则新增页面 /// /// /// /// /// 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; } /// /// 重建页面并将所有方面写入数据库 /// /// /// /// 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 /// /// /// /// /// private static List ParsePageTokens(IZelEngineState state) { var parsedTokens = new List(); 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 ComputeParsedPageTokens(string content, double weightMultiplier) { var searchConfig = ConfigurationRepository.GetConfigurationEntryValuesByGroupName("Search"); var exclusionWords = searchConfig?.Value("Word Exclusions")? .Split([',', ';'], StringSplitOptions.RemoveEmptyEntries).Distinct() ?? new List(); var strippedContent = Html.StripHtml(content); var tokens = strippedContent.Split([' ', '\n', '\t', '-', '_']).ToList(); if (searchConfig?.Value("Split Camel Case") == true) { var allSplitTokens = new List(); 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 } }