轉(zhuǎn)載:
張馳有道 http://www.jinsehupan.com/blog/?p=25
多謝他的介紹。
1、開篇語
2、概述
3、淵源
4、初識Solr
5、Solr的安裝
6、Solr分詞順序
7、Solr中文應(yīng)用的一個實例
8、Solr的檢索運算符
[開篇語]按照慣例應(yīng)該寫一篇技術(shù)文章了,這次結(jié)合Lucene/Solr來分享一下開發(fā)經(jīng)驗。
Lucene是一個使用Java語言寫的全文檢索開發(fā)包(API),利用它可以實現(xiàn)強大的檢索功能,它的詳細(xì)介紹大家可以去Google上搜索一下,本文重點放在Solr相關(guān)的討論上。
[概述]目前國內(nèi)研究Solr的人不多,而且大多是因為項目開發(fā)需要。Solr師承Lucene,為Apache基金會下的一個項目,具體的說它還是Lucene下的一個子項目。Solr出身豪門,而且具有自己的技術(shù)特點,填補了以往Lucene僅僅作為開發(fā)工具包的遺憾,它是一個完完整整地應(yīng)用。換句話說,它是一個全文檢索服務(wù)器,它開箱即用,讓我們能立馬體會到Lucene的強大功能,為Lucene產(chǎn)品化走出了一大步。

Solr分詞原理演示界面
[淵源]最初,CNET Networks使用Lucene API來開發(fā)了一些應(yīng)用,并在這個基礎(chǔ)上產(chǎn)生了Solr的雛形,后來Apache Software Foundation在Lucene頂級項目的支持下得到了Solr,這已經(jīng)是2006年1月份的事了。2006年1月17日,Solr正是加入Apache基金會的孵化項目,在整個項目孵化期間,Solr 穩(wěn)步地積累各種特性并吸引了一個穩(wěn)定的user群體、developer群體和Committer群體,并于1年之后的17日正式醞釀成熟,在這之前已經(jīng)成功發(fā)布了1.1.0版。目前的穩(wěn)定版本是1.2,Solr在9月份的2007Apache年會上大放異彩,在今年11月底將來到香港參加2007亞洲開源軟件峰會,遺憾的是為什么不來北京:-(
[初識Solr]Solr服務(wù)器不同于普通的關(guān)系型數(shù)據(jù)庫,不僅僅在于它核心本質(zhì)的不同(面向結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)的不同),很大的不同還在于它的體系架構(gòu)上。Solr服務(wù)器一般情況下需要部署于應(yīng)用服務(wù)器/Java容器上(如果是本機通信不涉及RPC可以不使用Java容器,如采用嵌入方式使用Solr),無法獨立工作于JVM上。

