全文搜索Lucene.Net优化

2024-06-20 23:32
文章标签 优化 搜索 net lucene 全文

本文主要是介绍全文搜索Lucene.Net优化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

像www.verycd.com、博客园、淘宝、京东都有实现站内搜索功能,站内搜索无论在性能和用户体验上都非常不错,本节,通过使用Lucene.Net来实现站内搜索。

演示效果预览如下图10-22~10-24所示。

图10-22

 

图10-23

 

图10-24

在10.4节,已经完成了搜索的第一个版本,但是还有许多地方需要优化。比如说,我要统计关键词搜索的频率高的词,也即热词,以及像百度搜索那样,在输入关键字后,会自动把搜索相关的热词自动以下拉列表的形式带出来。还有诸如搜索结果分页,查看文章明细等。

10.5.1 热词统计

思路:

1、  首先,我们脑海里要明确一点:搜索关键字的统计,实时性是不高的。也就是说我们可以定期的去进行统计。

2、  客户的每一次搜索记录,我们都需要存起来,这样才能够统计得到。

从第1点,我们脑海中就会呈现一张汇总统计表,从第2点中,我们会想到使用一张搜索记录明细表。那方案就很明了了,只需要定期的从明细表中Group by查询,然后把查询结构放到汇总表中。怎么放到汇总表中?是直接Update更新吗?其实我们可以有更快捷的方式,那就是对汇总表先进行truncate,然后再进行insert操作。

表10-1 搜索汇总统计表SearchTotals

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchCounts

int

搜索次数

表10-2 搜索明细表SearchDetails

字段名称

字段类型

说明

Id

char(36)

主键,采用Guid方式存储

KeyWords

nvarchar(50)

搜索关键字

SearchDateTime

datetime

搜索时间

操作步骤:

(1)在Models文件夹中,新建两个类SearchTotal、SearchDetail。

SearchTotal.cs代码:

复制代码
using System;
using System.ComponentModel.DataAnnotations;namespace SearchDemo.Models
{public class SearchTotal{public Guid Id { get; set; }[StringLength(50)]public string KeyWords { get; set; }public int SearchCounts { get; set; }}
}
复制代码

SearchDetail.cs代码:

复制代码
using System;
using System.ComponentModel.DataAnnotations;namespace SearchDemo.Models
{public class SearchDetail{public Guid Id { get; set; }[StringLength(50)]public string KeyWords { get; set; }public Nullable<DateTime> SearchDateTime { get; set; }}
}
复制代码

(2)修改SearchDemoContext类,新增了属性SearchTotal、SearchDetail。

复制代码
using System.Data.Entity;namespace SearchDemo.Models
{public class SearchDemoContext : DbContext{public SearchDemoContext() : base("name=SearchDemoContext") { }public DbSet<Article> Article { get; set; }//下面两个属性是新增加的public DbSet<SearchTotal> SearchTotal { get; set; }public DbSet<SearchDetail> SearchDetail { get; set; }}
}
复制代码

3)更新数据库

由于修改了EF上下文,新增了两个模型类,所以需要进行迁移更新数据库操作。

将应用程序重新编译,然后选择工具->库程序包管理器->程序包管理控制台。

打开控制台,输入enable-migrations -force ,然后回车。回车后会在项目项目资源管理器中会出现Migrations文件夹,打开Configuration.cs 文件,将AutomaticMigrationsEnabled 值改为 true,然后在控制台中输入 update-database 运行。操作完成之后,会在数据库SearchDemo中多新建两张表SearchTotals、SearchDetails,而原来的Articles表保持不变。如图10-20所示。

 

图10-20

(4)保存搜索记录

用户在每次搜索的时候,要把搜索记录存入SearchDetails表中。为了方便,这里我是在用户每次点击搜索之后就立即往SearchDetails表中插入记录了,也就是同步操作,而实际上,如果为了提升搜索的效率,我们可以采用异步操作,即把搜索记录的数据先写入redis队列中,后台再开辟一个线程来监听redis队列,然后把队列中的搜索记录数据写入到数据表中。因为在每次点击搜索的时候,我们把记录往redis写和把记录直接往关系型数据库中写的效率是相差很大的。

 //先将搜索的词插入到明细表。SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };db.SearchDetail.Add(_SearchDetail);int r = db.SaveChanges();

(5)定时更新SearchTotals表记录

