1 solr概述
1.1 solr的簡介
1.2 solr的特點
2 Solr安裝
2.1 安裝JDK
2.2 安裝Tomcat
2.3 安裝solr
2.4 目錄結構說明
2.5 SOLR HOME說明
3 Solr配置
3.1 Solr.XML說明
3.2 配置SolrConfig.xml
3.3 配置schema.xml
3.4 配置中文分詞
3.5 多實例部署
4 solr使用
4.1 添加索引
4.2 更新索引
4.3 刪除索引
4.4 提交和優化
4.5 查詢索引
5 擴展到SolrCloud
5.1 Zookeeper安裝
5.2 啓動SolrCloud
5.3 術語及注意事項
6 SolrJ的使用
6.1 部署號碼黃頁的SolrCloud
6.2 SolrJ操作SolrCloud
7 Solr管理
1 solr概述
1.1 solr的簡介
solr是一個基於lucene的全文檢索引擎。他包括了全文檢索,命中高亮,準實時搜索,富文本檢索等特性. Solr是用Java編寫的,並作爲一個獨立的全文搜索服務器,比如tomcat容器內運行。Solr的全文索引和搜索其核心使用了Lucene Java搜索庫,並具有類似REST的HTTP / XML和JSON的API,可以很容易地從幾乎任何編程語言使用.
什麼是全文檢索?
全文檢索是將存儲於數據庫中整本書、整篇文章中的任意內容信息查找出來的檢索。它可以根據需要獲得全文中有關章、節、段、句、詞等信息,也就是說類似於給整本書的每個字詞添加一個標籤,也可以進行各種統計和分析。
對於全文檢索來說,倒排索引是最常用的一種技術。倒排索引用來存儲某個單詞在一個文檔或者一組文檔中的存儲位置的映射。它是文檔檢索系統中最常用的數據結構。
然後再我們檢索的時候。系統會將我們需要查詢的文本轉化爲檢索詞。然後去映射表中查詢其對應的文檔,然後做文檔歸併既可以獲取到我們希望得到的結果。
Why solr?
既然Solr是基於lucene的,那爲什麼我們不直接使用Lucene呢?
Lucene是一個開放源代碼的全文檢索引擎工具包,即它不是一個完整的全文檢索引擎,而是一個全文檢索引擎的架構,提供了完整的查詢引擎和索引引擎 。Lucene的目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者是以此爲基礎建立起完整的全文檢索引擎.
Lucene的涉及目標決定了lucene在擴展和管理索引上比較困難。但是solr提供了一個管理頁面,並且可以動態的添加和刪除索引節點。可以做索引之間的互備,而這些使用lucene則很難實現
1.2 solr的特點
- 基於標準的開放接口:Solr支持XML,JSON和HTTP的調用形式,所以雖然solr是用java寫成,但是我們依然可以使用別的語言來調用solr
- 先進的全文檢索技術:在Solr中,我們不僅可以使用詞來作爲檢索條件,還可以使用時間範圍,數字範圍等作爲檢索條件,也可以進行模糊搜索。
- 線性可擴展性:可以在線的擴展索引節點,自動索引複製,自動故障切換和恢復。
- 近實時索引:數據添加到索引後,可以很快的被檢索到。
- 管理界面:可以很方便的管理各個節點,包括索引統計信息以及各個節點的狀態。
2 Solr安裝
Solr的運行環境非常簡單。只需要JDK和一個WEB容器。這裏以Tomcat爲例介紹Solr的安裝。
2.1安裝JDK
下載JDK:
http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR
設置權限:[root@localhost solrTest]# chmod 777 ./jdk-6u45-linux-i586.bin
安裝:[root@localhost solrTest]# ./jdk-6u45-linux-i586.bin
設置環境變量,在/ect/profile中添加並export
[root@localhost solrTest]# vim /etc/profile
在文件的最後加上下面三句話,並在控制檯內也執行這四句話
JAVA_HOME=/usr/local/solrTest/jdk1.6.0_45
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
確定已經安裝成功
在控制檯執行
[root@localhost ~]# java –version
返回
java version "1.6.0_45"
Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
Java HotSpot(TM) Client VM (build 20.45-b01, mixed mode, sharing)
2.2安裝Tomcat
下載TOMCAT http://tomcat.apache.org/download-60.cgi
解壓縮 [root@localhost solrTest]# tar -zxvf apache-tomcat-6.0.37.tar.gz
啓動Tomcat
[root@localhost apache-tomcat-6.0.37]# cd /usr/local/solrTest/apache-tomcat-6.0.37/bin/
[root@localhost bin]# ./catalina.sh start
訪問頁面測試下http://192.168.39.250:8080/ (虛擬主機的IP)
看到這個頁面說明Tomcat運行正常
2.3安裝solr
下載solr http://lucene.apache.org/solr/downloads.html
解壓縮 [root@localhost solrTest]# tar zxvf solr-4.4.0.tgz
Solr解壓後會有一個example目錄,這個目錄下是Solr自帶的一個示例。這個示例下有一個已經編譯好的Solr.War.我們後續的操作可以使用這個已經編譯好的war包
將war包拷到Tomcat目錄下:
[root@localhost solrTest]# cp solr-4.4.0/example/webapps/solr.war /usr/local/solrTest/apache-tomcat-6.0.37/webapps/solr.war
創建一個集合的文件夾並配置
[root@localhost solrTest]# mkdir testData
[root@localhost solrTest]# cp -a solr-4.4.0/example/solr/* testData/
設置solr home
[root@localhost solrTest]# vi apache-tomcat-6.0.37/conf/Catalina/localhost/solr.xml
<?xml version="1.0" encoding="utf-8"?>
<Context docBase="/usr/local/solrTest/apache-tomcat-6.0.37/webapps/solr.war" debug="0" crossContext="true">
<Environment name="solr/home" type="java.lang.String" value="/usr/local/solrTest/testData" override="true"/>
</Context>
啓動一下Tomcat
(/usr/local/solrTest/apache-tomcat-6.0.37/bin/startup.sh)
這時http://192.168.39.250:8080/solr 應該是無法訪問的,主要是因爲缺少配置文件
關閉tomcat (/usr/local/solrTest/apache-tomcat-6.0.37/bin/shutdown.sh)
拷貝一下文件:
[root@localhost solrTest]# cp solr-4.4.0/example/lib/ext/* apache-tomcat-6.0.37/webapps/solr/WEB-INF/lib/
[root@localhost solrTest]# cp solr-4.4.0/example/resources/log4j.properties apache-tomcat-6.0.37/lib/
再次啓動 Tomcat (/usr/local/solrTest/apache-tomcat-6.0.37/bin/startup.sh)
再次訪問 http://192.168.39.250:8080/solr
可以看到 Solr已經可以正常的運行,現在 我們來看一下Solr的目錄結構
2.4目錄結構說明
我們下載的Solr包後,進入Solr所在的目錄,我們可以看到以下幾個目錄:contrib、dist、docs、example、licenses。下面分別對其進行介紹。
-
1) Contrib:Solr的一些擴展包,包括分詞器,聚類,語言識別,數據導入處理,非結構化內容分析等.
-
2) dist:該目錄包含build過程中產生的war和jar文件,以及相關的依賴文件。我們之前使用的solr.war實際上就是這個文件夾下的solr-4.40.war
-
3) example:這個目錄實際上是Tomcat的安裝目錄。其中包含了一些樣例數據和一些Solr的配置。第一次使用solr的時候可以直接啓動這個目錄下的start.jar來啓動solr,以便對solr有個比較直觀的瞭解
其中一些子目錄也比較重要,這裏也對它們稍作介紹。
- example/multicore:該目錄是一個包含了多實例配置信息的Solr的home目錄。
- example/solr:該目錄是一個包含了默認配置信息的Solr的home目錄。
- example/webapps:tomcat的webapps目錄,該目錄通常用來放置Java的Web應用程序。在Solr中,前面提到的solr.war文件就部署在這裏。
其餘的2個目錄docs和licenses則分別是本地的文檔以及權限介紹.
2.5 SOLR HOME說明
Solr home目錄實際上是一個運行的Solr實例所對應的配置和數據(Lucene索引)。就example來說,合法的solrhome目錄有2個,一個是example/solr目錄,另一個是example/multicore目錄,他們的區別就是multicore是多實例的。
example/solr目錄下主要有以下一些目錄和文件:
- solr.xml solr的主要配置文件,在solr啓動的時候被加載,solr的配置信息包括端口號,連接時間,超時時間等.
- collection1/conf/ schema.xml 該文件是索引的schema,包含了域類型的定義
- collection1/conf/ solrconfig.xml 該文件是Solr的主配置文件,solr的版本,數據存放位置,定義擴展功能的使用等.
3 Solr配置
Solr的配置主要是以下三個主要的文件solr.xml, solrconfig.xml, schema.xml,在solr啓動的時候,會首先檢查solr.xml,這個文件時solr的全局的配置信息.告訴solr在哪裏可以找到solr的實例.在solr.xml加載後,solr會去每個實例內查找solrconfig.xml. solrconfig.xml指向其他的配置文件.除非修改solrconfig.xml,否則將以schema.xml配置文件來決定Solr的字段
3.1 Solr.XML說明
Solr.xml的配置通常是不用修改的,配置文件可以修改的欄目如下:
<solr>
<str name="adminHandler">${adminHandler:org.apache.solr.handler.admin.CoreAdminHandler}</str>
<int name="coreLoadThreads">${coreLoadThreads:3}</int>
<str name="coreRootDirectory">${coreRootDirectory:}</str> <!-- usually solrHome -->
<str name="managementPath">${managementPath:}</str>
<str name="sharedLib">${sharedLib:}</str>
<str name="shareSchema">${shareSchema:false}</str>
<int name="transientCacheSize">${transientCacheSize:Integer.MAX_VALUE}</int> <!-- ignored unless cores are defined with transient=true -->
<solrcloud>
<int name="distribUpdateConnTimeout">${distribUpdTimeout:}</int>
<int name="distribUpdateSoTimeout">${distribUpdateTimeout:}</int>
<int name="leaderVoteWait">${leaderVoteWait:}</int>
<str name="host">${host:}</str>
<str name="hostContext">${hostContext:solr}</str>
<int name="hostPort">${jetty.port:8983}</int>
<int name="zkClientTimeout">${zkClientTimeout:15000}</int>
<str name="zkHost">${zkHost:}</str>
<bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
</solrcloud>
<logging>
<str name="class">${loggingClass:}</str>
<str name="enabled">${loggingEnabled:}</str>
<watcher>
<int name="size">${loggingSize:}</int>
<int name="threshold">${loggingThreshold:}</int>
</watcher>
</logging>
<shardHandlerFactory name="shardHandlerFactory" class="HttpShardHandlerFactory">
<int name="socketTimeout">${socketTimeout:}</int>
<int name="connTimeout">${socketTimeout:}</int>
</shardHandlerFactory>
</solr>
Solr.xml在加載以後,會去根目錄下的每個目錄進行搜索,直到遇到一個名爲core.properties的文件. 發現core.properties文件的目錄被當成一個sorlr的實例. core.properties可以設置的項目包括:
- name 實例名字.
- config 實例的配置文件名,默認爲solrconfig.xml
- dataDir 數據存儲路徑,默認爲當前路徑.
- ulogDir 事物日誌的存儲路徑,默認爲當前路徑
- schema 域字段的配置文件,默認爲schema.xml
- shard 實例的 ID.
- roles SolrCloud 中的角色定義是什麼
- loadOnStartup 是否是在solr啓動的時候加載,默認爲Ture.
- coreNodeName solr核心節點名字
3.2 配置SolrConfig.xml
solrconfig.xml文件包含了大部分的參數用來配置Solr本身的。solrconfig.xml文件不僅指定了 Solr 如何處理索引、突出顯示、分類、搜索以及其他請求,還指定了用於指定緩存的處理方法的屬性,以及用於指定Lucene 管理索引的方法的屬性。
3.2.1 插件加載
Solr的允許你加載自定義代碼來執行各種任務,首先將你的solr的插件打成一個jar,然後以類似下面的方式配置solr,以便讓solr知道如何加載他們
如果我們有多個實例,並且希望所有的實例都可以共享插件.可以在solr.xml中啓動sharedLib屬性.
如果只希望在某些實例中使用插件.則可以使用如下的方式來配置插件.
<lib dir=”../../../contrib./extractor/lib” regex=”.*\.jar” />
<lib path=”../a-jar-that-does-not-exist.jar”>
注意 在默認情況下訪問http://192.168.39.250:8080/solr/#/~logging頁面應該會出現如下異常:
修改solrconfig.xml文件內的lib加載路徑後,重新tomcat.再次訪問.正常
< lib dir="/usr/local/solrTest/solr-4.4.0/contrib/extraction/lib" regex=".*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/dist/" regex="solr-cell-\d.*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/contrib/clustering/lib/" regex=".*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/dist/" regex="solr-clustering-\d.*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/contrib/langid/lib/" regex=".*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/dist/" regex="solr-langid-\d.*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/contrib/velocity/lib" regex=".*\.jar" />
<lib dir="/usr/local/solrTest/solr-4.4.0/dist/" regex="solr-velocity-\d.*\.jar" />
3.2.2 dataDir
默認情況下索引文件時在實例的./data的目錄下,但是我們也可以使用來修改默認目錄.
<dataDir>/var/data/solr</dataDir>
3.2.3 更新配置
<updateHandler class="solr.DirectUpdateHandler2">
<maxPendingDeletes>100000</maxPendingDeletes>
<autoCommit>
<maxDocs>10000</maxDocs>
<maxTime>15000</maxTime>
<openSearcher>false</openSearcher>
</autoCommit>
…
這個更新處理器主要涉及底層的關於如何更新處理內部的信息。(這個參數不同於來自客戶端的手動更新)。
- maxPendingDeletes 最大的緩衝項目
- maxDocs 內存中最多的文檔數
- maxTime 觸發自動提交的最大等待時間,單位是ms
- openSearcher 在值爲false的時候,在啓動硬盤搜索的時候不會打開新的實例,導致內存內的信息可以被檢索到
3.2.4 查詢配置
<maxBooleanClauses>1024</maxBooleanClauses>
查詢子句的最大的數量.這裏的默認值爲1024.修改這個值可以傳入更多的條件.
3.2.5 緩存配置
<queryResultCache
class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="256"/>
<documentCache
class="solr.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"/>
這裏也基本不需要修改,目前支持的緩存算法有LRU(近期最少使用算法),FastLRU,LFU(最近最不常用) FastLRUCache比LRU有更快的讀取速度以及更慢的插入速度,而且有可能大小沒有限制.
size是最大情況下緩存的條目(注意,不是內存大小)。Init是初始容量
filterCache存儲了filter queries(“fq”參數)得到的document id集合結果。Solr中的query參數有兩種,即q和fq。如果fq存在,Solr是先查詢fq(因爲fq可以多個,所以多個fq查詢是個取結果交集的過程),之後將fq結果和q結果取並。在這一過程中,filterCache就是key爲單個fq(類型爲Query),value爲document id集合(類型爲DocSet)的cache。對於fq爲range query來說,filterCache表現出其有價值的一面。
queryResultCache是對查詢結果的緩存,documentCache用來保存<doc_id,document>對的
myUserCache是用戶自定義的一個cache,如果開啓了自定義的緩存。則不使用Solr自帶的緩存。
3.3 配置schema.xml
schema.xml文件主要用來配置數據類型和字段信息.這些字段被用來建立索引和查詢.
3.3.1 數據類型
數據類型可以在標籤內用 標籤來定義.定義fieldtype時,最少應該包含name,class這個兩個屬性. name就是這個FieldType的名稱,class指向類所在的位置.在fieldtype定義的時候,一般還會定義類型的analyser(分詞器), similarity(評分器)等
<types>
<fieldType name="text_dfr" class="solr.TextField">
<analyzer class="org.apache.lucene.analysis.standard.StandardAnalyzer"/>
<similarity class="solr.DFRSimilarityFactory">
<str name="basicModel">I(F)</str>
<str name="afterEffect">B</str>
<str name="normalization">H2</str>
</similarity>
</fieldType>
<fieldType name="text_ib" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/>
</analyzer>
<similarity class="org.apache.lucene.search.similarities.DefaultSimilarity"/>
</fieldType>
...
</types>
<similarity class="solr.SchemaSimilarityFactory"/>
analyzer,包括分詞和過濾. 在index的analyzer中使用 solr.WhitespaceTokenizerFactory這個分詞包,就是空格分詞,然後使用 solr.StopFilterFactory這幾個過濾器。在向索引庫中添加text類型的索引的時候,Solr會首先用空格進行分詞,然後把分詞結果依次使用指定的過濾器進行過濾,最後剩下的結果纔會加入到索引庫中以備查詢。Solr的analysis包中默認並不包括中文的分詞包.
Similarity 是計算相似性的組件,相似性用於計算搜索命中後的得分,得分最後影響排序,Solr默認的評分器是基於TF-IDF的計算方法來實現的.通常這個是不用修改的.但是Solr4中支持分別爲每個字段定義相似性計算的類以及全局的計算類.
3.3.2 字段
接下來的工作就是在fields結點內定義具體的字段(類似數據庫中的字段),就是filed,filed定義包括name,type(爲之前定義過的各種FieldType),indexed(是否被索引),stored(是否被儲存),multiValued(是否有多個值)等等。
<fields>
<field name="id" type="integer" indexed="true" stored="true" required="true" />
<field name="name" type="text" indexed="true" stored="true" />
<field name="summary" type="text" indexed="true" stored="true" />
<field name="keyword" type="text" indexed="true" stored="false" multiValued="true" />
...
</ fields >
field的定義相當重要,有幾個技巧需注意一下,對可能存在多值得字段儘量設置 multiValued屬性爲true,避免建索引是拋出錯誤;如果不需要存儲相應字段值,儘量將stored屬性設爲false。 所謂multValued就是一個field有多個值,如下:
3.3.3 唯一鍵
定義唯一鍵. id
3.3.4 拷貝字段
拷貝字段舉例來說,就是查詢的時候不用再輸入:userName:張三 and userProfile:張三的個人簡介。直接可以輸入"張三"就可以將“名字”含“張三”或者“簡介”中含“張三”的又或者“名字”和“簡介”都含有“張三”的查詢出來。他將需要查詢的內容放在了一個字段中,並且查詢該字段就行了
如建立了一個統一的查詢字段all,並將name和summary拷貝到這個字段內:
< field name="all" type="text" indexed="true" stored="false" multiValued="true" />
並在拷貝字段結點處完成拷貝設置:
<copyField source="name" dest="all"/>
<copyField source="summary" dest="all" maxChars="300"/>
拷貝字段可以設置最大的字符長度
3.3.5 動態字段
動態字段就是不用指定具體的名稱,只要定義字段名稱的規則,例如定義一個 dynamicField,name 爲*i,定義它的type爲text,那麼在使用這個字段的時候,任何以i結尾的字段都被認爲是符合這個定義的
如我們一開始定義字段的時候可能並沒有考慮到有school這個字段,但是索引已經運行一段時間.並不方便再次修改索引的配置文件.這時就可以直接在添加索引的時候加上school_i這個字段而不需要修改配置文件就能生效.
3.4 配置中文分詞
如上文所說,目前Solr中默認是不支持中文分詞的.如果需要支持中文.則必須自己擴展分詞組件.目前國內比較有名的分詞組件有IK,庖丁, ICTCLAS, 盤古分詞, mmseg4j等.就業內評測結果來說, ICTCLAS分詞效果最好,而且包含詞性識別.但是ICTCLAS分爲商用版和免費版兩種,免費版的測試結果欠佳.
如: 工信處女幹事每月經過機房時都會檢查二十四口交換機
結果爲: 工/n 信/n 處女/n 幹事/n 每月/r 經過/p 機房/n 時/ng 都/d 會/v 檢查/v 二十四/m 口/q 交換機/n
就分詞來說.主要需要考慮的要素爲準確率和召回率.如
“世界盃”是一個詞,用單字切分的話,查“世界”也可以命中這篇文檔,而用中文分詞就查不到了; 而中文分詞的支持者們的反駁大概是: “參加過世界盃”,用單字切分的話,查“過世”也可以命中這篇文檔,但事實上並沒有人掛掉;
所以通常的做法是在建立索引階段.使用全切分的算法對文本中所有的可能性詞語進行切分,並在檢索階段竟可能的去準確的分析用戶的意圖.
IK在處理全切分時,速度較快,並且可以返回所有的可能結果.下面以IK爲例,配置中文分詞.
下載IK.
https://code.google.com/p/ik-analyzer/downloads/detail?name=IK%20Analyzer%202012FF_hf1.zip&can=2&q=
解壓
[root@localhost IK]# unzip IK.zip
拷貝到solr的lib下
[root@localhost conf]# cp /usr/local/solrTest/IK/IKAnalyzer2012FF_u1.jar /usr/local/solrTest/testData/lib/IK.jar
配置solrconfig.xml.設置IK的加載路徑.
<lib path="../lib/IK.jar" />
配置schma.xml(這時一個最簡單的schema文件)
<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.5">
<fields>
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="text" type="text_ik" indexed="true" stored="true"/>
<field name="_version_" type="long" indexed="true" stored="true"/>
</fields>
<uniqueKey>id</uniqueKey>
<types>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
</types>
</schema>
啓動Tomcat.並訪問http://192.168.39.250:8080/solr 看到正常的solr頁面表示插件已經正常加載了. 如果遇到問題.需要分析appache的日誌來定位問題並修正.
3.5 多實例部署
多核,官方說法,讓你只用一個Solr實例,實現多配置多索引的功能,爲不同的應用保留不同的配置。就是每個core都有獨立的solrconfig.xml與schema.xml,卻依然保留統一與方便的管理。每份索引都可以當做一個獨立的應用來對待,甚至可以實現索引的熱切換。比如說,爲新聞、微博、論壇搜索各建立一個搜索系統。
由上文提到的
“Solr.xml在加載以後,會去根目錄下的每個目錄進行搜索,直到遇到一個名爲core.properties的文件”
Solr4中不在需要對多核心做特殊的配置,只需要創建新的collection文件夾就可以了.以下是一個簡單的示例.
複製文件夾
[root@localhost testData]# cp -r collection1/ collection2/
修改core.properties文件
[root@localhost collection2]# vim core.properties
name=collection2
重新啓動tomcat 既可以看到效果.
4 solr使用
Solr使用主要分爲兩個部分.一個是建立索引,一個是查詢索引.建立索引的過程包括追加,刪除,提交,優化(合併).Solr爲了保證能夠提供給其他語言接口.提供了REST接口(這裏指可以使用HTTP協議和Solr進行交互).REST接口提供的格式有XML,JSON,CSV
下面介紹的時候.將先介紹REST的接口中的JSON的形式,再介紹Java的實現.其本質實際上是一樣的.
4.1 添加索引
首先編輯我們需要上傳的JSON文件(這個文件以上文中創建的solr實例collection1爲例).
[
{
"id" : "978-0641723445",
"text" : "Solr in Action"
},
{
"id" : "978-1423103349",
"text" : "Solr測試"
},
{
"id" : "978-1857995879",
"text" : "工信處女幹事"
}
]
文件命名爲simpleTest.json
執行(HTML-POST)
[root@localhost testREST]# curl 'http://192.168.39.250:8080/solr/collection1/update/json?commit=true' --data-binary @simpleTest.json -H 'Content-type:application/json'
訪問: http://192.168.39.250:8080/solr/collection1/select?q=%3A&wt=json&indent=true (q=: 即查詢所有記錄)
返回結果如上圖.可以看到已經添加成功
4.2 更新索引
以下個JSON爲例說明如何使用JSON來進行更新
[
"add": {
"commitWithin": 5000,
"overwrite": true,
"boost": 3.45,
"doc": {
"id": "978-1857995879",
"text": "工信處女幹事每月經過機房時都會檢查二十四口交換機"
"text": "工信處女幹事每月經過機房時都會檢查二十四口交換機"
}
}
]
訪問頁面.可以看到剛纔的信息已經被更新
4.3 刪除索引
爲了演示刪除這裏又多加了一條數據 ID:978-1423103350,刪除的代碼很簡單.
[
"delete": { "id":"978-1423103350" }
]
可以看到, ID:978-1423103350的記錄已經被刪除了
4.4 提交和優化
commit 告訴 Solr,應該使上次提交以來所做的所有更改都可以搜索到。默認情況下索引內容是在內存中,當顯式的調用commit的時候.Solr就會把這部分內容寫到硬盤.
optimize 重構 Lucene 的文件以改進搜索性能。索引完成後執行一下優化通常比較好。如果更新比較頻繁,則應該在使用率較低的時候安排優化。一個索引無需優化也可以正常地運行。優化是一個耗時較多的過程。優化的主要作用是合併lucene文件,以減少IO操作.
在JSON中使用commit和optimize很簡單.只要如下即可.
[
"commit": {},
"optimize":{}
]
Optimize有參數maxSegments .值是數值,表示優化後的段文件數目(默認爲1)
4.5 查詢索引
添加文檔後,就可以搜索這些文檔了。Solr 接受 HTTP GET 和 HTTP POST 查詢消息。收到的查詢由相應的 SolrRequestHandler 進行處理。
Solr部署才成功後.先進入http://192.168.39.250:8080/solr頁面,然後選擇solr的實例.再點擊Query即可進入Solr的查詢頁面. Solr查詢頁面主要是提供了一個方面的查詢接口.不用自己去拼接URL即可完成複雜的查詢.如果需要最終的URL.可以在Solr查詢頁面的上面獲取到拼接後的地址.
[Solr的檢索運算符]
1. “:” 指定字段查指定值,如返回所有值*:*
2. “?” 表示單個任意字符的通配
3. “*” 表示多個任意字符的通配(不能在檢索的項開始使用*或者?符號)
4. “~” 表示模糊檢索,如示例中分詞結果不存在二四.所以直接用二四查詢會不存在結果.但是如果是”二四~” 則可以命中記錄
5. 鄰近檢索,如查詢text:”solr action”~0 沒有結果而”solr action”~1 命中
6. “^” 控制相關度檢索,如檢索jakarta apache,同時希望去讓”jakarta”的相關度更加好,那麼在其後加上”^”符號和增量值,即jakarta^4 apache
7. 布爾操作符AND、OR、&&、||、+、<空格>
8. 布爾操作符NOT、!、- (排除操作符不能單獨與項使用構成查詢)
9. “+” 存在操作符,要求符號”+”後的項必須在文檔相應的域中存在
10. ( ) 用於構成子查詢 如 +text:((Solr && 測試) 處女)
11. [] 包含範圍檢索,如檢索某時間段記錄,包含頭尾,date:[200707 TO 200710]
12. {} 不包含範圍檢索,如檢索某時間段記錄,不包含頭尾date:{200707 TO 200710}
13. \ 轉義操作符,特殊字符包括+ - && || ! ( ) { } [ ] ^ ” ~ * ? : \
Solr查詢參數說明
•q - 查詢字符串,查詢的語法需要符合上述的檢索運算符規則。
•fq -過濾語句,默認包含纔會返回查詢結果.如q=text:solr fq=text:in 則結果命中Solr in Action 如果q=text:solr fq=-text:in 則命中Solr測試
•fl - 指定返回那些字段內容,用逗號或空格分隔多個。如指定text 則不再返回id的值
•start - 返回第一條記錄在完整找到結果中的偏移位置,0開始,一般分頁用。
•rows - 指定返回結果最多有多少條記錄,配合start來實現分頁。
•sort - 排序,格式:sort=<field name><空格><desc|asc>[,<field name><空格><desc|asc>]… 。
示例:(id asc,text desc)表示先 “id” 升序, 再 “text” 降序,默認是相關性降序。
•wt - (writer type)指定輸出格式,可以有 xml, json, php, python,ruby等。
•df - 默認的查詢字段,一般默認指定
•qt - (query type)指定那個類型來處理查詢請求,一般不用指定,默認是standard。
•indent - 返回的結果是否縮進,默認關閉,用 indent=true|on 開啓,一般調試json,php,phps,ruby輸出纔有必要用這個參數。
•hl - 檢索結果高亮 hl.fl用於設置需要高亮的字段.hl.simple.pre和hl.simple.post用於設置高亮的標籤
•facet - 類似於字段統計.顯示所有已經索引的字段以及他的數目.
5 擴展到SolrCloud
在Solr的早期版本中,分佈式的索引是基於索引的複製分發,主節點負責建索引,建好之後定期複製分發到從節點,從節點負責查詢;支持從URL指定從節點響應查詢請求.這種情況下,根本就不能算作真正的分佈式索引。而且對節點的管理,擴充,負載均衡等都只能依靠自己來實現。所以在Solr4中。引入了SolrCloud的技術方案。
SolrCloud是基於Solr和Zookeeper的分佈式搜索方案,是正Solr4X的核心組件之一,它的主要思想是使用Zookeeper作爲集羣的配置信息中心。藉助Zookeeper.Solr4實現了集中式的配置信息,自動容錯以及查詢時自動負載均衡
5.1 Zookeeper安裝
下載: http://www.apache.org/dyn/closer.cgi/zookeeper/
解壓Zookeeper [root@localhost solrTest]# tar zxvf zookeeper-3.3.5.tar.gz
編輯對應的zookeeper配置文件,複製zookeeperconf下zoo_sample.cfg爲zoo.cfg
[root@localhost conf]# cp zoo_sample.cfg zoo.cfg
[root@localhost conf]# vi zoo.cfg
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
dataDir=/usr/local/solrTest/zookeeper/
# the port at which the clients will connect
clientPort=2181
- tickTime:心跳時間,爲了確保連接存在的,以毫秒爲單位,最小超時時間爲兩個心跳時間
- initLimit:多少個心跳時間內,允許其他server連接並初始化數據,如果ZooKeeper管理的數據較大,則應相應增大這個值
- clientPort:服務的監聽端口
- dataDir:用於存放內存數據庫快照的文件夾,同時用於集羣的myid文件也存在這個文件夾裏(注意:一個配置文件只能包含一個dataDir字樣,即使它被註釋掉了。)
- syncLimit:多少個tickTime內,允許follower同步,如果follower落後太多,則會被丟棄。
由於這裏主要是使用SolrCloud 所以只配置一個Zookeeper來管理所有的Solr節點.在實際環境中可以按Zookeeper集羣的方式來部署.
創建數據文件夾 [root@localhost bin]# mkdir /usr/local/solrTest/zookeeper
啓動 [root@localhost bin]# ./zkServer.sh start
[root@localhost bin]# ./zkCli.sh 測試是否可以連接到Zookeeper服務器.如下則爲正常
5.2 啓動SolrCloud
編輯Tomcat的catalina.sh文件 在啓動Tomcat的時候初始化Zookeeper的配置文件及SolrCloud的環境變量
[root@localhost bin]# vi catalina.sh
JAVA_OPTS="$JAVA_OPTS -Dbootstrap_confdir=/usr/local/solrTest/testData/collection1/conf -Dcollection.configName=myconf4test -DnumShards=1 -DzkHost=192.168.39.250:2181 -Dj
etty.port=8080"
- -DzkRun參數是啓動一個嵌入式的Zookeeper服務器,它會作爲solr服務器的一部分,這裏是外部zookeeper,就不需要此參數
- -Dbootstrap_confdir參數是上傳本地的配置文件上傳到zookeeper中去,作爲整個集羣共用的配置文件,
- -DnumShards指定了集羣的邏輯分組數目,數據會分散在裏面,最小單位爲doc。
- Djetty.port也可用於tomcat,指定對外服務的端口號
測試SolrCloud是否已經成功啓動
[root@localhost bin]# ./catalina.sh start
訪問頁面
http://192.168.39.250:8080/solr/#/~cloud
添加節點
主節點配置完成後,再添加節點就變得比較容易.只需要在別的機器節點的Solr啓動的時候,指定Zookeeper的host所在的機器即可.如在39.251上配置一個solr環境,保證實例的字段和主節點的一致 修改tomcat的文件
[root@localhost bin]# vi catalina.sh
JAVA_OPTS="-DzkHost=192.168.39.250:2181 -Djetty.port=8080"
啓動節點 一會可以看到
SolrCloud的查詢在任意一個節點上都可以使用.
在查詢的時候.會整合所有的shard的結果後再返回.所以只要指定collection.在任意一個存貨節點上查詢數據都是可以的.使用REST的時候只要先問ZK要存貨節點就OK了
5.3 術語及注意事項
- Collection 數據的集合,多個Collection就組成了Cluster(集羣).同一個羣集必須使用同一套schema和solrconfig
- Shard 分片 就是把Collection內的數據分成幾份,分的越多 負載也就越小.shard內的數據不會互相備份.
- Leader 每個分片至少有一個shard
- Replication 對leader的備份 可以爲0-n
注意:
-
1 JAVAOPTS的位置.在測試的時候. JAVAOPTS放在文件的最後不起作用.最後是放在
JAVA_OPTS (Optional) Java runtime options used when the "start"
-
2 主節點的選取時間 在solrCloud運行的時候,如果一個節點掛掉或者是重新啓動.其他的節點就進入了等待選取leader節點的狀態.這時solrCloud也無法進行訪問.這個選取leader的時間需要3分鐘.我們可以通過配置文件來縮短這個等待時間.
在solr.xml上添加配置:leaderVoteWait="${leaderVoteWait:20000}"就可以將選取等待時間減少
<solrcloud> <str name="host">${host:}</str> <int name="hostPort">${jetty.port:8983}</int> <str name="hostContext">${hostContext:solr}</str> <int name="zkClientTimeout">${zkClientTimeout:15000}</int> <int name="leaderVoteWait">${leaderVoteWait:20000}</int> <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool> </solrcloud>
-
3 默認情況下.有任意一個shard掛掉.將無法返回結果.可以在查詢URL的後面加上shards.tolerant=true來忽略失效的shard
舉例:
現在設置3個節點.250,251,252.251和252一個shard,251一個shard,停掉251,並查詢
加上shards.tolerant=true後
6 SolrJ的使用
現在,Solr的安裝部署,Solr雲的部署都已經有了介紹.下面以號碼黃頁爲例,介紹SolrJ的使用,在配置索引的使用,保留SolrCloud下的collection1 另建立一份collection,順便介紹solrcloud下的多實例的部署.
6.1 部署號碼黃頁的SolrCloud
從原有的集合中copy一份配置出來
[root@localhost testData]# cp -r collection1/ YellowPages/
修改實例的名稱
[root@localhost YellowPages]# vi core.properties
name=YellowPages
修改黃頁的資源實例.因爲只DEMO的性質 所以這裏就簡單的設計下. 黃頁內一個項目只包含 id ,name ,address,phone,其中phone可以爲多個.則schema.xml爲
[root@localhost YellowPages]# vi conf/schema.xml
<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.5">
<fields>
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="name" type="text" indexed="true" stored="true"/>
<field name="address" type="text_ik" indexed="true" stored="true"/>
<field name="phone" type="text" indexed="true" stored="true" multiValued="true" />
<field name="all" type="text_ik" indexed="true" stored="false" />
<copyField source="name" dest="all"/>
<copyField source="address" dest="all" />
<copyField source="phone" dest="all" />
<field name="_version_" type="long" indexed="true" stored="true"/>
</fields>
<uniqueKey>id</uniqueKey>
<types>
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="text" class="solr.TextField" />
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
</types>
</schema>
YellowPages的實例已經配置完成.現在開始配置多核的SolrCloud,在使用多核的SolrCloud的時候.我們不再使用編寫tomcat的文件的方式來指定zookeeper來上傳文件.而是指定Solr的工作目錄即可.這裏需要用到solr自帶的工具.先用example自帶的包來解壓運行一下solr.以生成需要的配置文件
[root@localhost example]# java -jar start.jar
進入cloud-scripts目錄
[root@localhost cloud-scripts]# ./zkcli.sh -zkhost 192.168.39.250:2281 -cmd bootstrap -solrhome /usr/local/solrTest/testData/
上傳Solr的根目錄 Solr在加載的時候會依據根目錄內的多個集合的屬性來初始化配置文件
修改Tomcat的文件,僅僅指定Shard的數量 ZK的機器以及服務的端口
[root@localhost bin]# vi catalina.sh
JAVA_OPTS="$JAVA_OPTS -DnumShards=2 -DzkHost=192.168.39.250:2281 -Djetty.port=8080"
將配置好的YellowPages的實例複製到其他的機器上.由於其他機器的catalina.sh沒有變動.則不用修改
先後啓動250,251,252 即可看到
6.2 SolrJ操作SolrCloud
SolrJ操作Solr和操作SolrCould並沒有太多的區別.這裏就以SolrCould爲例子來說明.SolrJ操作的時候和上面說的URL的方式也非常的類似.提供的功能也很相像,也就是索引方面的添加,刪除,更新,提交和優化.但是默認情況下只要索引中有這條記錄,就會覆蓋原有的.標記是否存在索引記錄的字段就是唯一字段,一般是(ID).
搭建環境.
新建一個項目,並且Copy必須的包到項目內.
solr-solrj-4.4.0.jar Solr對Java的接口類
solr-core-4.4.0.jar Solr的核心包
solrj-lib/zookeeper-3.4.5.jar zookeeper的工具包
//httpClient的組件,用於網絡請求(HTTP POST GET)
solrj-lib/commons-io-2.1.jar
solrj-lib/httpclient-4.2.3.jar
solrj-lib/httpcore-4.2.2.jar
solrj-lib/httpmime-4.2.3.jar
//日誌包
solrj-lib/jcl-over-slf4j-1.6.6.jar
solrj-lib/jul-to-slf4j-1.6.6.jar
solrj-lib/log4j-1.2.16.jar
solrj-lib/slf4j-api-1.6.6.jar
solrj-lib/slf4j-log4j12-1.6.6.jar
//雜項
solrj-lib/noggit-0.5.jar
solrj-lib/wstx-asl-3.2.7.jar
數據文件
京翰1對1輔導 中小學課外輔導專家
北京京翰英才教育科技有限公司
4008116268-2880
提高記憶力3-5倍,讓學習更輕鬆、快樂、高效
新腦力教育
13965121806
合肥博強教育管理諮詢有限公司
合肥劉博士數理化一對一、精品小班、藝術生文化課快速提分
4008806400
尚助教育輔導中心
合肥寧國路
13966662351
新腦力教育
合肥天鵝湖
13965121809
實例代碼
IndexAPI.java
package com.iflytek.test.solr.core;
import java.io.IOException;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import com.iflytek.test.solr.conf.Constent;
import com.iflytek.test.solr.data.ContactInfo;
public class IndexAPI {
private CloudSolrServer server = null;
/**
* 添加索引
* */
public boolean addIndex(ContactInfo info){
//如果不是SolrCloud 則類似下面的寫法
//HttpSolrServer server = new HttpSolrServer("http://localhost:8983/solr");
try{
if(server==null){
server = new CloudSolrServer(Constent.ZKHOST);
server.setDefaultCollection(Constent.COLLECTION);
}
}catch(Exception e){
//日誌
return false;
}
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", info.get_id());
doc.addField("name", info.getName());
doc.addField("address", info.getAddress());
doc.addField("phone", info.getPhone());
try {
server.add(doc);
server.commit();
//也可以選擇不提交等後期一起提交
server.optimize();
//索引優化 也不是必須的
} catch (SolrServerException e) {
//日誌
return false;
} catch (IOException e) {
//日誌
return false;
}
return true;
}
/**
* 查詢索引
* @param q 查詢條件 具體的構建過程交給外部去做
* */
public SolrDocumentList searchIndex(String q){
//如果不是SolrCloud 則類似下面的寫法
//HttpSolrServer server = new HttpSolrServer("http://localhost:8983/solr");
try{
if(server==null){
server = new CloudSolrServer(Constent.ZKHOST);
server.setDefaultCollection(Constent.COLLECTION);
}
}catch(Exception e){
//日誌
return null;
}
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("q", q);
params.set("start", 0);
params.set("row", 10);
//這裏實際上就是請求的URL的拼接過程
QueryResponse response = null;
try {
response = server.query(params);
} catch (SolrServerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SolrDocumentList results = response.getResults();
return results;
}
/**
* 按查詢結果刪除索引.還支持按ID刪除,批量刪除等.
* @param q 要刪除的查詢語句
* */
public boolean delIndex(String q){
//如果不是SolrCloud 則類似下面的寫法
//HttpSolrServer server = new HttpSolrServer("http://localhost:8983/solr");
try{
if(server==null){
server = new CloudSolrServer(Constent.ZKHOST);
server.setDefaultCollection(Constent.COLLECTION);
}
}catch(Exception e){
return false;
}
try {
server.deleteByQuery(q);
server.commit();
} catch (SolrServerException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
}
CreateData.java
package com.iflytek.test.solr.core.test;
import gg.mine.tools.io.local.ReadFileByLine;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import com.iflytek.test.solr.core.IndexAPI;
import com.iflytek.test.solr.data.ContactInfo;
public class CreateData {
/**
* 讀取文件並轉換爲聯繫人列表
* @param file 文件名
* @return 返回聯繫人的List
* */
private static List<ContactInfo> fileToDataList(String file){
ArrayList<String> lines = ReadFileByLine.getAllLine2Array(file);
List<ContactInfo> result = new LinkedList<ContactInfo>();
for(int index=0;index<lines.size();index=index+3){
ContactInfo instance = new ContactInfo();
instance.setName(lines.get(index));
instance.setAddress(lines.get(index+1));
instance.addPhone(lines.get(index+2));
result.add(instance);
}
return result;
}
public static void main(String []a){
List<ContactInfo> list = fileToDataList("data/ContactInfo");
if(list==null){
return;
}
IndexAPI indexer = new IndexAPI();
for(ContactInfo info:list){
if(indexer.addIndex(info)){
System.out.println("添加成功!");
}else{
System.err.println("添加失敗!"+info.getName());
}
}
}
}
添加後訪問 http://192.168.39.250:8080/solr/YellowPages/select?q=%3A&wt=json&indent=true 即可看到添加成功
SearchIndex.java
package com.iflytek.test.solr.core.test;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import com.iflytek.test.solr.core.IndexAPI;
public class SearchIndex {
private static void printDocument(String q,SolrDocumentList list){
System.out.println("查詢語句: "+q+"\n\n");
if(list==null){
return;
}
for(SolrDocument cur:list){
System.out.println("名字 "+cur.getFieldValue("name"));
System.out.println("地址 "+cur.getFieldValue("address"));
System.out.println("電話 "+cur.getFieldValue("phone"));
System.out.println();
}
}
public static void main(String []a){
IndexAPI indexer = new IndexAPI();
String q = "all:合肥的數理化輔導班";
SolrDocumentList list = indexer.searchIndex(q);
printDocument(q,list);
q = "all:北京的輔導班";
list = indexer.searchIndex(q);
printDocument(q,list);
q = "all:13965121809是誰的電話";
list = indexer.searchIndex(q);
printDocument(q,list);
}
}
運行結果
查詢語句: all:合肥的數理化輔導班
名字 合肥博強教育管理諮詢有限公司
地址 合肥劉博士數理化一對一、精品小班、藝術生文化課快速提分
電話 [4008806400]
名字 尚助教育輔導中心
地址 合肥寧國路
電話 [13966662351]
名字 新腦力教育
地址 合肥天鵝湖
電話 [13965121809]
名字 京翰1對1輔導 中小學課外輔導專家
地址 北京京翰英才教育科技有限公司
電話 [4008116268-2880]
查詢語句: all:北京的輔導班
名字 尚助教育輔導中心
地址 合肥寧國路
電話 [13966662351]
名字 京翰1對1輔導 中小學課外輔導專家
地址 北京京翰英才教育科技有限公司
電話 [4008116268-2880]
查詢語句: all:13965121809是誰的電話
名字 新腦力教育
地址 合肥天鵝湖
電話 [13965121809]
package com.iflytek.test.solr.core.test;
import com.iflytek.test.solr.core.IndexAPI;
public class DelIndex {
public static void main(String []a){
IndexAPI indexer = new IndexAPI();
indexer.delIndex("id:2212087180485603235");
/**
*{
"id": "2212087180485603235",
"name": "提高記憶力3-5倍,讓學習更輕鬆、快樂、高效",
"address": "新腦力教育",
"phone": [
"13965121806\t"
],
"_version_": 1447136747670470700
},
*
* */
}
}
注意:在真實環境中 沒有必要每個請求都commit 和 optimize,這兩個操作都是比較耗時的.具體可以依據生產環境來決定多長時間commit一次
7 Solr管理
Solr在搭建成功後會提供一個管理頁面.也就是上面截圖中看到的
包括
Dashboard 儀表盤,可以看到系統的運行狀態,JVM參數等
Logging 系統日誌.可以看到警告,提示信息.
Logging/Level 對日誌級別的設置.即上面級別的日誌可以被記錄Log
Cloud /Graph 雲監控平臺,可以看到有哪些Collection部署在哪些機器上,及分片和主從的信息
Cloud/Tree 配置文件的樹信息
Cloud/dump JSON格式返回服務器的狀態信息
Core Admin 核心(Collection)的配置信息
JavaProperties Java的運行參數
Thread 線程的堆棧信息
集合頁面
OverView 運行信息.可以在這個頁面上優化索引
Analysis 分詞界面.可以測試分詞效果
Config 顯示配置文件SolrConfig.xml
Document 追加/修改文檔
plugins 顯示加載的插件及插件狀態
Query 查詢頁面
Replication 是否已經數據備份
Schema 字段信息schema.xml
SchemaBrowser 以UI查看字段和類型信息