北京好奇怪,晝夜溫差很大,有點(diǎn)像月球。早起時(shí)窗上的冰霜很厚實(shí),但到了白天陽光很足,風(fēng)力很小,氣溫很好。大連現(xiàn)在確在降溫,零下十幾度,比較罕見。可能是我離開她一會,她卻變冷了。呵呵~~
今日上午把lucene的高級部分給結(jié)束了。下午搞了一下Compass,Compass是對lucene的封閉。因?yàn)?/span>lucene使用起來有些麻煩。
一、lucene高級
1.分詞器
一般的分詞器流程:
1) 輸入文本:輸入查詢的內(nèi)容。
2) 關(guān)鍵詞切分:使用分詞器取出關(guān)鍵詞。
3) 去除停用詞:去除沒有多大意義的詞,比如a,an,the,的,呢,吧。
4) 形態(tài)還原:將詞的某種形態(tài)還原為原形,比如英文復(fù)數(shù)形式恢復(fù)到單數(shù)形式。
5) 轉(zhuǎn)為小寫:將英文轉(zhuǎn)為小寫,不區(qū)分大小寫。
Lucene中的分詞器
1) 單字分詞:對應(yīng)的類ChineseAnalyzer,將輸入的字符串中的每個(gè)字做為關(guān)鍵字。比如“中國人加油!”,會被切分為“中”、“國”、“人”、“加”、“油”。(標(biāo)點(diǎn)符號屬于停用詞)
2) 二分法分詞:對應(yīng)的類CJKAnalyzer,將輸入的字符串以二分法分詞。比如“中國人加油!”,會被切分為“中國”、“國人”、“人加”、“加油”這四個(gè)關(guān)鍵字。(標(biāo)點(diǎn)符號屬于停用詞)
3) 詞庫分詞:對應(yīng)的類MMAnalyzer,最為常用的分詞器。比如“中國人加油!”,會被切分為“中國人”、“加油”。(標(biāo)點(diǎn)符號屬于停用詞)
示例:
package cn.itcast.cc.anayzler; import java.io.IOException; import java.io.StringReader; import jeasy.analysis.MMAnalyzer; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.Token; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.cjk.CJKAnalyzer; import org.apache.lucene.analysis.cn.ChineseAnalyzer; import org.junit.Test; public class AnalyzerTest { Analyzer anaylzer1 = new ChineseAnalyzer();// 單字分詞 Analyzer anaylzer2 = new CJKAnalyzer();// 二分分詞法 Analyzer anaylzer3 = new MMAnalyzer();// 詞庫分詞 @Test public void test() throws IOException { String str = "中國人加油!"; printAnalyzer(anaylzer1, str); printAnalyzer(anaylzer2, str); printAnalyzer(anaylzer3, str); } private void printAnalyzer(Analyzer analyzer, String str) throws IOException { TokenStream tokenStream = analyzer.tokenStream("text", new StringReader( str)); System.out.println("*****分詞器->" + analyzer.getClass().getName() + ",將'" + str + "'切分為:"); Token token = new Token(); while ((token = tokenStream.next(token)) != null) { System.out.println(token); } } } |
2.高亮
Lucene的高亮器(Highlighter類)可以實(shí)現(xiàn)lucene的關(guān)鍵字高亮:
package cn.itcast.cc.highlighter; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.document.*; import org.apache.lucene.document.Field.*; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriter.MaxFieldLength; import org.apache.lucene.queryParser.*; import org.apache.lucene.search.*; import org.apache.lucene.search.highlight.*; import org.apache.lucene.search.highlight.Scorer; import org.junit.Test; import jeasy.analysis.MMAnalyzer; public class HighLighterTesst { private String path = "./index/";// lucene的索引數(shù)據(jù)被保存在這個(gè)目錄中 private Analyzer analyzer = new MMAnalyzer();// 詞庫分詞器 @Test public void test() { try { // 創(chuàng)建索引數(shù)據(jù) IndexWriter indexWriter = new IndexWriter(this.path, this.analyzer, MaxFieldLength.LIMITED); Document doc = new Document(); doc.add(new Field("content", "中國人民加油!", Store.YES, Index.ANALYZED)); indexWriter.addDocument(doc); indexWriter.close(); // 查詢數(shù)據(jù) IndexSearcher indexSearcher = new IndexSearcher(this.path); QueryParser queryParser = new MultiFieldQueryParser( new String[] { "content" }, this.analyzer); Query query = queryParser.parse("加油"); TopDocs topDocs = indexSearcher.search(query, null, 10); // 創(chuàng)建高亮 // SimpleHTMLFormatter的默認(rèn)值為"<a></a>" Formatter formatter = new SimpleHTMLFormatter("<span>", "</span>"); Scorer scorer = new QueryScorer(query); Highlighter highlighter = new Highlighter(formatter, scorer); // 打印結(jié)果 for (ScoreDoc scoreDoc : topDocs.scoreDocs) { // 取出查詢結(jié)果 Document searchdoc = indexSearcher.doc(scoreDoc.doc); String searchstr = searchdoc.getField("content").stringValue(); // 添加高亮 String histr = highlighter.getBestFragment(this.analyzer, "content", searchstr); System.out.println(histr); } indexSearcher.close(); } catch (Exception e) { e.printStackTrace(); } } } |
3.排序(默認(rèn)相關(guān)度排序)
a) 實(shí)驗(yàn)相關(guān)度排序,得分是在搜索時(shí)算出來的。
b) 影響區(qū)域
i. 整個(gè)文檔
ii. 某個(gè)字段
1. 建立索引時(shí),影響它的排名,創(chuàng)建QueryParser時(shí)指定“MultiFieldQueryParser(String[] fields, Analyzer analyzer, Map boosts)”中第三個(gè)參數(shù)為“new HashMap<String, Float>().put(String fieldname, float fraction)”提升對應(yīng)字段內(nèi)容的排名。一般網(wǎng)站內(nèi)部搜索會將標(biāo)題部分的內(nèi)容提升,以至于標(biāo)題內(nèi)容的排名大于帖子內(nèi)容或回復(fù)的排名。
2. 搜索時(shí),標(biāo)題與內(nèi)容的含量排名,TopDoc有一個(gè)score屬性,它是根據(jù)文檔中關(guān)鍵字的數(shù)量,記錄文檔的得分。
c) 按指定的字段進(jìn)行排序,就是在搜索時(shí),指定的字段。
d) Sort排序器,由類Sort實(shí)現(xiàn)。
Sort sort = new Sort(); sort.setSort(SortField field); indexSearcher.search(query, null, 100, sort); |
4.過濾器
在查詢時(shí)添加一個(gè)過濾器,過濾掉查詢后不想要的內(nèi)容,由Filter接口實(shí)現(xiàn)。
String lower = NumberTools.longToString(3); String upper = NumberTools.longToString(6); Filter filter = new RangeFilter("id", lower, upper, true, false); indexSearcher.search(query, filter, 100); |
在lucene中使用數(shù)值、日期數(shù)據(jù)時(shí),必須使用NumberTools和DateTools。前后必須統(tǒng)一,比如使用longToString將Long轉(zhuǎn)換為String,那么也必須使用stringToLong將String轉(zhuǎn)換為Long。
5.搜索,Query的子類對應(yīng)各種查詢:
1) TermQuery,關(guān)鍵詞查詢:
Term term = new Term("context", "加油"); Query query = new TermQuery(term); indexSearcher.search(query, null, 100); |
2) RangeQuery,范圍查詢:
Term lower = new Term("content", NumberTools.longToString(3)); Term upper = new Term("content", NumberTools.longToString(10)); Query query = new RangeQuery(lower, upper, false/*包含邊界*/); indexSearcher.search(query, null, 100); |
3) WildcardQuery,通配符查詢:
Term term = new Term("context", "加?");//?匹配任意一個(gè)字符,*代表任意多個(gè)字符。 Query query = new TermQuery(term); indexSearcher.search(query, null, 100); indexSearcher.search(query, null, 100); |
4) PhraseQuery,短語查詢:
PhraseQuery phraseQuery = new PhraseQuery(); phraseQuery.add(new Term("context", "中國人民")); phraseQuery.add(new Term("context", "加油")); phraseQuery.setSlop(5); // 指定關(guān)鍵詞之間間隔的字符的最大數(shù)量 indexSearcher.search(query, null, 100); |
5) BooleanQuery,布爾查詢:
Query query1 = new TermQuery(new Term("context", "中國人民")); Query query2 = new TermQuery(new Term("context", "加油")); BooleanQuery boolQuery = new BooleanQuery(); boolQuery.add(query1, Occur.MUST); boolQuery.add(query2, Occur.SHOULD);//Occur的常量值:MUST、SHOULD、MUST_NOT。 indexSearcher.search(query, null, 100); |
注意:經(jīng)過分詞器的所有字母,無論是添加索引還是查詢,都會被轉(zhuǎn)換為小寫的。但上邊這些查詢類沒有經(jīng)過分詞器,如果查詢關(guān)鍵里有大寫字母,將查詢不到匹配的結(jié)果。所以在使用上邊這些查詢類時(shí),查詢文本中的字母全部為小寫。我們之前使用的查詢是通過QueryParser切分出查詢關(guān)鍵字,所以使用QueryParser可以不注意大小寫問題。
二、Compass
Compass是lucene的框架,它與hibernate極其相似(但不具有hibernate那些高級功能,比如緩存技術(shù))。湯兄弟做的好,因?yàn)閷W(xué)習(xí)lucene之前的課程正是hibernate,他將hibernate與compass對比了一下,使我們學(xué)習(xí)compass更加容易了。OK,我總結(jié)一下。
1.hibernate與compass
![]() |
![]() |
| hibernate | compass |
配置方式 | 1.編程方式: Configuation cfg = new Configu...(); cfg.set...(); ... 2.配置文件: //默認(rèn)配置,文件名為“hibernate.cfg.xml” Configuation cfg= new Configu...(); //指定文件名(文件名可變更) //cfg.configure("hibernate.cfg.xml"); | 1.編程方式: CompassConfiguation cfg = new CompassConf...(); cfg.set("key","value"); ... 2.配置文件 //默認(rèn)配置,文件名為“compass.cfg.xml” cfg.configure(); //指定文件名(文件名可變更) cfg.configure("hibernate.cfg.xml"); |
配置文件 | XML文件 注解 | XML文件 注解 |
2.compass中的注解配置
package cn.itcast.cc.compass; import org.compass.annotations.Index; import org.compass.annotations.Searchable; import org.compass.annotations.SearchableId; import org.compass.annotations.SearchableProperty; import org.compass.annotations.Store; @Searchable public class Article { private Long id; private String title; private String content; @SearchableId public Long getId() { return id;} @SearchableProperty(store = Store.YES, index = Index.ANALYZED, boost = public String getTitle() {return title;} @SearchableProperty(store = Store.YES, index = Index.ANALYZED) public String getContent() {return content;} public void setId(Long id) {this.id = id;} public void setTitle(String title) {this.title = title;} public void setContent(String content) {this.content = content;} } |
XML配置文件,可以查看“compass-
3.compassAPI
CompassConfiguration cfg = new CompassConfiguration(); cfg.setConnection("./indexPath/");// 連接信息 cfg.addClass(Article.class);// 聲明映射信息 Compass compassSessionFactory = cfg.buildCompass(); CompassTransaction tx = session.beginTransaction(); session.create(article); tx.commit(); session.close(); |
其他API:
session.find(String arg0); session.save(Object arg0); session.delete(Class arg0, Object arg1); |
這兩天的課程相對比較容易些,雖然容易但仍然需要一定的練習(xí)。后天就要學(xué)習(xí)jbpm與OA項(xiàng)目了,終于開始第一個(gè)像樣的項(xiàng)目了,呵呵!不過感覺并沒想像中的那么復(fù)雜,因?yàn)橛辛?/span>jbpm。