看到这种定时任务操作,这里可以采用Quartz.Net框架,为了方便,我把Quartz.Net的Job寄宿在控制台程序中,而实际工作中,我则更倾向于将其寄宿在Windows服务中。如果有必要,可以把这个定时更新SearchTotals表记录的程序部署到独立的服务器,这样可以减轻Web服务器的压力。

  1. 新建控制台程序QuartzNet,添加Quartz.dll和Common.Logging.dll的程序集引用,这里采用Database First的方式,添加ADO.NET实体数据模型,把表SearchTotals、SearchDetails添加进来。

2.添加KeyWordsTotalService.cs类,里面封装两个方法,清空SearchTotals表,然后把SearchDetails表的分组查询结构插入到SearchTotals表,这里我只统计近30天内的搜索明细。

复制代码
namespace QuartzNet
{public class KeyWordsTotalService{private SearchDemoEntities db = new SearchDemoEntities();/// <summary>/// 将统计的明细表的数据插入。/// </summary>/// <returns></returns>public bool InsertKeyWordsRank(){string sql = "insert into SearchTotals(Id,KeyWords,SearchCounts) select newid(),KeyWords,count(*)  from SearchDetails where DateDiff(day,SearchDetails.SearchDateTime,
getdate())<=30 group by SearchDetails.KeyWords
";return this.db.Database.ExecuteSqlCommand(sql) > 0;}/// <summary>/// 删除汇总中的数据。/// </summary>/// <returns></returns>public bool DeleteAllKeyWordsRank(){string sql = "truncate table SearchTotals";return this.db.Database.ExecuteSqlCommand(sql) > 0;}} }
复制代码

3. 添加TotalJob.cs类,继承Ijob接口,并实现Execute方法。

复制代码
namespace QuartzNet
{public class TotalJob : IJob{/// <summary>/// 将明细表中的数据插入到汇总表中。/// </summary>/// <param name="context"></param>public void Execute(JobExecutionContext context){KeyWordsTotalService bll = new KeyWordsTotalService();bll.DeleteAllKeyWordsRank();bll.InsertKeyWordsRank();}}
}
复制代码

4.修改Program.cs类

复制代码
using Quartz;
using Quartz.Impl;
using System;namespace QuartzNet
{class Program{static void Main(string[] args){IScheduler sched;ISchedulerFactory sf = new StdSchedulerFactory();sched = sf.GetScheduler();JobDetail job = new JobDetail("job1", "group1", typeof(TotalJob));//IndexJob为实现了IJob接口的类DateTime ts = TriggerUtils.GetNextGivenSecondDate(null, 5);//5秒后开始第一次运行TimeSpan interval = TimeSpan.FromSeconds(50);//每隔50秒执行一次Trigger trigger = new SimpleTrigger("trigger1", "group1", "job1", "group1", ts, null,SimpleTrigger.RepeatIndefinitely, interval);//每若干时间运行一次,时间间隔可以放到配置文件中指定
sched.AddJob(job, true);sched.ScheduleJob(trigger);sched.Start();Console.ReadKey();}}
}
复制代码

这里我是直接把Job和计划都直接写到代码中了,理由还是因为方便。而实际工作中,我们应当把这些信息尽量写到配置文件中,这样后面改动起来方便,不需要修改代码,只需要修改配置文件。

为了尽快看到效果,我这里是每隔50秒就进行了一次统计操作,而在实际应用中,我们的时间间隔可能是几个小时甚至一天,因为像这样的大数据统计,对实时性的要求不高,我们可以尽量减少对数据库的IO读写次数。

保持运行控制台程序QuartzNet,然后我们去进行搜索操作,这样后台就定期的生成了搜索统计记录。

10.5.2 热门搜索
10.5.2.1 展示热门搜索

其实就是从表SearchTotals中按照搜索次数进行降序排列,然后取出数条记录而已。

LastSearch控制器中的Index方法中添加如下代码:

var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();ViewBag.KeyWords = keyWords;

View视图中

<div id="divKeyWords"><span>热门搜索:</span>@if (ViewBag.KeyWords != null) {foreach (string v in ViewBag.KeyWords) { <a href="#">@v</a>}}</div>

接下来,我想要实现如下图10-21所示的效果:

 

图10-21

当我点击一个热词的时候,自动加载到文本框,并点击“搜索”按钮。

在View中添加代码:

复制代码
<script type="text/javascript">$(function () {$("#divKeyWords a").click(function () {$("#txtSearch").val($(this).html());$("#btnSearch").click();});
});
</script>
复制代码
10.5.2.2 搜索下拉框

这里我引入一个第三方js框架Autocomplete,它能在文本框中输入文字的时候,自动从后台抓去数据下拉列表。

云盘中我提供了Autocomplete.rar,将其解压,然后拷贝到SearchDemo项目中的lib目录下。

在SearchDemo项目中的KeyWordsTotalService.cs类中添加方法

复制代码
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;namespace SearchDemo.Common
{public class KeyWordsTotalService{private SearchDemoContext db = new SearchDemoContext();public List<string> GetSearchMsg(string term){try{//存在SQL注入的安全隐患//string sql = "select KeyWords from SearchTotals where KeyWords like '"+term.Trim()+"%'";//return db.Database.SqlQuery<string>(sql).ToList();string sql = "select KeyWords from SearchTotals where KeyWords like @term";return db.Database.SqlQuery<string>(sql, new SqlParameter("@term", term+"%")).ToList();}catch (Exception ex){throw new Exception(ex.Message);}}}
}
复制代码

然后在LastSearch控制器中添加方法:

复制代码
     /// <summary>/// 获取客户列表 模糊查询/// </summary>/// <param name="term"></param>/// <returns></returns>public string GetKeyWordsList(string term){if (string.IsNullOrWhiteSpace(term))return null;var list = new KeyWordsTotalService().GetSearchMsg(term);//序列化对象//尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替//System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();//return js.Serialize(list.ToArray());return JsonConvert.SerializeObject(list.ToArray());}
复制代码

我们来看View:

复制代码
<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>
<script type="text/javascript">$(function () {$("#divKeyWords a").click(function () {$("#txtSearch").val($(this).html());$("#btnSearch").click();});getKeyWordsList("txtSearch");});//自动加载搜索列表function getKeyWordsList(txt) {if (txt == undefined || txt == "")return;$("#" + txt).autocomplete({source: "/LastSearch/GetKeyWordsList",minLength: 1});}
</script>
复制代码
10.5.3 标题和内容都支持搜索并高亮展示

在10.4中,只支持在内容中对关键词进行搜索,而实际上,我们可能既要支持在标题中搜索,也要在内容中搜索。

这里引入了BooleanQuery,我们的查询条件也添加了一个titleQuery。

搜索方法中,如下代码有修改:

复制代码
 PhraseQuery query = new PhraseQuery();//查询条件PhraseQuery titleQuery = new PhraseQuery();//标题查询条件List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。foreach (string word in lstkw)            {query.Add(new Term("Content", word));//contains("Content",word)titleQuery.Add(new Term("Title", word));}query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了BooleanQuery bq = new BooleanQuery();//Occur.Should 表示 Or , Must 表示 and 运算bq.Add(query, BooleanClause.Occur.SHOULD);bq.Add(titleQuery, BooleanClause.Occur.SHOULD);TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collector
复制代码
10.5.4 与查询、或查询、分页

前面我们在搜索的时候,其实采用的都是与查询,也就是说,我输入“诸葛亮周瑜”,则只会查找出,既存在诸葛亮,又存在周瑜的记录。那么有时候,我们是想查询存在诸葛亮或者周瑜的记录的,这也就是所谓的或查询。

我在界面添加一个复选框“或查询”,来让用户决定采用何种方式进行查询。

至于分页,这里采用MvcPager,关于MvcPager的使用方法请参见4.6.3。

View完整代码预览:

复制代码
@{ViewBag.Title = "Index";
}
@model PagedList<SearchDemo.Models.SearchResult>
@using Webdiyer.WebControls.Mvc;
@using SearchDemo.Models;
<style type="text/css">
.search-text2{ display:block; width:528px; height:26px; line-height:26px; float:left; margin:3px 5px; border:1px solid gray; outline:none; font-family:'Microsoft Yahei'; font-size:14px;}
.search-btn2{width:102px; height:32px; line-height:32px; cursor:pointer; border:0px; background-color:#d6000f;font-family:'Microsoft Yahei'; font-size:16px;color:#f3f3f3;}
.search-list-con{width:640px; background-color:#fff; overflow:hidden; margin-top:0px; padding-bottom:15px; padding-top:5px;}
.search-list{width:600px; overflow:hidden; margin:15px 20px 0px 20px;}
.search-list dt{font-family:'Microsoft Yahei'; font-size:16px; line-height:20px; margin-bottom:7px; font-weight:normal;}
.search-list dt a{color:#2981a9;}
.search-list dt a em{ font-style:normal; color:#cc0000;}
#divKeyWords {text-align:left;width:520px;padding-left:4px;}
#divKeyWords a {text-decoration:none;}
#divKeyWords a:hover {color:red;}
</style>
<link href="~/lib/Autocomplete/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
@using(@Html.BeginForm(null, null, FormMethod.Get))
{@Html.Hidden("hidfIsOr")<div>@Html.TextBox("txtSearch", null, new { @class="search-text2"})<input type="submit" value="搜索" name="btnSearch" id="btnSearch"  class="search-btn2"/><input type="checkbox" id="isOr" value="false"/>或查询</div><div id="divKeyWords"><span>热门搜索:</span>@if (ViewBag.KeyWords != null) {foreach (string v in ViewBag.KeyWords) { <a href="#">@v</a>}}</div><div class="search-list-con"><dl class="search-list">@if (Model != null&& Model.Count > 0){foreach (var viewModel in Model){<dt><a href="@viewModel.Url" target="_blank">@MvcHtmlString.Create(viewModel.Title)</a><span style="margin-left:50px;">@viewModel.CreateTime</span></dt><dd>@MvcHtmlString.Create(viewModel.Msg)</dd>}} @Html.Pager(Model, new PagerOptions{PageIndexParameterName = "id",ShowPageIndexBox = true,FirstPageText = "首页",PrevPageText = "上一页",NextPageText = "下一页",LastPageText = "末页",PageIndexBoxType = PageIndexBoxType.TextBox,PageIndexBoxWrapperFormatString = "请输入页数{0}",GoButtonText = "转到"})<br />>>分页 共有 @(Model==null? 0: Model.TotalItemCount) 篇文章 @(Model==null?0:Model.CurrentPageIndex)/@(Model==null?0:Model.TotalPageCount)</dl></div><div>@ViewData["ShowInfo"]</div>
}
<script type="text/javascript">$(function () {$("#divKeyWords a").click(function () {$("#txtSearch").val($(this).html());$("#btnSearch").click();});getKeyWordsList("txtSearch");$("#isOr").click(function () {if ($(this).attr("checked") == "checked") {$("#hidfIsOr").val(true);}else {$("#hidfIsOr").val(false);}});if ($("#hidfIsOr").val() == "true") {$("input[type='checkbox']").prop("checked", true);}});//自动加载搜索列表function getKeyWordsList(txt) {if (txt == undefined || txt == "")return;$("#" + txt).autocomplete({source: "/LastSearch/GetKeyWordsList",minLength: 1});}
</script>
<script src="~/lib/Autocomplete/js/jquery-ui-1.8.17.custom.min.js"></script>
复制代码

然后,各位看官请再看LastSearch控制器中的方法:

复制代码
 public class LastSearchController : Controller{//// GET: /LastSearch/string indexPath = System.Configuration.ConfigurationManager.AppSettings["lucenedir"];private SearchDemoContext db = new SearchDemoContext();public ActionResult Index(string txtSearch, bool? hidfIsOr, int id = 1){PagedList<SearchResult> list = null;if (!string.IsNullOrEmpty(txtSearch))//如果点击的是查询按钮
            {//list = Search(txtSearch);list = (hidfIsOr == null || hidfIsOr.Value == false) ? OrSearch(txtSearch, id) : AndSearch(txtSearch, id);}var keyWords = db.SearchTotal.OrderByDescending(a => a.SearchCounts).Select(x => x.KeyWords).Skip(0).Take(6).ToList();ViewBag.KeyWords = keyWords;return View(list);}//与查询PagedList<SearchResult> AndSearch(String kw, int pageNo, int pageLen = 4){FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());IndexReader reader = IndexReader.Open(directory, true);IndexSearcher searcher = new IndexSearcher(reader);PhraseQuery query = new PhraseQuery();//查询条件PhraseQuery titleQuery = new PhraseQuery();//标题查询条件List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。foreach (string word in lstkw){query.Add(new Term("Content", word));//contains("Content",word)titleQuery.Add(new Term("Title", word));}query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了
BooleanQuery bq = new BooleanQuery();//Occur.Should 表示 Or , Must 表示 and 运算
            bq.Add(query, BooleanClause.Occur.SHOULD);bq.Add(titleQuery, BooleanClause.Occur.SHOULD);TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collectorint recCount=collector.GetTotalHits();//总的结果条数ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo*pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据
List<SearchResult> list = new List<SearchResult>();string msg = string.Empty;string title = string.Empty;for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)//所以查询结果中只有id,具体内容需要二次查询Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是DocumentSearchResult result = new SearchResult();result.Id = Convert.ToInt32(doc.Get("Id"));msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。title = doc.Get("Title");foreach (string word in lstkw){title=title.Replace(word,"<span style='color:red;'>"+word+"</span>");}//result.Title=LuceneHelper.CreateHightLight(kw, title);result.Title = title;result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;list.Add(result);}//先将搜索的词插入到明细表。SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };db.SearchDetail.Add(_SearchDetail);int r = db.SaveChanges();PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);lst.TotalItemCount = recCount;lst.CurrentPageIndex = pageNo;return lst;}//或查询PagedList<SearchResult> OrSearch(String kw, int pageNo, int pageLen = 4){FSDirectory directory = FSDirectory.Open(new DirectoryInfo(indexPath), new NoLockFactory());IndexReader reader = IndexReader.Open(directory, true);IndexSearcher searcher = new IndexSearcher(reader);List<PhraseQuery> lstQuery = new List<PhraseQuery>();List<string> lstkw = LuceneHelper.PanGuSplitWord(kw);//对用户输入的搜索条件进行拆分。foreach (string word in lstkw){PhraseQuery query = new PhraseQuery();//查询条件query.SetSlop(100);//两个词的距离大于100(经验值)就不放入搜索结果,因为距离太远相关度就不高了query.Add(new Term("Content", word));//contains("Content",word)
PhraseQuery titleQuery = new PhraseQuery();//查询条件titleQuery.Add(new Term("Title", word));lstQuery.Add(query);lstQuery.Add(titleQuery);}BooleanQuery bq = new BooleanQuery();foreach (var v in lstQuery){//Occur.Should 表示 Or , Must 表示 and 运算
                bq.Add(v, BooleanClause.Occur.SHOULD);}TopScoreDocCollector collector = TopScoreDocCollector.create(1000, true);//盛放查询结果的容器searcher.Search(bq, null, collector);//使用query这个查询条件进行搜索,搜索结果放入collectorint recCount = collector.GetTotalHits();//总的结果条数ScoreDoc[] docs = collector.TopDocs((pageNo - 1) * pageLen, pageNo * pageLen).scoreDocs;//从查询结果中取出第m条到第n条的数据
List<SearchResult> list = new List<SearchResult>();string msg = string.Empty;string title = string.Empty;for (int i = 0; i < docs.Length; i++)//遍历查询结果
            {int docId = docs[i].doc;//拿到文档的id,因为Document可能非常占内存(思考DataSet和DataReader的区别)//所以查询结果中只有id,具体内容需要二次查询Document doc = searcher.Doc(docId);//根据id查询内容。放进去的是Document,查出来的还是DocumentSearchResult result = new SearchResult();result.Id = Convert.ToInt32(doc.Get("Id"));msg = doc.Get("Content");//只有 Field.Store.YES的字段才能用Get查出来result.Msg = LuceneHelper.CreateHightLight(kw, msg);//将搜索的关键字高亮显示。title = doc.Get("Title");foreach (string word in lstkw){title = title.Replace(word, "<span style='color:red;'>" + word + "</span>");}//result.Title=LuceneHelper.CreateHightLight(kw, title);result.Title = title;result.CreateTime = Convert.ToDateTime(doc.Get("CreateTime"));result.Url = "/Article/Details?Id=" + result.Id + "&kw=" + kw;list.Add(result);}//先将搜索的词插入到明细表。SearchDetail _SearchDetail = new SearchDetail { Id = Guid.NewGuid(), KeyWords = kw, SearchDateTime = DateTime.Now };db.SearchDetail.Add(_SearchDetail);int r = db.SaveChanges();PagedList<SearchResult> lst = new PagedList<SearchResult>(list, pageNo, pageLen, recCount);lst.TotalItemCount = recCount;lst.CurrentPageIndex = pageNo;return lst;}/// <summary>/// 获取客户列表 模糊查询/// </summary>/// <param name="term"></param>/// <returns></returns>public string GetKeyWordsList(string term){if (string.IsNullOrWhiteSpace(term))return null;var list = new KeyWordsTotalService().GetSearchMsg(term);//序列化对象//尽量不要用JavaScriptSerializer,为什么?性能差,完全可用Newtonsoft.Json来代替//System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer();//return js.Serialize(list.ToArray());return JsonConvert.SerializeObject(list.ToArray());}
复制代码

这篇关于全文搜索Lucene.Net优化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079571

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

2、PF-Net点云补全

2、PF-Net 点云补全 PF-Net论文链接:PF-Net PF-Net (Point Fractal Network for 3D Point Cloud Completion)是一种专门为三维点云补全设计的深度学习模型。点云补全实际上和图片补全是一个逻辑,都是采用GAN模型的思想来进行补全,在图片补全中,将部分像素点删除并且标记,然后卷积特征提取预测、判别器判别,来训练模型,生成的像

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者