1. 程式人生 > >Lucene檢索與關鍵字Like 效能對比

Lucene檢索與關鍵字Like 效能對比

日常開發中,相信大家經常會用like去匹配一些資料,同時我們也知道,like往往會導致全表掃描,當資料量越來越大的時候,我們會糾結於

資料庫的龜速查詢,此時我們必須另尋蹊蹺,這時lucene就可以大顯身手了。

     首先我們做一個demo,向資料庫中插入10w條資料,總共778M。

接下來,我們搜尋下新聞內容中包含“流行”的記錄。

檢索一下要78s,是誰都要砸了面前的破機子。

複製程式碼
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using Lucene.Net.Index;
6 using Lucene.Net.Store; 7 using Lucene.Net.Analysis.Standard; 8 using Lucene.Net.Documents; 9 using System.Data; 10 using System.Diagnostics; 11 using Lucene.Net.Search; 12 13 using Lucene.Net.QueryParsers; 14 15 namespace First 16 { 17 class Program 18 { 19 static string path = @"
D:\Sample"; 20 21 static void Main(string[] args) 22 { 23 //建立索引 24 CreateIndex(); 25 26 var watch = Stopwatch.StartNew(); 27 28 //搜尋 29 IndexSearcher search = new IndexSearcher(path); 30 31 //查詢表示式 32 QueryParser query = new
QueryParser(string.Empty, new StandardAnalyzer()); 33 34 //query.parse:注入查詢條件 35 var hits = search.Search(query.Parse("Content:流行")); 36 37 for (int i = 0; i < hits.Length(); i++) 38 { 39 Console.WriteLine("當前內容:{0}", hits.Doc(i).Get("Content").Substring(0, 20) + "..."); 40 } 41 42 watch.Stop(); 43 44 Console.WriteLine("搜尋耗費時間:{0}", watch.ElapsedMilliseconds); 45 } 46 47 static void CreateIndex() 48 { 49 //建立索引庫目錄 50 var directory = FSDirectory.GetDirectory(path, true); 51 52 //建立一個索引,採用StandardAnalyzer對句子進行分詞 53 IndexWriter indexWriter = new IndexWriter(directory, new StandardAnalyzer()); 54 55 var reader = DbHelperSQL.ExecuteReader("select * from News"); 56 57 while (reader.Read()) 58 { 59 //域的集合:文件,類似於表的行 60 Document doc = new Document(); 61 62 //要索引的欄位 63 doc.Add(new Field("ID", reader["ID"].ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED)); 64 doc.Add(new Field("Title", reader["Title"].ToString(), Field.Store.NO, Field.Index.ANALYZED)); 65 doc.Add(new Field("Content", reader["Content"].ToString(), Field.Store.YES, Field.Index.ANALYZED)); 66 67 indexWriter.AddDocument(doc); 68 } 69 70 reader.Close(); 71 72 //對索引檔案進行優化 73 indexWriter.Optimize(); 74 75 indexWriter.Close(); 76 } 77 } 78 }
複製程式碼

448ms,頓時78s黯然失色,當然這個時間是不包含"建立索引“的時間,從時間複雜度上來說,這種預載入索引算是常量。

作為入門,簡單的介紹下lucene的實現過程,首先lucene主要分成兩步:"索引"和"搜尋"。

一:索引:

相信大家對索引還是比較熟悉的,lucene能夠將我們內容切分成很多詞,然後將詞作為key,建立“倒排索引”,然後放到索引庫中,在上面

的例子中,我們看到了索引過程中使用到了IndexWriter,FSDirectory,StandardAnalyzer,Document和Field這些類,下面簡要分析下。

1:IndexWriter

    我們看到該類有一個AddDocument方法,所以我們認為該類實現了索引的寫入操作。

2:FSDirectory

    這個就更簡單了,提供了索引庫的存放位置,比如我們這裡的D:\Sample,或許有人問,能不能存放在記憶體中,在強大的lucene面前當然

可以做到,lucene中的RAMDirectory就可以實現,當然我們的記憶體足夠大的話,還是可以用記憶體承載索引庫,進而提高搜尋的效率。

3:StandardAnalyzer

   這個算是索引過程中最最關鍵的一步,也是我們使用lucene非常慎重考慮的東西,之所以我們能搜尋秒殺,關鍵在於我們如何將輸入的內容

進行何種形式的切分,當然不同的切分形式誕生了不同的分析器,StandardAnalyzer就是一個按照單字分詞的一種分析器,詳細的介紹後續文

章分享。

4:Document

 在上面的例子可以看到,他是承載field的集合,然後新增到IndexWriter中,有點類似表中的行的概念。

5: Field

提供了對要分析的欄位進行何種處理,以KV形式呈現。

①:Field.Store.YES, Field.Index.NOT_ANALYZED   表示對索引欄位採取:原樣儲存並且不被StandardAnalyzer進行切分。

②: Field.Store.NO, Field.Index.ANALYZED             不儲存但是要被StandardAnalyzer切分。

二:搜尋

這個比較容易,根據我們輸入的詞lucene能夠在索引庫中快速定位到我們要找的詞,同樣我們可以看到IndexSearcher,QueryParser,Hits。

1:IndexSearcher

   這個我們可以理解成以只讀的形式開啟由IndexWriter建立的索引庫,search給QueryParser提供了查詢的橋樑。

2:QueryParser

   這玩意提供了一個parse方法能夠將我們要查詢的詞轉化為lucene能夠理解了查詢表示式。

3:Hits

   這個就是獲取匹配結果的一個指標,優點類似C#中的延遲載入,目的都是一樣,提高效能。