NHibernate.Search 基于Lucene.NET的全文索引
NHibernate.Search現(xiàn)在是NHiberante Contrilb下面的一個(gè)還沒有發(fā)布的項(xiàng)目,也是從Hibernate.Search移植而來,把NHibernate和Lucene.NET結(jié)合在一起,ORM持久化對(duì)象到數(shù)據(jù)庫中,Lucene.NET提供索引及查詢支持.
下面在實(shí)際使用一下NHibernate.Search的使用:
由于這個(gè)項(xiàng)目還沒有發(fā)布,它的很多特性也是一直在變化,所以現(xiàn)在只是以我下載的版本為準(zhǔn),如果你想嘗試此項(xiàng)目,請(qǐng)下載最下面的代碼,里面包括自己編譯生成的NHibernate.Search及最新的Lucene.net相關(guān)的dll.
一.配置
1.修改你的NHibernate配置信息的地方,同樣添加NHibernate.Search的配置信息.
<configSections> <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/> <section name="nhs-configuration" type="NHibernate.Search.Cfg.ConfigurationSectionHandler, NHibernate.Search"
requirePermission="false" /> <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup,
System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> ..... </configSections>
需要注意的是,在NHibernate.Search之前的版本中,曾經(jīng)NHibernate.Search的配置信息和NHIbernate的放在一起.接下來,我們來看下具體的配置塊:
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2"> <bytecode-provider type="lcg"/> <reflection-optimizer use="true"/> <session-factory name="NHibernateSearch.Demo"> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider, NHibernate</property> <property name="connection.connection_string"> Data Source=|DataDirectory|Demo.db3;Version=3;Compress=False;synchronous=OFF; </property> <property name="show_sql">true</property> <property name="dialect">NHibernate.Dialect.SQLiteDialect</property> <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property> <property name="prepare_sql">true</property> <property name="cache.provider_class">NHibernate.Cache.HashtableCacheProvider, NHibernate</property> <property name="cache.use_query_cache">true</property> <mapping assembly="NHibernateSearch.Demo.Model"/> </session-factory> </hibernate-configuration> <nhs-configuration xmlns='urn:nhs-configuration-1.0'> <search-factory sessionFactoryName="NHibernateSearch.Demo"> <property name='hibernate.search.default.directory_provider'>NHibernate.Search.Store.FSDirectoryProvider,
NHibernate.Search</property> <property name='hibernate.search.default.indexBase'>~/Index</property> <property name='hibernate.search.default.indexBase.create'>true</property> </search-factory> </nhs-configuration>
上面的是NHibernate的配置信息,由于我在示例程序中使用的是SQLite數(shù)據(jù)庫,所以這個(gè)Demo也是一個(gè)SQLite+NHibernate的案例,而且里注意SQLite的連接字符串Data Source=|DataDirectory|Demo.db3,這樣的話,只要把數(shù)據(jù)文件放在App_Data下面就可以運(yùn)行了,而不用再去填寫數(shù)據(jù)庫文件的絕對(duì)路徑.
下面是NHibernate.Search的配置,我們采用基于文件目錄的全文檢索,索引文件放在根目錄下面的Index文件夾下面.
另外,我們?cè)O(shè)置一下NHibernate的事件監(jiān)聽(如果不我們?cè)O(shè)置的話,我們要手動(dòng)去調(diào)用,才能夠使NHibernate在持久化對(duì)象時(shí),同時(shí)處理全文索引),現(xiàn)在這個(gè)事件配置還不支持直接在NHibernate這樣配置:
<listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-insert'/>
<listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-update'/>
<listener class='NHibernate.Search.Event.FullTextIndexEventListener, NHibernate.Search' type='post-delete'/>
現(xiàn)在我們只能在創(chuàng)建SessionFactory前,手動(dòng)添加這個(gè)配置信息:
Configuration configuration = new Configuration(); configuration.SetListener(NHibernate.Event.ListenerType.PostUpdate, new FullTextIndexEventListener()); configuration.SetListener(NHibernate.Event.ListenerType.PostInsert, new FullTextIndexEventListener()); configuration.SetListener(NHibernate.Event.ListenerType.PostDelete, new FullTextIndexEventListener()); configuration.Configure(); sessionFactory= configuration.BuildSessionFactory();
我們?yōu)楦?刪除,添加都配置了全文索引的事件監(jiān)聽,這樣就能夠保證索引文件里的數(shù)據(jù)和實(shí)際數(shù)據(jù)庫里的保持一致,不要擔(dān)心,這的性能也有考慮,這里可以支持最大提交數(shù)量,而不一定非要每條操作都去更改索引文件.
二.使用
首先我們要在NHibernate實(shí)體對(duì)象這里添加一些NHibernate.Search的一些關(guān)于全文索引的屬性聲明.不知道這里以后會(huì)不會(huì)支持xml的配置而不是修改原來的對(duì)象代碼.
[Indexed(Index = "Book")] public class Book { [DocumentId] public virtual string BookID { get; set; } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Title { get; set; } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Authors { get; set; } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Publisher { get; set; } [Field(Index.Tokenized, Store = Store.Yes)] public virtual string Summary { get; set; } }
用過Lucene.Net的朋友們可能會(huì)發(fā)現(xiàn),其實(shí)這些標(biāo)識(shí),原來在不使用NHibernate時(shí)是直接針對(duì)字段的.而現(xiàn)在只是針對(duì)一個(gè)業(yè)務(wù)對(duì)象的屬性.這樣的話,但數(shù)據(jù)添加或者更改時(shí),就會(huì)自動(dòng)的進(jìn)行索引,但數(shù)據(jù)進(jìn)行刪除時(shí),也自動(dòng)更新索引,而可以不進(jìn)行人為的干預(yù).
上面是一個(gè)對(duì)象Book,其中包含名稱,作者,出版社,簡(jiǎn)介.我們要想實(shí)現(xiàn)對(duì)這幾個(gè)屬性進(jìn)行全文檢索的話,以前只能夠同時(shí)拼幾個(gè)LiKE,如果針對(duì)數(shù)據(jù)庫,數(shù)據(jù)庫數(shù)據(jù)的話肯定性能不會(huì)好,但是如果針對(duì)索引文件就不一樣了.首先我們看一下怎么來實(shí)現(xiàn)搜索:
public static IList<BookSearchResult> FindBooks(string query) { IList<BookSearchResult> results = new List<BookSearchResult>(); Analyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer(); MultiFieldQueryParser parser = new MultiFieldQueryParser(new string[] { "Title", "Summary", "Authors", "Publisher"
}, analyzer); Query queryObj; try { queryObj = parser.Parse(query); } catch (ParseException) { return results; } IFullTextSession session = Search.CreateFullTextSession(NHibernateHelper.GetCurrentSession());
///1 System.Type targetType = typeof(Book); IQuery nhQuery = session.CreateFullTextQuery(queryObj, new Type[] { targetType }); IList<Book> books = nhQuery.List<Book>(); NHibernate.Cfg.Configuration cf = new Configuration().Configure(); SearchFactoryImpl searchFactory = SearchFactoryImpl.GetSearchFactory(cf); IDirectoryProvider provider = searchFactory.GetDirectoryProviders(targetType)[0]; Workspace workspace = new Workspace(searchFactory); IndexReader indexReader = workspace.GetIndexReader(provider, targetType); Query simplifiedQuery = queryObj.Rewrite(indexReader); SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<b class='term'>", "</b>"); Highlighter hTitle = GetHighlighter(simplifiedQuery, formatter, "Title", 100); Highlighter hSummary = GetHighlighter(simplifiedQuery, formatter, "Summary", 200); Highlighter hAuthors = GetHighlighter(simplifiedQuery, formatter, "Authors", 100); Highlighter hPublisher = GetHighlighter(simplifiedQuery, formatter, "Publisher", 100); foreach (Book book in books) { BookSearchResult result = new BookSearchResult(book); TokenStream tsTitle = analyzer.TokenStream("Title", new System.IO.StringReader(book.Title ?? string.Empty)); result.HighlightedTitle = hTitle.GetBestFragment(tsTitle, book.Title); TokenStream tsAuthors = analyzer.TokenStream("Authors", new System.IO.StringReader(book.Authors ?? string.Empty)); result.HighlightedAuthors = hAuthors.GetBestFragment(tsAuthors, book.Authors); TokenStream tsPublisher = analyzer.TokenStream("Publisher", new System.IO.StringReader(book.Publisher ??
string.Empty)); result.HighlightedPublisher = hPublisher.GetBestFragment(tsPublisher, book.Publisher); TokenStream tsSummary = analyzer.TokenStream("Summary", new System.IO.StringReader(book.Summary ??
string.Empty)); result.HighlightedSummary = hSummary.GetBestFragments(tsSummary, book.Summary, 3, " ... <br /><br /> ... "); results.Add(result); } return results; }
相信使用過Lucene.Net的朋友對(duì)上面的代碼并不難理解,所有使用IFullTextSession的操作,都會(huì)進(jìn)行全文索引的處理.另外這里還有多字段解析和分詞的技術(shù),就不詳細(xì)介紹了.上面還使用了對(duì)查詢關(guān)鍵字進(jìn)行高亮顯示,其中的BookSearchResult實(shí)體也只是對(duì)Book進(jìn)行了包裝,進(jìn)行了顯示的一些處理.具體請(qǐng)查看源代碼.
你可以在上面注釋的///1處,添加對(duì)Book的一些操作,就可以顯示的查看索引文件是否也同時(shí)進(jìn)行了更新了.
二.結(jié)果
下載直接運(yùn)行整個(gè)項(xiàng)目,輸入”程序”關(guān)鍵字,你會(huì)發(fā)現(xiàn),在很短時(shí)間內(nèi),列出來了符合的記錄,并黑色顯示匹配的字(至于與不進(jìn)行索引的搜索性能對(duì)比,留給以后再做吧):
三.資料及參考
1.NHibernate.Search using Lucene.NET Full Text Index http://blogs.intesoft.net/post/2008/03/NHibernateSearch-using-Lucene-NET-Full-Text-Index-Part1.aspx
2.NHibernate Search http://darioquintana.com.ar/blogging/?p=21
3.Lucene.NET and NHibernate.Search on medium trust http://www.klopfenstein.net/lorenz.aspx/lucene-net-and-nhibernate-search-on-medium-trust
4.Using NHibernate.Search with ActiveRecord http://using.castleproject.org/display/AR/Using+NHibernate.Search+with+ActiveRecord
本次項(xiàng)目文件下載(NHibernate+SQLite+Lucene.Net).(for Vs 2008)
作者:孤獨(dú)俠客(似水流年)
出處:http://lonely7345.cnblogs.com
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

浙公網(wǎng)安備 33010602011771號(hào)