using Masuit.LuceneEFCore.SearchEngine; using Masuit.LuceneEFCore.SearchEngine.Interfaces; using Masuit.MyBlogs.Core.Common; using Masuit.MyBlogs.Core.Infrastructure.Repository.Interface; using Masuit.MyBlogs.Core.Infrastructure.Services.Interface; using Masuit.MyBlogs.Core.Models.DTO; using Masuit.MyBlogs.Core.Models.Entity; using Masuit.MyBlogs.Core.Models.Enum; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.Extensions.Caching.Memory; using PanGu; using PanGu.HighLight; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; namespace Masuit.MyBlogs.Core.Infrastructure.Services { public partial class PostService : BaseService, IPostService { private readonly IMemoryCache _memoryCache; public PostService(IPostRepository repository, ISearchEngine searchEngine, ILuceneIndexSearcher searcher, IMemoryCache memoryCache) : base(repository, searchEngine, searcher) { _memoryCache = memoryCache; } public SearchResult SearchPage(int page, int size, string keyword) { var cacheKey = $"search:{keyword}:{page}:{size}"; if (_memoryCache.TryGetValue>(cacheKey, out var value)) { return value; } var searchResult = _searchEngine.ScoredSearch(BuildSearchOptions(page, size, keyword)); var posts = searchResult.Results.Select(p => p.Entity.Mapper()).Where(p => p.Status == Status.Pended).ToList(); var simpleHtmlFormatter = new SimpleHTMLFormatter("", ""); var highlighter = new Highlighter(simpleHtmlFormatter, new Segment()) { FragmentSize = 200 }; var keywords = _searcher.CutKeywords(keyword); foreach (var p in posts) { foreach (var s in keywords) { string frag; if (p.Title.Contains(s) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(s, p.Title))) { p.Title = frag; break; } } bool handled = false; foreach (var s in keywords) { string frag; if (p.Content.Contains(s) && !string.IsNullOrEmpty(frag = highlighter.GetBestFragment(s, p.Content))) { p.Content = frag; handled = true; break; } } if (p.Content.Length > 200 && !handled) { p.Content = p.Content.Substring(0, 200); } } var result = new SearchResult() { Results = posts, Elapsed = searchResult.Elapsed, Total = searchResult.TotalHits }; return _memoryCache.Set(cacheKey, result, TimeSpan.FromHours(1)); } private static SearchOptions BuildSearchOptions(int page, int size, string keyword) { var fields = new List(); var newkeywords = new List(); if (keyword.Contains("intitle:")) { fields.Add("Title"); newkeywords.Add(keyword.Split(' ', ' ').FirstOrDefault(s => s.Contains("intitle")).Split(':')[1]); } if (keyword.Contains("content:")) { fields.Add("Content"); newkeywords.Add(keyword.Split(' ', ' ').FirstOrDefault(s => s.Contains("content")).Split(':')[1]); } var searchOptions = fields.Any() ? new SearchOptions(newkeywords.Join(" "), page, size, fields.Join(",")) : new SearchOptions(keyword, page, size, typeof(Post)); return searchOptions; } /// /// 添加实体并保存 /// /// 需要添加的实体 /// 添加成功 public override Post AddEntitySaved(Post t) { t = base.AddEntity(t); _searchEngine.SaveChanges(t.Status == Status.Pended); return t; } /// /// 添加实体并保存(异步) /// /// 需要添加的实体 /// 添加成功 public override Task AddEntitySavedAsync(Post t) { base.AddEntity(t); return _searchEngine.SaveChangesAsync(t.Status == Status.Pended); } /// /// 根据ID删除实体并保存 /// /// 实体id /// 删除成功 public override bool DeleteByIdSaved(object id) { base.DeleteById(id); return _searchEngine.SaveChanges() > 0; } /// /// 删除多个实体并保存 /// /// 实体集合 /// 删除成功 public override bool DeleteEntitiesSaved(IEnumerable list) { base.DeleteEntities(list); return _searchEngine.SaveChanges() > 0; } /// /// 根据ID删除实体并保存(异步) /// /// 实体id /// 删除成功 public override Task DeleteByIdSavedAsync(object id) { base.DeleteById(id); return _searchEngine.SaveChangesAsync(); } /// /// 删除多个实体并保存(异步) /// /// 实体集合 /// 删除成功 public override Task DeleteEntitiesSavedAsync(IEnumerable list) { base.DeleteEntities(list); return _searchEngine.SaveChangesAsync(); } /// /// 根据条件删除实体 /// /// 查询条件 /// 删除成功 public override int DeleteEntitySaved(Expression> @where) { base.DeleteEntity(@where); return _searchEngine.SaveChanges(); } /// /// 删除实体并保存 /// /// 需要删除的实体 /// 删除成功 public override bool DeleteEntitySaved(Post t) { base.DeleteEntity(t); return _searchEngine.SaveChanges() > 0; } /// /// 根据条件删除实体 /// /// 查询条件 /// 删除成功 public override Task DeleteEntitySavedAsync(Expression> @where) { base.DeleteEntity(@where); return _searchEngine.SaveChangesAsync(); } /// /// 删除实体并保存(异步) /// /// 需要删除的实体 /// 删除成功 public override Task DeleteEntitySavedAsync(Post t) { base.DeleteEntity(t); return _searchEngine.SaveChangesAsync(); } } }