我记得在园子里有园友提出博客园的搜索功能是采用的Lucene.net,具体是不是我也不确定,但是宁可信其是,所以我在仿照博客园 搜索功能的时候采用的也是Lucene.net,有园友给我提意见,就是我以前的博客中提到的那些框架,例如log4net,Quartz.net等都是片面的讲解一个框架结构,只能作为练习用,而不能真正的在项目中使用,具体原因就是在实战中会遇到各种问题,没对应的策略,所以今天我就来把我这个仿照系统的搜索功能的实现简单的描述一下,重点说明的是在项目中使用这些框架应该注意的地方,这样才会更贴切实战,也更有用一些。
利用Lucene.net 进行搜索,应该分为三步走战略
总的来说就是这三步,下面我们来具体分析一下这三步在实战中都应该采用什么策略。
首先,创建索引,因为博客会不断的被添加,所以我们在创建索引的时候要指定索引为增量添加(在IndexWriter实例化的时候有一个属性设置为false就可以)
1 Lucene.Net.Store.Directory dir = FSDirectory.Open("d:/index"); 2 IndexWriter writer = new IndexWriter(dir, new PanGuAnalyzer(), false, IndexWriter.MaxFieldLength.LIMITED);
设置了创建索引为增量索引以后,我们还需要指定其中的某些参数,让lucene.net在特定的计算机上工作最大化。
现在有一个问题出现了,我们不可能手动的去创建索引,所以我们要使用定时器去自动的创建索引,这就用到了Quartz.net定时器,
还有一个问题就是我们创建索引因为是自动创建,所以不需要界面显示,并且需要在后台运行,所以我们创建索引最好是采用Windows 服务形式来承载。
当然了,在程序运行过程中会遇到各种问题,需要我们记录成粗错误发生的位置以及时间,这就会用到log4net 日志管理框架。
问题一个一个的出现了,现在我们就要把这些问题逐个的解决,首先就是创建Windows 服务,这个在Vs中很容易的就可以实现。现在我把仿照博客园实现搜索的Windows服务的部分代码贴出来分析一下,
1 public partial class Service1 : ServiceBase 2 { 3 private readonly ILog logger = LogManager.GetLogger(typeof(Service1)); 4
5
6 public Service1() 7 { 8 log4net.Config.XmlConfigurator.Configure(); 9 InitializeComponent(); 10 SchedulerManager.GetSchedulerFactory().GetScheduler().ListenerManager.AddJobListener(SchedulerManager.GetJobListener()); 11 } 12
13 protected override void OnStart(string[] args) 14 { 15 try
16 { 17 JobKey jobKey = new JobKey("CreateIndex", "CreateIndexGroup"); 18
19 IJobDetail jobDetail = JobBuilder.Create().WithIdentity(jobKey).OfType(typeof(Jobs.QuzrtaNet)).Build(); 20
21 ITrigger trigger = TriggerBuilder.Create().WithCronSchedule("0 0/59 * * * ?").StartNow().Build(); 22 SchedulerManager.GetScheduler().ScheduleJob(jobDetail, trigger); 23 logger.Info("任务 " + jobDetail.Key.Group + "已经调度陈功"); 24 if (SchedulerManager.GetScheduler().IsStarted == false) 25 { 26 SchedulerManager.GetScheduler().Start(); 27 logger.Info("服务已经成功启动"); 28 } 29 } 30 catch (Exception ex) 31 { 32 logger.Error("服务启动失败", ex); 33 if (this.CanStop == true) 34 { 35 this.Stop(); 36 } 37 } 38 } 39
40 protected override void OnStop() 41 { 42 try
43 { 44 if (SchedulerManager.GetScheduler().IsShutdown == false) 45 { 46 SchedulerManager.GetScheduler().Shutdown(); 47 logger.Info("Quartz服务成功终止"); 48 } 49 } 50 catch (Exception ex) 51 { 52 logger.Error("服务停止失败",ex); 53 } 54
55 } 56 protected override void OnPause() 57 { 58
59 } 60
61 protected override void OnContinue() 62 { 63
64 } 65 }
在上面额代码中,有几点我要说明一下。
1 <configSections>
2 <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
3 </configSections>
4 <log4net debug="false">
5 <appender name="LogFileAppender" type="log4net.Appender.FileAppender">
6 <param name="File" value="c:\Log\DBLog.txt"/>
7 <param name="AppendToFile" value="true"/>
8 <layout type="log4net.Layout.PatternLayout">
9 <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n"/>
10 </layout>
11 </appender>
12
13 <appender name="ADONetAppender" type="log4net.Appender.ADONetAppender">
14 <bufferSize value="10"/>
15 <connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
16 <connectionString value="server=.\sqlexpress;database=DbLog;user id=sa;password=yuanjinzhou"/>
17 <commandText value="INSERT INTO Log ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception)"/>
18 <parameter>
19 <parameterName value="@log_date"/>
20 <dbType value="DateTime"/>
21 <layout type="log4net.Layout.RawTimeStampLayout"/>
22 </parameter>
23 <parameter>
24 <parameterName value="@thread"/>
25 <dbType value="String"/>
26 <size value="255"/>
27 <layout type="log4net.Layout.PatternLayout">
28 <conversionPattern value="%thread"/>
29 </layout>
30 </parameter>
31 <parameter>
32 <parameterName value="@log_level"/>
33 <dbType value="String"/>
34 <size value="50"/>
35 <layout type="log4net.Layout.PatternLayout">
36 <conversionPattern value="%level"/>
37 </layout>
38 </parameter>
39 <parameter>
40 <parameterName value="@logger"/>
41 <dbType value="String"/>
42 <size value="255"/>
43 <layout type="log4net.Layout.PatternLayout">
44 <conversionPattern value="%logger"/>
45 </layout>
46 </parameter>
47 <parameter>
48 <parameterName value="@message"/>
49 <dbType value="String"/>
50 <size value="4000"/>
51 <layout type="log4net.Layout.PatternLayout">
52 <conversionPattern value="%message"/>
53 </layout>
54 </parameter>
55 <parameter>
56 <parameterName value="@exception"/>
57 <dbType value="String"/>
58 <size value="2000"/>
59 <layout type="log4net.Layout.ExceptionLayout"/>
60 </parameter>
61 </appender>
62 <root>
63 <level value="DEBUG"/>
64 <appender-ref ref="ADONetAppender"/>
65 <appender-ref ref="LogFileAppender"/>
66 </root>
67 </log4net>
log4net的输出介质园子里有很多介绍,我这里贴出来配置文件,就是不想有太多人因为拼写错误而导致log4net不能正常工作。其中我要特别强调一下的
就是log4net输出日志到数据库中,这里面有很多配置参数,其中
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
connectionType结点中的System.Data后面的Version以后的内容我们一定要添加上,我在多次试验中发现如果后面的版本号不加上的话,log4net不
会正确的把日志插入到数据库中,而加上版本号就可以,所以当你不能把日志插入到数据库中时,检查一下版本号是否写上。
总结一下,log4net日志管理框架,可以输出日志到任何的介质,对log4net的配置文件的配置是重点。
Lucene.net可以用来实现创建索引,通过索引进行查询,实现全文检索的功能。
Quartz.net 实现的是定时器任务,可以按照定时规则按照规定的时间执行任务。
根据我在仿照博客园搜索功能中遇到的问题,其实任何一个框架的单纯使用都很简单,但是在实战中如何更加合理的使用这些框架,更加高效的让这些框架协同工
作使我们做项目的时候需要思考的重点,有时候思考 分析一下,甚至总结一下会对自己的能力提升有很大的好处。虽然我在这篇博客中总结的问题不多,但是这
都是我在做项目的时候遇到的问题,困扰了我好几天的时间才发现的原因。
有总结才会有提高,有总结才会有进步,我不敢说通过完善这个仿照博客园的系统我有学习到很多东西,但是我发现了我自己的很多不足,这是很珍贵的,只有发
现不足才可以弥补。
我经常看见有些园友看了一下某个框架的配置文件,在试验的时候能够让框架运行输出自己想要的结果,然后就说掌握了这个框架,这个框架有多么的简单,等等,我都会笑一笑,继续其他的事情。