Solr架構(gòu)圖
Solr服務(wù)器可以存儲數(shù)據(jù)并通過索引對其進行快速高效檢索。對外提供HTTP/XML和Json API接口,這使得它能夠在多語言環(huán)境下集成,比如針對它的客戶端的開發(fā)。Solr目前的客戶端面向的有Java、PHP、Python、C#、Json和Ruby等,遺憾的是沒有面向C/C++(這也是本人目前在研究的),研究音樂搜索分類的Brian Whitman曾在蘋果平臺上使用JNI技術(shù)在C代碼中嵌入Solr實現(xiàn)檢索,不過是一個Cocoa工程。有了這些客戶端,使用者能很方便地將Solr集成到具體運用中。目前最完善的當(dāng)屬Java客戶端Solrj,以及加入到Solr trunk,并將在1.3版本中正式發(fā)布。
如果不研究開發(fā)Solr,只是使用Solr,只需要關(guān)注Solr的以下幾個方面:
1、Solr服務(wù)器的配置在solrconfig.xml中完成,包括對緩存,servlet的個性化配置等等,即系統(tǒng)全局的配置;
2、索引方法、索引域(字段)等等在schema.xml中完成,這個配置是針對Solr實例的;
3、索引數(shù)據(jù)文件默認(rèn)放在Solr文檔根目錄下的data/index目錄下,這個路徑可以通過第1點配置,同時可以將這個目錄下的文件進行復(fù)制粘貼,即可完成索引的復(fù)用;
4、建立索引的時間相當(dāng)長,我采用按詞無字典索引方式對2G110萬條中文記錄進行索引,花了將近2個半小時的時間(當(dāng)然這個時間和很多因素有關(guān),有興趣的話大家可以留言和我討論),相對而言,在linux下建索引時間要比windows下快很多,可以使用commit操作使新增索引生效,同時注意索引的優(yōu)化,索引優(yōu)化也是很費資源和時間的,但是優(yōu)化索引也是提高檢索速度的重要方法,因此需要好好權(quán)衡這一點;
5、安裝完后的Solr目錄下有這么幾個文件夾:bin文件夾里主要是用于建立鏡像和完成遠程同步的腳本;conf文件夾下主要是1、2點中提到的配置文件;admin文件夾下是的主要是提供web管理界面的文件;
6、目前Solr1.2不具備安全性設(shè)計,沒有用戶組及權(quán)限設(shè)置,在進行具體應(yīng)用時需要注意安全,目前最有效的方法是通過應(yīng)用服務(wù)器上的授權(quán)實現(xiàn)。
本文永久鏈接:http://www.jinsehupan.com/blog/?p=25
[Solr的安裝]Solr發(fā)行版中已經(jīng)有一個使用Jetty為servlet容器的小例子,可以使用這個例子來體驗,那正在在自己想部署的平臺和應(yīng)用服務(wù)器上該怎么一個步驟呢?
要開始使用 Solr,需安裝以下軟件:
1、Java 1.5 或更高版本;
2、Ant 1.6.x 或更高版本(用于編譯管理Solr工程,個人推薦,當(dāng)然可以使用eclipse);
3、Web 瀏覽器,用來查看管理頁面(官方建議使用Firefox,但實際沒有發(fā)現(xiàn)和IE有什么差別);
4、servlet 容器,如Tomcat 5.5(不建議使用6版本)。本文以Tomcat 在 8080 端口上運行為例。如果運行的是其他 servlet 容器或在其他的端口上運行,則可能要修改代碼中的URL才能訪問示例應(yīng)用程序和 Solr。
下面開始安裝配置:
1、使用Ant編譯工程或下載示例應(yīng)用程序,將Solr WAR 文件復(fù)制到 servlet 容器的webapps目錄中;
2、得到Solr文件夾,以備隨后將其復(fù)制到當(dāng)前目錄,可以使用ant build得到,也可以在下載的壓縮包中找到,以它為模板以備之后的修改;
3、可以通過以下三種方式之一設(shè)置 Solr 的主位置:
設(shè)置 java 系統(tǒng)屬性 solr.solr.home (沒錯,就是 solr.solr.home,一般在嵌入式集成中用得多);
配置 java:comp/env/solr/home 的一個 JNDI 查找指向 solr 目錄,建立/tomcat55/conf/Catalina/localhost/solr.xml文件,注意這個xml文件名將是Solr實例名稱,2中的當(dāng)前目錄被指定為下面中的f:/solrhome,文件內(nèi)容如下:
- <context docBase="f:/solr.war" debug="0" crossContext="true" >
- <environment name="solr/home" type="java.lang.String" value="f:/solrhome" override="true" />
- </context>
在包含 solr 目錄的目錄中啟動 servlet 容器(默認(rèn)的 Solr 主目錄是當(dāng)前工作目錄下的 solr);
4、最后一點就是如果有CJK(中日韓文字)應(yīng)用,出現(xiàn)亂碼問題,采用如下方法解決(其實已經(jīng)不算是solr配置問題,而是應(yīng)用服務(wù)器配置問題),修改Tomcat的conf/server.xml文件中對于端口(本文為8080)的連接器統(tǒng)一資源編碼為UTF-8,因為Solr1.2內(nèi)核支持UTF-8編碼:
- <server ...>
- <service ...>
- <connector ... URIEncoding="UTF-8"/>
- ...
- </service>
- </server>
[Solr分詞順序]Solr建立索引和對關(guān)鍵詞進行查詢都得對字串進行分詞,在向索引庫中添加全文檢索類型的索引的時候,Solr會首先用空格進行分詞,然后把分詞結(jié)果依次使用指定的過濾器進行過濾,最后剩下的結(jié)果才會加入到索引庫中以備查詢。分詞的順序如下:
索引
1:空格whitespaceTokenize
2:過濾詞StopFilter
3:拆字WordDelimiterFilter
4:小寫過濾LowerCaseFilter
5:英文相近詞EnglishPorterFilter
6:去除重復(fù)詞RemoveDuplicatesTokenFilter
查詢
1:查詢相近詞
2:過濾詞
3:拆字
4:小寫過濾
5:英文相近詞
6:去除重復(fù)詞
以上是針對英文,中文的除了空格,其他都類似
[Solr中文應(yīng)用的一個實例]
1、首先配置schema.xml,這個相當(dāng)于數(shù)據(jù)表配置文件,它定義了加入索引的數(shù)據(jù)的數(shù)據(jù)類型的。1.2版本的schema.xml主要包括types、fields和其他的一些缺省設(shè)置。
A、首先需要在types結(jié)點內(nèi)定義一個FieldType子結(jié)點,包括name,class,positionIncrementGap等等一些參數(shù),name就是這個FieldType的名稱,class指向org.apache.solr.analysis包里面對應(yīng)的class名稱,用來定義這個類型的行為。在FieldType定義的時候最重要的就是定義這個類型的數(shù)據(jù)在建立索引和進行查詢的時候要使用的分析器analyzer,包括分詞和過濾。在例子中text這個FieldType在定義的時候,在index的analyzer中使用solr.WhitespaceTokenizerFactory這個分詞包,就是空格分詞,然后使用solr.StopFilterFactory,solr.WordDelimiterFilterFactory,solr.LowerCaseFilterFactory,solr.EnglishPorterFilterFactory,solr.RemoveDuplicatesTokenFilterFactory這幾個過濾器。在向索引庫中添加text類型的索引的時候,Solr會首先用空格進行分詞,然后把分詞結(jié)果依次使用指定的過濾器進行過濾,最后剩下的結(jié)果才會加入到索引庫中以備查詢。Solr的analysis包并沒有帶支持中文的包,在這里我們采用lucene里的語言包(在下載后的solr壓縮包內(nèi),lib目錄下有一個lucene-analyzers-2.2.0.jar包,里面含有中文處理的cn和cjk類),有cn和cjk兩個類可以支持中文。我們采用cjk類,并在schema.xml中加入如下配置:
- <fieldtype name="text_cjk" class="solr.TextField">
- <analyzer class="org.apache.lucene.analysis.cjk.CJKAnalyzer"/>
- </fieldtype>
支持類型定義完成了。
B、接下來的工作就是在fields結(jié)點內(nèi)定義具體的字段(類似數(shù)據(jù)庫中的字段),就是filed,filed定義包括name,type(為之前定義過的各種FieldType),indexed(是否被索引),stored(是否被儲存),multiValued(是否有多個值)等等。例如定義如下:
- <field name="記錄號" type="slong" indexed="true" stored="true" required="true" />
- <field name="文件名" type="string" indexed="true" stored="true" />
- <field name="日期" type="date" indexed="true" stored="true" />
- <field name="版次" type="string" indexed="true" stored="true" multiValued="true"/>
- <field name="欄目" type="string" indexed="true" stored="true" multiValued="true"/>
- <field name="標(biāo)題" type="text_cjk" indexed="true" stored="true" multiValued="true"/>
- <field name="作者" type="text_cjk" indexed="true" stored="true" multiValued="true"/>
- <field name="正文" type="text_cjk" indexed="true" stored="true" multiValued="true"/>
- <field name="標(biāo)記" type="text_cjk" indexed="true" stored="true" multiValued="true"/>
field的定義相當(dāng)重要,有幾個技巧需注意一下,對可能存在多值得字段盡量設(shè)置multiValued屬性為true,避免建索引是拋出錯誤;如果不需要存儲相應(yīng)字段值,盡量將stored屬性設(shè)為false。
C、建議建立了一個拷貝字段,將所有的全文字段復(fù)制到一個字段中,以便進行統(tǒng)一的檢索:
- <field name="text_com" type="text_cjk" indexed="true" stored="false" multiValued="true"/>
并在拷貝字段結(jié)點處完成拷貝設(shè)置:
- <copyfield source="標(biāo)題" dest="text_com"/>
- <copyfield source="正文" dest="text_com"/>
D、除此之外,還可以定義動態(tài)字段,所謂動態(tài)字段就是不用指定具體的名稱,只要定義字段名稱的規(guī)則,例如定義一個dynamicField,name為*_i,定義它的type為text,那么在使用這個字段的時候,任何以_i結(jié)尾的字段都被認(rèn)為是符合這個定義的,例如name_i,gender_i,school_i等。
2、配置solrconfig.xml,用來配置Solr的一些系統(tǒng)屬性,比較重要的一個就是可以通過更改其中的dataDir屬性來指定索引文件的存放位置,對于有大數(shù)據(jù)量的情況下還要進行自動commit操作配置,以下設(shè)置為當(dāng)內(nèi)存索引量達到20W條時自動進行往磁盤寫操作,以免堆溢出,這也是解決單個入庫xml文件最好不要超過30M的有效方法:
- <autocommit>
- <maxdocs>200000</maxdocs>
- </autocommit>
3、配置好這些后,需要重新啟動Solr服務(wù)器使配置生效,然后向其中添加數(shù)據(jù)。
4、添加數(shù)據(jù)是通過向服務(wù)器的update Servlet POST xml格式的數(shù)據(jù)來實現(xiàn)的,xml結(jié)構(gòu)是這樣的add中間有很多個doc,每個doc中有很多個field。添加到索引庫中的每條記錄都必須指定唯一的數(shù)字id來唯一標(biāo)識這條索引。建立好xml文件(例如solr.xml)之后,在exampledocs目錄下執(zhí)行:java -jar post.jar solr.xml來添加索引數(shù)據(jù)。對于post的jar包,如果重新配置了應(yīng)用服務(wù)器,如使用了comcat,端口改為8080,實例名稱改為solrx了需要重新生成相應(yīng)的post.jar包進行操作。
另附ronghao實現(xiàn)中文分詞的案例供大家參考:
對全文檢索而言,中文分詞非常的重要,這里采用了qieqie庖丁分詞(非常不錯:))。集成非常的容易,我下載的是2.0.4-alpha2版本,其中它支持最多切分和按最大切分。創(chuàng)建自己的一個中文TokenizerFactory繼承自solr的BaseTokenizerFactory。
**
* Created by IntelliJ IDEA.
* User: ronghao
* Date: 2007-11-3
* Time: 14:40:59
* 中文切詞 對庖丁切詞的封裝
*/
public class ChineseTokenizerFactory extends BaseTokenizerFactory {
/**
* 最多切分 默認(rèn)模式
*/
public static final String MOST_WORDS_MODE = “most-words”;
/**
* 按最大切分
*/
public static final String MAX_WORD_LENGTH_MODE = “max-word-length”;
private String mode = null;
public void setMode(String mode) {
if (mode==null||MOST_WORDS_MODE.equalsIgnoreCase(mode)
|| “default”.equalsIgnoreCase(mode)) {
this.mode=MOST_WORDS_MODE;
} else if (MAX_WORD_LENGTH_MODE.equalsIgnoreCase(mode)) {
this.mode=MAX_WORD_LENGTH_MODE;
}
else {
throw new IllegalArgumentException(”不合法的分析器Mode參數(shù)設(shè)置:” + mode);
}
}
@Override
public void init(Map args) {
super.init(args);
setMode(args.get(”mode”));
}
public TokenStream create(Reader input) {
return new PaodingTokenizer(input, PaodingMaker.make(),
createTokenCollector());
}
private TokenCollector createTokenCollector() {
if( MOST_WORDS_MODE.equals(mode))
return new MostWordsTokenCollector();
if( MAX_WORD_LENGTH_MODE.equals(mode))
return new MaxWordLengthTokenCollector();
throw new Error(”never happened”);
}
}
在schema.xml的字段text配置里加入該分詞器。
1. <fieldtype name="text" class="solr.TextField" positionIncrementGap="100">
2.
3. <analyzer type="index">
4.
5. <tokenizer class="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory" mode="most-words"/>
6.
7.
8. <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
9.
10. <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0"/>
11.
12. <filter class="solr.LowerCaseFilterFactory"/>
13.
14.
15. <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
16.
17. </analyzer>
18.
19. <analyzer type="query">
20.
21. <tokenizer class="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory" mode="most-words"/>
22.
23. <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
24.
25. <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
26.
27. <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0"/>
28.
29. <filter class="solr.LowerCaseFilterFactory"/>
30.
31. <filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
32.
33. </analyzer>
34.
35. </fieldtype>
完成后重啟tomcat,即可在http://localhost:8080/solr/admin/analysis.jsp
體驗到庖丁的中文分詞。注意要將paoding-analysis.jar復(fù)制到solr的lib下,注意修改jar包里字典的home。
[Solr的檢索運算符]
“:” 指定字段查指定值,如返回所有值*:*²
“?”²表示單個任意字符的通配
“*” 表示多個任意字符的通配(不能在檢索的項開始使用*或者?符號)²
“~”²表示模糊檢索,如檢索拼寫類似于”roam”的項這樣寫:roam~將找到形如foam和roams的單詞;roam~0.8,檢索返回相似度在0.8以上的記錄。
²鄰近檢索,如檢索相隔10個單詞的”apache”和”jakarta”,”jakarta apache”~10
“^”²控制相關(guān)度檢索,如檢索jakarta apache,同時希望去讓”jakarta”的相關(guān)度更加好,那么在其后加上”^”符號和增量值,即jakarta^4 apache
布爾操作符AND、||²
布爾操作符OR、²&&
布爾操作符NOT、!、-²(排除操作符不能單獨與項使用構(gòu)成查詢)
“+” 存在操作符,要求符號”+”后的項必須在文檔相應(yīng)的域中存在²
( ) 用于構(gòu)成子查詢²
² [] 包含范圍檢索,如檢索某時間段記錄,包含頭尾,date:[200707 TO 200710]
{}²不包含范圍檢索,如檢索某時間段記錄,不包含頭尾
date:{200707 TO 200710}
" 轉(zhuǎn)義操作符,特殊字符包括+ -² && || ! ( ) { } [ ] ^ ” ~ * ? : "
posted on 2008-03-26 11:22
流浪汗 閱讀(14318)
評論(1) 編輯 收藏 所屬分類:
lucene