1.随着網站資料量達到500萬條的時候,發現SQL資料庫如果使用LIKE語句來查詢,總是占用CPU很忙,不管怎麼優化,速度還是上不來;
2.經過網上收集資料,HUBBLE.net目前雖然做得不錯,但需要配置記憶體給他,由于伺服器4G記憶體,而且運作了好幾個網站,是以考慮采用Lucene.net來做為搜尋引擎;
3.雖然本地測試沒有問題,但是部署到64位的伺服器上還是經過了好幾天的折騰,在此都記錄一下.
在此記錄搜片神器的整個開發過程中遇到的問題和相關的解決方案,希望大家一起交流.
在此記錄搜片神器的整個開發過程中遇到的問題和相關的解決方案,希望大家一起交流.
Lucene軟體下載下傳編譯整合的問題
網站采用了最新Lucene.Net.3.0.3版本的代碼,然後配置盤古分詞來進行.
由于Lucene.Net更新到了3.0.3後接口發生了很大變化,原來好多分詞庫都不能用了,
.Net下還有一個盤古分詞(http://pangusegment.codeplex.com/),但也不支援Lucene.Net 3.0.3,園子裡的大哥們修改的項目位址:
https://github.com/JimLiu/Lucene.Net.Analysis.PanGu
下載下傳後裡面有DEMO代碼進行整合.
Lucene在軟體中內建處理
由于實時處理資料程式是WINFORM程式,是以需要采用軟體代碼來實時更新索引資料,這樣可控性高一些.
引用頭檔案
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Lucene.Net.Util;
using PanGu;
using Lucene.Net.Analysis.PanGu;
using PanGu.HighLight;
using FSDirectory = Lucene.Net.Store.FSDirectory;
using Version = Lucene.Net.Util.Version;
建立索引
public static class H31Index
{
private static Analyzer analyzer = new PanGuAnalyzer(); //MMSegAnalyzer //StandardAnalyzer
private static int ONEPAGENUM = 200;
private static string m_indexPath = "";
private static IndexWriter iw = null;
public static void Init(string indexpath)
{
m_indexPath = indexpath;
}
public static bool OpenIndex()
{
try
{
DirectoryInfo INDEX_DIR = new DirectoryInfo(m_indexPath+"//Index");
bool iscreate = true;
if (INDEX_DIR.Exists)
iscreate = false;
Int32 time21 = System.Environment.TickCount;
if (iw == null)
{
iw = new IndexWriter(FSDirectory.Open(INDEX_DIR), analyzer, iscreate, new IndexWriter.MaxFieldLength(32));
Int32 time22 = System.Environment.TickCount;
H31Debug.PrintLn("IndexWriter2[" + type.ToString() + "]:" + " IndexWriter:" + (time22 - time21).ToString() + "ms");
return true;
}
}
catch (System.Exception ex)
{
H31Debug.PrintLn("OpenIndex" + ex.Message);
}
return false;
}
public static void CloseIndex()
{
try
{
if (iw != null)
{
//if (count > 0)
{
iw.Commit();
iw.Optimize();
}
iw.Dispose();
iw = null;
}
}
catch (System.Exception ex)
{
H31Debug.PrintLn("CloseIndex" + ex.Message);
}
}
//建立索引
public static int AddIndexFromDB()
{
int res = 0;
int count = 0;
try
{
Int32 time0 = System.Environment.TickCount;
while (count < OneTimeMax && iw != null)
{
Int32 time11 = System.Environment.TickCount;
DataSet ds = H31SQL.GetHashListFromDB(type, startnum, startnum + ONEPAGENUM - 1, NewOrUpdate);
Int32 time12 = System.Environment.TickCount;
int cnt = ds.Tables[0].Rows.Count;
if (ds != null&& cnt>0)
{
Int32 time1 = System.Environment.TickCount;
count = count + cnt;
for (int i = 0; i < cnt; i++)
{
//ID,hashKey,recvTime,updateTime,keyContent,keyType,recvTimes,fileCnt,filetotalSize,Detail,viewTimes,viewLevel
Document doc = new Document();
doc.Add(new Field("ID", ds.Tables[0].Rows[i]["ID"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,索引
doc.Add(new Field("hashKey", ds.Tables[0].Rows[i]["hashKey"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,索引
doc.Add(new Field("recvTime", ds.Tables[0].Rows[i]["recvTime"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("updateTime", ds.Tables[0].Rows[i]["updateTime"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,索引
doc.Add(new Field("keyContent", ds.Tables[0].Rows[i]["keyContent"].ToString(), Field.Store.YES, Field.Index.ANALYZED));//存儲,索引
//PanGuFenCiTest(ds.Tables[0].Rows[i]["keyContent"].ToString());
string typeid=ds.Tables[0].Rows[i]["keyType"].ToString();
if(typeid.Length<2)
typeid=type.ToString();
doc.Add(new Field("keyType", typeid, Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("recvTimes", ds.Tables[0].Rows[i]["recvTimes"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存儲,索引
doc.Add(new Field("fileCnt", ds.Tables[0].Rows[i]["fileCnt"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("filetotalSize", ds.Tables[0].Rows[i]["filetotalSize"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("Detail", ds.Tables[0].Rows[i]["Detail"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("viewTimes", ds.Tables[0].Rows[i]["viewTimes"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
doc.Add(new Field("viewLevel", ds.Tables[0].Rows[i]["viewLevel"].ToString(), Field.Store.YES, Field.Index.NO));//存儲,不索引
iw.AddDocument(doc);
}
ds = null;
Thread.Sleep(10);
}
else
{
res = 1;
break;
}
}
Int32 time10 = System.Environment.TickCount;
H31Debug.PrintLn("AddIndexFromDB[" + type.ToString() + "],Building index done:" + startnum.ToString() + " Time:" + (time10 - time0).ToString() + "ms");
}
catch (System.Exception ex)
{
H31Debug.PrintLn(ex.StackTrace);
}
return res;
}
建立索引代碼
查詢代碼
//網站搜尋代碼
public static void Search(string keyword,int typeid,int pageNo)
{
int onePage=20;//一頁多少
int TotalNum=1000;//一次加載多少
if (pageNo < 0) pageNo = 0;
if (pageNo * onePage > TotalNum)
pageNo = TotalNum / onePage;
//索引加載的目錄
DirectoryInfo INDEX_DIR = new DirectoryInfo(m_indexPath+"//Index//index1");
IndexSearcher searcher = new IndexSearcher(FSDirectory.Open(INDEX_DIR), true);
QueryParser qp = new QueryParser(Version.LUCENE_30, "keyContent", analyzer);
Query query = qp.Parse(keyword);
//Console.WriteLine("query> {0}", query);
//設定排序問題
Sort sort = new Sort(new SortField[]{new SortField("recvTimes", SortField.INT, true),new SortField("updateTime", SortField.STRING, true)});
//設定高亮顯示的問題
PanGu.HighLight.SimpleHTMLFormatter simpleHTMLFormatter = new PanGu.HighLight.SimpleHTMLFormatter("<font color=\"red\">", "</font>");
PanGu.HighLight.Highlighter highlighter =new PanGu.HighLight.Highlighter(simpleHTMLFormatter,new Segment());
highlighter.FragmentSize = 50;
TopFieldDocs tds = searcher.Search(query,null, 1000, sort);
Console.WriteLine("TotalHits: " + tds.TotalHits);
/* 計算顯示的條目 */
int count = tds.ScoreDocs.Length;
int start = (pageNo - 1) * onePage;
int end = pageNo * onePage > count ? count : pageNo * onePage;
//傳回集合清單
for (int i = start; i < end; i++)
{
Document doc = searcher.Doc(tds.ScoreDocs[i].Doc);
string contentResult = highlighter.GetBestFragment(keyword, doc.Get("keyContent").ToString());
Console.WriteLine(contentResult + ">>" + doc.Get("recvTimes") + "<<" + doc.Get("updateTime"));
}
searcher.Dispose();
}
伺服器部署的問題
當你覺得本地都運作的好好的時候,發現到伺服器上根本就運作不了,一直報錯.
由于Lucene.net最新版本直接使用了net4.0,伺服器是64們的WIN2003,而且運作的網站都還是32位的net2.0的DLL,是以更新到4.0怎麼也出不來
1.運作顯示的錯誤是提示沒有.net4.0的架構,需要注冊.net4.0
直接到網上找如何搞定顯示ASP.NET頁籤的問題,最後找到文章方法是:
停止iis直接删除C:/WINDOWS/system32/inetsrv/MetaBase.xml中的Enable32BitAppOnWin64="TRUE" 行
重新開機IIS後頁籤到是出來了,但net.2.0的網站全部挂掉,運作不起來,sosobta.com網站也運作不起來,
Enable32BitAppOnWin64的意思是允許運作32們的程式,是以此方法不行.
2.另外找的文章都是重新注冊net 4.0
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i
開始執行試了好多次,沒有效果,這裡也允許了,重新安裝了好幾次Net4.0.
3.最後一次在停止IIS後,再次全部注冊net2.0,4.0,然後
cscript %SYSTEMDRIVE%\inetpub\adminscripts\adsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1
重新開機IIS後,出現的錯誤終于不再是上面的.
新錯誤是:
Server Application Unavailable
4.通過網上查找資料
解決辦法: 在IIS中建立一個應用程式池,然後選中你的 基于.net
framework4.0的虛拟目錄,點“屬性”-》在“應用程式池” 中選擇剛才建立的的應用程式池,點選“确定”。
最後伺服器網站sosobt.com終于運作起來了.
Lucene.net搜尋的效果
1.經過目前測試,目前伺服器4G的記憶體搜尋速度比以前需要5S左右的LIKE強了很多倍,基本上都在1S以内;
2.由于Lucene索引是基于檔案的索引,進而使SQL資料庫的使用壓力減輕不少,這樣給其它程式的整體壓力減少不少,網站效果還行.
3.目前500萬的資料重建立立一次索引需要1小時左右,但是網站運作的時候去更新索引速度目前感覺比較慢.比如要更新點選次數和更新時間等時,發現新的問題來了,這塊的時間比較長.
4.目前考慮的方案是幾天一次全部重建立立索引一次,平時隻是添加資料.
希望有了解的朋友在此留言指教下lucene.net方面的性能優化問題,大家一起共同學習進步.
大家看累了,就移步到娛樂區http://www.sosobta.com 去看看速度如何,休息下...
希望大家多多推薦哦...大家的推薦才是下一篇介紹的動力...