最近因爲工做的須要, 要分析大量C#代碼, 在數萬個cs文件中搜索特定關鍵詞. 這是一項很是耗時的工做, 用Notepad++要運行接近半個小時. 因而我利用WEBUS2.0 SDK建立了一個代碼搜索器程序, 很是方便的完成了這項工做.html
Code Search程序首先會在選定的目錄中搜索全部cs文件:性能
private void btnOpen_Click(object sender, EventArgs e) { try { if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK) { Task.Factory.StartNew(IndexProc); //... }
而後建立IIndexer, 並在一個線程中爲全部找到的文件編制索引:優化
void IndexProc() { var files = Directory.GetFiles(folderBrowserDialog1.SelectedPath, "*.cs", SearchOption.AllDirectories); if (files != null && files.Length > 0) { //...this.ResetIndex(); foreach (var file in files) { Document doc = new Document(); doc.Fields.Add(new Field("FileName", file, FieldAttributes.None)); doc.Fields.Add(new Field("Code", StringHelper.LoadString(file), FieldAttributes.AnalyseIndex)); m_Index.Add(doc); //... } } //... } void ResetIndex() { if (m_Index != null) { m_Index.Close(); } m_Index = new IndexManager(new CodeAnalyzer()); m_Index.DumpDocs = 3000; m_Index.DumpSize = 10; m_Index.MinIndexSize = int.MaxValue; m_Index.MaxIndexSize = int.MaxValue; m_Index.MergeFactor = int.MaxValue; m_Index.New(AppDomain.CurrentDomain.BaseDirectory + @"\Index"); m_Searcher = new IndexSearcher(m_Index); }
經過調節DumpDocs和DumpSize, 能夠優化程序的內存佔用;ui
經過調節Min/MaxIndexSize和MergeFactor, 能夠優化程序的IO性能, 目前我設置的MinIndexSize最大意味着自始至終只會生成一個索引片斷; MergeFactor最大意味着從不合並索引片斷.this
在建立索引的時候, 咱們使用的是專門爲代碼分析設計的IAnalyzer:spa
class CodeAnalyzer : IAnalyzer { //...public ITokenStream GetTokenStream(Webus.Documents.Field field) { if (field.Name == "Code") { return this.GetTokenStream(field.Value.ToString()); } else { return null; } } } class CodeTokenStream : ITokenStream { HashSet<string> stops = new HashSet<string>(new string[] { "abstract", "event", "new", //... "enum", "namespace", "string" }); Queue<Token> m_Buffer = new Queue<Token>(); public CodeTokenStream(string text) { MatchCollection mc = Regex.Matches(text, @"\w+"); foreach (Match m in mc) { var key = m.Value.ToLower(); if (stops.Contains(key) == false) { m_Buffer.Enqueue(new Token(key, m.Index, m.Length)); } } } //...
}
這個分析器中包含了全部C#的關鍵詞, 因爲他們是絕對高頻詞而且沒有搜索的意義, 所以在分析的時候會跳過這些詞彙而不作任何處理. 線程
在編制索引的時候經過事件將狀態更新到UI上面:設計
private void frmCodeSearch_Load(object sender, EventArgs e) { try { this.StatusChanged += new StatusChangeEventHandler(frmCodeSearch_StatusChanged); //... } delegate void UpdateUI(); void frmCodeSearch_StatusChanged(object sender, string status) { this.Invoke(new UpdateUI(() => { this.txtStatus.Text = status; })); }
這裏是跨線程更新UI, 所以須要使用this.Invoke來封送相應操做. code
索引編制過程當中就能夠開始搜索了:orm
對應代碼以下:
private void txtKeyword_TextChanged(object sender, EventArgs e) { try { TermQuery query = new TermQuery(new Term("Code", txtKeyword.Text.ToLower())); var hits = m_Searcher.Search(query); List<SearchResult> result = new List<SearchResult>(); foreach (HitDoc hit in hits) { StandardHighlighter hl = new StandardHighlighter(hit); result.Add(new SearchResult(hit)); } dgvResult.DataSource = result; } catch (Exception ex) { MessageBox.Show(ExceptionHelper.ToString(ex)); } }
建立一個TermQuery對象, 對Code字段進行搜索, 構建List<SearchResult>類型的結果集, 而且綁定到DataGridView上面, 大功告成! enjoy~!
2013-7-21補充:
加強了搜索功能, 支持WEBUS2.0 SDK的查詢表達式, 可以完成各類複雜的搜索任務. 具體語法將在後面的文章中介紹.
2013-8-20補充:
Build - 選擇一個文件夾開始編制索引, 編好的索引自動保存在當前目錄的CodeSearch.Index子目錄下面. 好比咱們選擇C:\SourceCode來編制索引, 這索引數據會保存在C:\SourceCode\CodeSearch.Index中.
Open - 打開已經存在的索引, 即上面所說的CodeSearch.Index文件夾.
關閉程序時會自動關閉當前索引. 索引關閉後所有數據都保存到磁盤上, 下次能夠直接打開來繼續使用.