出處:http://www.cnblogs.com/hoojo/archive/2011/10/21/2220431.htmlhtml
Solr 是一種可供企業使用的、基於 Lucene 的搜索服務器,它支持層面搜索、命中醒目顯示和多種輸出格式。在這篇文章中,將介紹 Solr 並展現如何輕鬆地將其表現優異的全文本搜索功能加入到 Web 應用程序中。java
開發環境:web
System:Windows算法
WebBrowser:IE6+、Firefox3+apache
JDK:1.6+json
JavaEE Server:tomcat5.0.2.八、tomcat6api
IDE:eclipse、MyEclipse 8緩存
開發依賴庫:tomcat
JavaEE 五、solr 3.4ruby
我的博客:
http://blog.csdn.net/IBM_hoojo
email: hoojo_@126.com
一、 首先去apache官方網站下載solr,下載地址
http://labs.renren.com/apache-mirror//lucene/solr/3.4.0/
目前最新的是3.4的版本
二、 下載後解壓目錄以下
client是一個ruby實現的示例,這個咱們暫時無論
contrib有一些功能模塊是須要的jar包
dist是打包發佈好的工程war包
docs是幫助文檔
example是示例,裏面有打包部署好的solr工程示例和servlet容器jetty。若是你沒有tomcat能夠直接使用Jetty服務器部署你的solr示例。
三、 發佈、部署solr示例
A、 利用自帶的Jetty服務器
首先在dos命令中進入到下載好的solr解壓的目錄apache-solr-3.4.0的example目錄
cd E:\JAR\solr\apache-solr-3.4.0\example
而後利用java命令,啓動jetty服務器。Java –jar start.jar
啓動Jetty成功後,若是沒有看到錯誤消息,你能夠看到端口信息。
若是你的端口衝突了,你能夠到解壓的solr示例包的example/etc的jetty.xml中,修改端口port信息。
<Set name="port">
<SystemProperty name="jetty.port" default="8983"/>
</Set>
B、 利用tomcat發佈solr示例
將下載的solr解壓後,進入apache-solr-3.4.0\dist目錄,將裏面的solr.war放到D:\tomcat-6.0.28\webapps目錄下,啓動tomcat會自動解壓。(固然,你也能夠手動解壓放到wabapps目錄下)
固然你也能夠設置context指向你的solr工程,在D:\tomcat-6.0.28\conf\Catalina\localhost目錄加入solr.xml配置,配置以下:
<Context docBase="D:\solr.war" debug="0" crossContext="true" >
<Environment name="solr/home" type="java.lang.String" value="D:\solr" override="true" />
</Context>
上面的2步都是同樣的,這樣尚未完。啓動後你可能會看到以下錯誤:
咱們須要將一些配置和index庫文件也放到解壓好的solr工程下。咱們到解壓的apache-solr-3.4.0\example\solr目錄下,將裏面的conf和data目錄copy到剛纔咱們部署的D:\tomcat-6.0.28\webapps\solr工程目錄下。或是copy到你的solr.xml中的context指定的路徑下工程目錄中。
重啓tomcat就ok了。
四、 這個時候你就能夠訪問http://localhost:8983/solr/admin/你就能夠看到以下界面:
在Query String中輸入solr,點擊Search就能夠查詢到相應的結果,結果以xml形式返回。固然你也能夠設置返回數據類型爲json。
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
<int name="status">0</int>
<int name="QTime">0</int>
<lst name="params">
<str name="indent">on</str>
<str name="start">0</str>
<str name="q">solr</str>
<str name="version">2.2</str>
<str name="rows">10</str>
</lst>
</lst>
<result name="response" numFound="1" start="0">
<doc>
<arr name="cat"><str>software</str><str>search</str></arr>
<arr name="features"><str>Advanced Full-Text Search Capabilities using Lucene</str><str>Optimized for High Volume Web Traffic</str><str>Standards Based Open Interfaces - XML and HTTP</str>
<str>Comprehensive HTML Administration Interfaces</str><str>Scalability - Efficient Replication to other Solr Search Servers</str><str>Flexible and Adaptable with XML configuration and Schema</str><str>Good unicode support: h¨¦llo (hello with an accent over the e)</str></arr>
<str name="id">SOLR1000</str>
<bool name="inStock">true</bool>
<date name="incubationdate_dt">2006-01-17T00:00:00Z</date>
<str name="manu">Apache Software Foundation</str>
<str name="name">Solr, the Enterprise Search Server</str>
<int name="popularity">10</int>
<float name="price">0.0</float>
</doc>
</result>
</response>
一、 solr基礎
由於 Solr 包裝並擴展了 Lucene,因此它們使用不少相同的術語。更重要的是,Solr 建立的索引與 Lucene 搜索引擎庫徹底兼容。經過對 Solr 進行適當的配置,某些狀況下可能須要進行編碼,Solr 能夠閱讀和使用構建到其餘 Lucene 應用程序中的索引。
在 Solr 和 Lucene 中,使用一個或多個 Document 來構建索引。Document 包括一個或多個 Field。Field 包括名稱、內容以及告訴 Solr 如何處理內容的元數據。例如,Field 能夠包含字符串、數字、布爾值或者日期,也能夠包含你想添加的任何類型,只需用在solr的配置文件中進行相應的配置便可。Field 可使用大量的選項來描述,這些選項告訴 Solr 在索引和搜索期間如何處理內容。如今,查看一下表 1 中列出的重要屬性的子集:
屬性名稱 |
描述 |
Indexed |
Indexed Field 能夠進行搜索和排序。你還能夠在 indexed Field 上運行 Solr 分析過程,此過程可修改內容以改進或更改結果。 |
Stored |
stored Field 內容保存在索引中。這對於檢索和醒目顯示內容頗有用,但對於實際搜索則不是必需的。例如,不少應用程序存儲指向內容位置的指針而不是存儲實際的文件內容。 |
二、 solr索引操做
在 Solr 中,經過向部署在 servlet 容器中的 Solr Web 應用程序發送 HTTP 請求來啓動索引和搜索。Solr 接受請求,肯定要使用的適當 SolrRequestHandler,而後處理請求。經過 HTTP 以一樣的方式返回響應。默認配置返回 Solr 的標準 XML 響應。你也能夠配置 Solr 的備用響應格式,如json、csv格式的文本。
索引就是接受輸入元數據(數據格式在schema.xml中進行配置)並將它們傳遞給 Solr,從而在 HTTP Post XML 消息中進行索引的過程。你能夠向 Solr 索引 servlet 傳遞四個不一樣的索引請求:
add/update 容許您向 Solr 添加文檔或更新文檔。直到提交後才能搜索到這些添加和更新。
commit 告訴 Solr,應該使上次提交以來所作的全部更改均可以搜索到。
optimize 重構 Lucene 的文件以改進搜索性能。索引完成後執行一下優化一般比較好。若是更新比較頻繁,則應該在使用率較低的時候安排優化。一個索引無需優化也能夠正常地運行。優化是一個耗時較多的過程。
delete 能夠經過 id 或查詢來指定。按 id 刪除將刪除具備指定 id 的文檔;按查詢刪除將刪除查詢返回的全部文檔。
Lucene中操做索引也有這幾個步驟,可是沒有更新。Lucene更新是先刪除,而後添加索引。由於更新索引在必定狀況下,效率沒有先刪除後添加的效率好。
三、 搜索
添加文檔後,就能夠搜索這些文檔了。Solr 接受 HTTP GET 和 HTTP POST 查詢消息。收到的查詢由相應的 SolrRequestHandler 進行處理。
solr查詢參數描述:
參數 |
描述 |
示例 |
q |
Solr 中用來搜索的查詢。有關該語法的完整描述,請參閱 參考資料。能夠經過追加一個分號和已索引且未進行斷詞的字段(下面會進行解釋)的名稱來包含排序信息。默認的排序是 score desc,指按記分降序排序。 |
q=myField:Java AND otherField:developerWorks; date asc 此查詢搜索指定的兩個字段,並根據一個日期字段對結果進行排序。 |
start |
將初始偏移量指定到結果集中。可用於對結果進行分頁。默認值爲 0。 |
start=15 返回從第 15 個結果開始的結果。 |
rows |
返回文檔的最大數目。默認值爲 10。 |
rows=25,返回25個結果集 |
fq |
提供一個可選的篩選器查詢。查詢結果被限制爲僅搜索篩選器查詢返回的結果。篩選過的查詢由 Solr 進行緩存。它們對提升複雜查詢的速度很是有用。 |
任何能夠用 q 參數傳遞的有效查詢,排序信息除外。 |
hl |
當 hl=true 時,在查詢響應中醒目顯示片斷。默認爲 false。參看醒目顯示參數(見 參考資料)。 |
hl=true |
fl |
做爲逗號分隔的列表指定文檔結果中應返回的 Field 集。默認爲 「*」,指全部的字段。「score」 指還應返回記分。 |
*,score |
sort |
排序,對查詢結果進行排序,參考 |
sort=date asc,price desc |
四、 solr模式
上面有提到schema.xml這個配置,這個配置能夠在你下載solr包的安裝解壓目錄的apache-solr-3.4.0\example\solr\conf中找到,它就是solr模式關聯的文件。打開這個配置文件,你會發現有詳細的註釋。
模式組織主要分爲三個重要配置
types 部分是一些常見的可重用定義,定義了 Solr(和 Lucene)如何處理 Field。也就是添加到索引中的xml文件屬性中的類型,如int、text、date等
fileds是你添加到索引文件中出現的屬性名稱,而聲明類型就須要用到上面的types
其餘配置有
uniqueKey 惟一鍵,這裏配置的是上面出現的fileds,通常是id、url等不重複的。在更新、刪除的時候能夠用到。
defaultSearchField默認搜索屬性,如q=solr就是默認的搜索那個字段
solrQueryParser查詢轉換模式,是而且仍是或者(and/or)
schema配置類型
<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.WhitespaceTokenizerFactory" />
<filter class="solr.StopFilterFactory" ignoreCase="true"
words="stopwords.txt" />
<filter class="solr.WordDelimiterFilterFactory"
generateWordParts="1" generateNumberParts="1" catenateWords="1"
catenateNumbers="1" catenateAll="0" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt" />
<filter class="solr.RemoveDuplicatesTokenFilterFactory" />
</analyzer>
<analyzer type="query">
<tokenizer class="solr.WhitespaceTokenizerFactory" />
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt"
ignoreCase="true" expand="true" />
<filter class="solr.StopFilterFactory" ignoreCase="true"
words="stopwords.txt" />
<filter class="solr.WordDelimiterFilterFactory"
generateWordParts="1" generateNumberParts="1" catenateWords="0"
catenateNumbers="0" catenateAll="0" />
<filter class="solr.LowerCaseFilterFactory" />
<filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt" />
<filter class="solr.RemoveDuplicatesTokenFilterFactory" />
</analyzer>
</fieldType>
上面就是一個type了,而後你在fields配置field的時候就能夠用這個type。
首先,上面的fieldType的配置中有兩個analyzer,它是分詞器。主要把咱們的數據進行分割成一個個的詞語。詞幹提取、中止詞刪除以及類似的操做都被應用於標記,而後才進行索引和搜索,致使使用相同類型的標記。
上面的應用程序的 Solr 的fieldType配置按如下步驟進行設置:
Ø 根據空白進行斷詞,而後刪除全部的公共詞(StopFilterFactory)
Ø 使用破折號處理特殊的大小寫、大小寫轉換等等。(WordDelimiterFilterFactory);將全部條目處理爲小寫(LowerCaseFilterFactory)
Ø 使用 Porter Stemming 算法進行詞幹提取(EnglishPorterFilterFactory)
Ø 刪除全部的副本(RemoveDuplicatesTokenFilterFactory)
Schema屬性、字段
<field name="id" type="string" indexed="true" stored="true"
required="true" />
<field name="sku" type="text_en_splitting_tight" indexed="true"
stored="true" omitNorms="true" />
<field name="name" type="text_general" indexed="true" stored="true" />
<field name="alphaNameSort" type="alphaOnlySort" indexed="true"
stored="false" />
<field name="manu" type="text_general" indexed="true" stored="true"
omitNorms="true" />
<field name="cat" type="string" indexed="true" stored="true"
multiValued="true" />
<field name="features" type="text_general" indexed="true" stored="true"
multiValued="true" />
<field name="includes" type="text_general" indexed="true" stored="true"
termVectors="true" termPositions="true" termOffsets="true" />
屬性是在添加索引、查詢的時候必須的配置,若是你不加這些配置。是沒法完成索引的建立的。
首先id屬性是未經分析的字符串類型,是能夠索引、存儲的,而且是惟一的。
sku是一個通過分詞器分析出來的英文切割的類型字符,能夠索引、存儲、不要存儲規範
multiValued 屬性是一個特殊的例子,指 Document 能夠擁有一個相同名稱添加了屢次的 Field。
omitNorms 屬性告訴 Solr(和 Lucene)不要存儲規範。
介紹一下字段聲明下方的 <dynamicField> 聲明。動態字段是一些特殊類型的字段,能夠在任什麼時候候將這些字段添加到任何文檔中,由字段聲明定義它們的屬性。動態字段和普通字段之間的關鍵區別在於前者不須要在 schema.xml 中提早聲明名稱。Solr 將名稱聲明中的 glob-like 模式應用到全部還沒有聲明的引入的字段名稱,並根據其 <dynamicField> 聲明定義的語義來處理字段。例如,<dynamicField name="*_i" type="sint" indexed="true" stored="true"/> 指一個 myRating_i 字段被 Solr 處理爲 sint,儘管並未將其聲明爲字段。這種處理比較方便,例如,當須要用戶定義待搜索內容的時候。
五、 索引配置
Solr 性能因素,來了解與各類更改相關的性能權衡。
表 1 歸納了可控制 Solr 索引處理的各類因素:
因素 |
描述 |
useCompoundFile |
經過將不少 Lucene 內部文件整合到單一一個文件來減小使用中的文件的數量。這可有助於減小 Solr 使用的文件句柄數目,代價是下降了性能。除非是應用程序用完了文件句柄,不然 false 的默認值應該就已經足夠。 |
mergeFactor |
決定低水平的 Lucene 段被合併的頻率。較小的值(最小爲 2)使用的內存較少但致使的索引時間也更慢。較大的值可以使索引時間變快但會犧牲較多的內存。 |
maxBufferedDocs |
在合併內存中文檔和建立新段以前,定義所需索引的最小文檔數。段 是用來存儲索引信息的 Lucene 文件。較大的值可以使索引時間變快但會犧牲較多的內存。 |
maxMergeDocs |
控制可由 Solr 合併的 Document 的最大數。較小的值 (< 10,000) 最適合於具備大量更新的應用程序。 |
maxFieldLength |
對於給定的 Document,控制可添加到 Field 的最大條目數,進而截斷該文檔。若是文檔可能會很大,就須要增長這個數值。然而,若將這個值設置得太高會致使內存不足錯誤。 |
unlockOnStartup |
unlockOnStartup 告知 Solr 忽略在多線程環境中用來保護索引的鎖定機制。在某些狀況下,索引可能會因爲不正確的關機或其餘錯誤而一直處於鎖定,這就妨礙了添加和更新。將其設置爲 true 能夠禁用啓動鎖定,進而容許進行添加和更新。 |
六、 查詢處理配置
<maxBooleanClauses> 標記定義了可組合在一塊兒造成一個查詢的子句數量的上限。對於大多數應用程序而言,默認的 1024 就應該已經足夠;然而,若是應用程序大量使用了通配符或範圍查詢,增長這個限值將能避免當值超出時,拋出 TooManyClausesException。
若應用程序預期只會檢索 Document 上少數幾個 Field,那麼能夠將 <enableLazyFieldLoading> 屬性設置爲 true。懶散加載的一個常見場景大都發生在應用程序返回和顯示一系列搜索結果的時候,用戶經常會單擊其中的一個來查看存儲在此索引中的原始文檔。初始的顯示經常只須要顯示很短的一段信息。若考慮到檢索大型 Document 的代價,除非必需,不然就應該避免加載整個文檔。
<query> 部分負責定義與在 Solr 中發生的事件相關的幾個選項。Searcher 的 Java 類來處理 Query 實例。要改進這一設計和顯著提升性能,把這些新的 Searcher 聯機以便爲現場用戶提供查詢服務以前,先對它們進行 「熱身」。<query> 部分中的 <listener> 選項定義 newSearcher 和 firstSearcher 事件,您可使用這些事件來指定實例化新搜索程序或第一個搜索程序時應該執行哪些查詢。若是應用程序指望請求某些特定的查詢,那麼在建立新搜索程序或第一個搜索程序時就應該反註釋這些部分並執行適當的查詢。
solrconfig.xml 文件的剩餘部分,除 <admin> 以外,涵蓋了與 緩存、複製 和 擴展或定製 Solr 有關的項目。admin 部分讓您能夠定製管理界面。有關配置 admin 節的更多信息,請參看solrconfig.xml 文件中的註釋。
七、 監視、記錄和統計數據
用於監視、記錄和統計數據的 Solr 管理選項
菜單名 |
URL |
描述 |
Statistics |
Statistics 管理頁提供了與 Solr 性能相關的不少有用的統計數據。這些數據包括: 關於什麼時候加載索引以及索引中有多少文檔的信息。 關於用來服務查詢的 SolrRequestHandler 的有用信息。 涵蓋索引過程的數據,包括添加、刪除、提交等的數量。 緩存實現和 hit/miss/eviction 信息 |
|
Info |
有關正在運行的 Solr 的版本以及在當前實現中進行查詢、更新和緩存所使用的類的詳細信息。此外,還包括文件存於 Solr subversion 存儲庫的何處的信息以及對該文件功能的一個簡要描述。 |
|
Distribution |
顯示與索引起布和複製有關的信息。更多信息,請參見 「發佈和複製」 一節。 |
|
Ping |
向服務器發出 ping 請求,包括在 solrconfig.xml 文件的 admin 部分定義的請求。 |
|
Logging |
讓您能夠動態更改當前應用程序的日誌記錄等級。更改日誌記錄等級對於調試在執行過程當中可能出現的問題很是有用。 |
|
properties |
http: //localhost:8080/solr/admin/get-properties.jsp |
顯示當前系統正在使用的全部 Java 系統屬性。Solr 支持經過命令行的系統屬性替換。有關實現此特性的更多信息,請參見 solrconfig.xml 文件。 |
Thread dump |
http://localhost:8080/solr/admin/threaddump.jsp |
thread dump 選項顯示了在 JVM 中運行的全部線程的堆棧跟蹤信息。 |
八、 智能緩存
智能緩存是讓 Solr 得以成爲引人矚目的搜索服務器的一個關鍵性能特徵。Solr 提供了四種不一樣的緩存類型,全部四種類型均可在 solrconfig.xml 的 <query> 部分中配置。solrconfig.xml 文件中所用的標記名列出了這些緩存類型:
緩存標記名 |
描述 |
可否自熱 |
filterCache |
經過存儲一個匹配給定查詢的文檔 id 的無序集,過濾器讓 Solr 可以有效提升查詢的性能。緩存這些過濾器意味着對 Solr 的重複調用能夠致使結果集的快速查找。更常見的場景是緩存一個過濾器,而後再發起後續的精煉查詢,這種查詢能使用過濾器來限制要搜索的文檔數。 |
能夠 |
queryResultCache |
爲查詢、排序條件和所請求文檔的數量緩存文檔 id 的有序 集合。 |
能夠 |
documentCache |
緩存 Lucene Document,使用內部 Lucene 文檔 id(以便不與 Solr 唯一 id 相混淆)。因爲 Lucene 的內部 Document id 能夠因索引操做而更改,這種緩存不能自熱。 |
不能夠 |
Named caches |
命名緩存是用戶定義的緩存,可被 Solr 定製插件 所使用。 |
能夠, 若是實現了 org.apache.solr.search.CacheRegenerator 的話。 |
每一個緩存聲明都接受最多四個屬性:
class 是緩存實現的 Java 名。
size 是最大的條目數。
initialSize 是緩存的初始大小。
autoWarmCount 是取自舊緩存以預熱新緩存的條目數。若是條目不少,就意味着緩存的 hit 會更多,只不過須要花更長的預熱時間。
使用SolrJ操做Solr會比利用httpClient來操做Solr要簡單。SolrJ是封裝了httpClient方法,來操做solr的API的。SolrJ底層仍是經過使用httpClient中的方法來完成Solr的操做。
一、 首先,你須要添加以下jar包
其中apache-solr-solrj-3.4.0.jar、slf4j-api-1.6.1.jar能夠在下載的apache-solr-3.4.0的壓縮包中的dist中能找到。
二、 其次,創建一個簡單的測試類,完成Server對象的相關方法的測試工做,代碼以下:
package com.hoo.test;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.hoo.entity.Index;
/**
* <b>function:</b> Server TestCase
* @author hoojo
* @createDate 2011-10-19 下午01:49:07
* @file ServerTest.java
* @package com.hoo.test
* @project SolrExample
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class ServerTest {
private SolrServer server;
private CommonsHttpSolrServer httpServer;
private static final String DEFAULT_URL = "http://localhost:8983/solr/";
@Before
public void init() {
try {
server = new CommonsHttpSolrServer(DEFAULT_URL);
httpServer = new CommonsHttpSolrServer(DEFAULT_URL);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@After
public void destory() {
server = null;
httpServer = null;
System.runFinalization();
System.gc();
}
public final void fail(Object o) {
System.out.println(o);
}
/**
* <b>function:</b> 測試是否建立server對象成功
* @author hoojo
* @createDate 2011-10-21 上午09:48:18
*/
@Test
public void server() {
fail(server);
fail(httpServer);
}
/**
* <b>function:</b> 根據query參數查詢索引
* @author hoojo
* @createDate 2011-10-21 上午10:06:39
* @param query
*/
public void query(String query) {
SolrParams params = new SolrQuery(query);
try {
QueryResponse response = server.query(params);
SolrDocumentList list = response.getResults();
for (int i = 0; i < list.size(); i++) {
fail(list.get(i));
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
}
測試運行server case方法,若是成功建立對象,那你就成功的連接到。
注意:在運行本方法以前,請啓動你的solr官方自動的項目。http://localhost:8983/solr/保證可以成功訪問這個工程。由於接下來的全部工做都是圍繞這個solr工程完成的。若是你如今還不知道,怎麼部署、發佈官方solr工程,請參考前面的具體章節。
三、 Server的有關配置選項參數,server是CommonsHttpSolrServer的實例
server.setSoTimeout(1000); // socket read timeout
server.setConnectionTimeout(100);
server.setDefaultMaxConnectionsPerHost(100);
server.setMaxTotalConnections(100);
server.setFollowRedirects(false); // defaults to false
// allowCompression defaults to false.
// Server side must support gzip or deflate for this to have any effect.
server.setAllowCompression(true);
server.setMaxRetries(1); // defaults to 0. > 1 not recommended.
//sorlr J 目前使用二進制的格式做爲默認的格式。對於solr1.2的用戶經過顯示的設置才能使用XML格式。
server.setParser(new XMLResponseParser());
//二進制流輸出格式
//server.setRequestWriter(new BinaryRequestWriter());
四、 利用SolrJ完成Index Document的添加操做
/**
* <b>function:</b> 添加doc文檔
* @author hoojo
* @createDate 2011-10-21 上午09:49:10
*/
@Test
public void addDoc() {
//建立doc文檔
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", 1);
doc.addField("name", "Solr Input Document");
doc.addField("manu", "this is SolrInputDocument content");
try {
//添加一個doc文檔
UpdateResponse response = server.add(doc);
fail(server.commit());//commit後才保存到索引庫
fail(response);
fail("query time:" + response.getQTime());
fail("Elapsed Time:" + response.getElapsedTime());
fail("status:" + response.getStatus());
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
query("name:solr");
}
在apache-solr-3.4.0\example\solr\conf目錄下的schema.xml中能夠找到有關於field屬性的配置,schema.xml中的field就和上面Document文檔中的field(id、name、manu)對應。若是出現ERROR:unknown field 'xxxx'就表示你設置的這個field在schema.xml中不存在。若是必定要使用這個field,請你在schema.xml中進行filed元素的配置。具體請參考前面的章節。
注意:在schema.xml中配置了uniqueKey爲id,就表示id是惟一的。若是在添加Document的時候,id重複添加。那麼後面添加的相同id的doc會覆蓋前面的doc,相似於update更新操做,而不會出現重複的數據。
五、 利用SolrJ添加多個Document,即添加文檔集合
/**
* <b>function:</b> 添加docs文檔集合
* @author hoojo
* @createDate 2011-10-21 上午09:55:01
*/
@Test
public void addDocs() {
Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", 2);
doc.addField("name", "Solr Input Documents 1");
doc.addField("manu", "this is SolrInputDocuments 1 content");
docs.add(doc);
doc = new SolrInputDocument();
doc.addField("id", 3);
doc.addField("name", "Solr Input Documents 2");
doc.addField("manu", "this is SolrInputDocuments 3 content");
docs.add(doc);
try {
//add docs
UpdateResponse response = server.add(docs);
//commit後才保存到索引庫
fail(server.commit());
fail(response);
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
query("solr");
}
就是添加一個List集合
六、 添加JavaEntity Bean,這個須要先建立一個JavaBean,而後來完成添加操做;
JavaBean:Index的代碼
package com.hoo.entity;
import org.apache.solr.client.solrj.beans.Field;
/**
* <b>function:</b> JavaEntity Bean;Index須要添加相關的Annotation註解,便於告訴solr哪些屬性參與到index中
* @author hoojo
* @createDate 2011-10-19 下午05:33:27
* @file Index.java
* @package com.hoo.entity
* @project SolrExample
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class Index {
//@Field setter方法上添加Annotation也是能夠的
private String id;
@Field
private String name;
@Field
private String manu;
@Field
private String[] cat;
@Field
private String[] features;
@Field
private float price;
@Field
private int popularity;
@Field
private boolean inStock;
public String getId() {
return id;
}
@Field
public void setId(String id) {
this.id = id;
}
//getter、setter方法
public String toString() {
return this.id + "#" + this.name + "#" + this.manu + "#" + this.cat;
}
}
注意上面的屬性是和在apache-solr-3.4.0\example\solr\conf目錄下的schema.xml中能夠找到有關於field屬性的配置對應的。若是你Index JavaBean中出現的屬性在schema.xml的field配置沒法找到,那麼出出現unknown filed錯誤。
添加Bean完成doc添加操做
/**
* <b>function:</b> 添加JavaEntity Bean
* @author hoojo
* @createDate 2011-10-21 上午09:55:37
*/
@Test
public void addBean() {
//Index須要添加相關的Annotation註解,便於告訴solr哪些屬性參與到index中
Index index = new Index();
index.setId("4");
index.setName("add bean index");
index.setManu("index bean manu");
index.setCat(new String[] { "a1", "b2" });
try {
//添加Index Bean到索引庫
UpdateResponse response = server.addBean(index);
fail(server.commit());//commit後才保存到索引庫
fail(response);
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
queryAll();
}
七、 添加Bean集合
/**
* <b>function:</b> 添加Entity Bean集合到索引庫
* @author hoojo
* @createDate 2011-10-21 上午10:00:55
*/
@Test
public void addBeans() {
Index index = new Index();
index.setId("6");
index.setName("add beans index 1");
index.setManu("index beans manu 1");
index.setCat(new String[] { "a", "b" });
List<Index> indexs = new ArrayList<Index>();
indexs.add(index);
index = new Index();
index.setId("5");
index.setName("add beans index 2");
index.setManu("index beans manu 2");
index.setCat(new String[] { "aaa", "bbbb" });
indexs.add(index);
try {
//添加索引庫
UpdateResponse response = server.addBeans(indexs);
fail(server.commit());//commit後才保存到索引庫
fail(response);
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
queryAll();
}
八、 刪除索引Document
/**
* <b>function:</b> 刪除索引操做
* @author hoojo
* @createDate 2011-10-21 上午10:04:28
*/
@Test
public void remove() {
try {
//刪除id爲1的索引
server.deleteById("1");
server.commit();
query("id:1");
//根據id集合,刪除多個索引
List<String> ids = new ArrayList<String>();
ids.add("2");
ids.add("3");
server.deleteById(ids);
server.commit(true, true);
query("id:3 id:2");
//刪除查詢到的索引信息
server.deleteByQuery("id:4 id:6");
server.commit(true, true);
queryAll();
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
九、 查詢索引
/**
* <b>function:</b> 查詢全部索引信息
* @author hoojo
* @createDate 2011-10-21 上午10:05:38
*/
@Test
public void queryAll() {
ModifiableSolrParams params = new ModifiableSolrParams();
// 查詢關鍵詞,*:*表明全部屬性、全部值,即全部index
params.set("q", "*:*");
// 分頁,start=0就是從0開始,,rows=5當前返回5條記錄,第二頁就是變化start這個值爲5就能夠了。
params.set("start", 0);
params.set("rows", Integer.MAX_VALUE);
// 排序,,若是按照id 排序,,那麼將score desc 改爲 id desc(or asc)
params.set("sort", "score desc");
// 返回信息 * 爲所有 這裏是所有加上score,若是不加下面就不能使用score
params.set("fl", "*,score");
try {
QueryResponse response = server.query(params);
SolrDocumentList list = response.getResults();
for (int i = 0; i < list.size(); i++) {
fail(list.get(i));
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
十、 其餘和Server有關方法
/**
* <b>function:</b> 其餘server相關方法測試
* @author hoojo
* @createDate 2011-10-21 上午10:02:03
*/
@Test
public void otherMethod() {
fail(server.getBinder());
try {
fail(server.optimize());//合併索引文件,能夠優化索引、提供性能,但須要必定的時間
fail(server.ping());//ping服務器是否鏈接成功
Index index = new Index();
index.setId("299");
index.setName("add bean index199");
index.setManu("index bean manu199");
index.setCat(new String[] { "a199", "b199" });
UpdateResponse response = server.addBean(index);
fail("response: " + response);
queryAll();
//回滾掉以前的操做,rollback addBean operation
fail("rollback: " + server.rollback());
//提交操做,提交後沒法回滾以前操做;發現addBean沒有成功添加索引
fail("commit: " + server.commit());
queryAll();
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
十一、 文檔查詢
/**
* <b>function:</b> query 基本用法測試
* @author hoojo
* @createDate 2011-10-20 下午04:44:28
*/
@Test
public void queryCase() {
//AND 而且
SolrQuery params = new SolrQuery("name:apple AND manu:inc");
//OR 或者
params.setQuery("name:apple OR manu:apache");
//空格 等同於 OR
params.setQuery("name:server manu:dell");
//params.setQuery("name:solr - manu:inc");
//params.setQuery("name:server + manu:dell");
//查詢name包含solr apple
params.setQuery("name:solr,apple");
//manu不包含inc
params.setQuery("name:solr,apple NOT manu:inc");
//50 <= price <= 200
params.setQuery("price:[50 TO 200]");
params.setQuery("popularity:[5 TO 6]");
//params.setQuery("price:[50 TO 200] - popularity:[5 TO 6]");
//params.setQuery("price:[50 TO 200] + popularity:[5 TO 6]");
//50 <= price <= 200 AND 5 <= popularity <= 6
params.setQuery("price:[50 TO 200] AND popularity:[5 TO 6]");
params.setQuery("price:[50 TO 200] OR popularity:[5 TO 6]");
//過濾器查詢,能夠提升性能 filter 相似多個條件組合,如and
//params.addFilterQuery("id:VA902B");
//params.addFilterQuery("price:[50 TO 200]");
//params.addFilterQuery("popularity:[* TO 5]");
//params.addFilterQuery("weight:*");
//0 < popularity < 6 沒有等於
//params.addFilterQuery("popularity:{0 TO 6}");
//排序
params.addSortField("id", ORDER.asc);
//分頁:start開始頁,rows每頁顯示記錄條數
//params.add("start", "0");
//params.add("rows", "200");
//params.setStart(0);
//params.setRows(200);
//設置高亮
params.setHighlight(true); // 開啓高亮組件
params.addHighlightField("name");// 高亮字段
params.setHighlightSimplePre("<font color='red'>");//標記,高亮關鍵字前綴
params.setHighlightSimplePost("</font>");//後綴
params.setHighlightSnippets(1);//結果分片數,默認爲1
params.setHighlightFragsize(1000);//每一個分片的最大長度,默認爲100
//分片信息
params.setFacet(true)
.setFacetMinCount(1)
.setFacetLimit(5)//段
.addFacetField("name")//分片字段
.addFacetField("inStock");
//params.setQueryType("");
try {
QueryResponse response = server.query(params);
/*List<Index> indexs = response.getBeans(Index.class);
for (int i = 0; i < indexs.size(); i++) {
fail(indexs.get(i));
}*/
//輸出查詢結果集
SolrDocumentList list = response.getResults();
fail("query result nums: " + list.getNumFound());
for (int i = 0; i < list.size(); i++) {
fail(list.get(i));
}
//輸出分片信息
List<FacetField> facets = response.getFacetFields();
for (FacetField facet : facets) {
fail(facet);
List<Count> facetCounts = facet.getValues();
for (FacetField.Count count : facetCounts) {
System.out.println(count.getName() + ": " + count.getCount());
}
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
十二、 分片查詢、統計
/**
* <b>function:</b> 分片查詢, 能夠統計關鍵字及出現的次數、或是作自動補全提示
* @author hoojo
* @createDate 2011-10-20 下午04:54:25
*/
@Test
public void facetQueryCase() {
SolrQuery params = new SolrQuery("*:*");
//排序
params.addSortField("id", ORDER.asc);
params.setStart(0);
params.setRows(200);
//Facet爲solr中的層次分類查詢
//分片信息
params.setFacet(true)
.setQuery("*:*")
.setFacetMinCount(1)
.setFacetLimit(5)//段
//.setFacetPrefix("electronics", "cat")
.setFacetPrefix("cor")//查詢manu、name中關鍵字前綴是cor的
.addFacetField("manu")
.addFacetField("name");//分片字段
try {
QueryResponse response = server.query(params);
//輸出查詢結果集
SolrDocumentList list = response.getResults();
fail("Query result nums: " + list.getNumFound());
for (int i = 0; i < list.size(); i++) {
fail(list.get(i));
}
fail("All facet filed result: ");
//輸出分片信息
List<FacetField> facets = response.getFacetFields();
for (FacetField facet : facets) {
fail(facet);
List<Count> facetCounts = facet.getValues();
for (FacetField.Count count : facetCounts) {
//關鍵字 - 出現次數
fail(count.getName() + ": " + count.getCount());
}
}
fail("Search facet [name] filed result: ");
//輸出分片信息
FacetField facetField = response.getFacetField("name");
List<Count> facetFields = facetField.getValues();
for (Count count : facetFields) {
//關鍵字 - 出現次數
fail(count.getName() + ": " + count.getCount());
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
分片查詢在某些統計關鍵字的時候仍是頗有用的,能夠統計關鍵字出現的次數,能夠經過統計的關鍵字來搜索相關文檔的信息。
這裏轉換的Bean是一個簡單的User對象
package com.hoo.entity;
import java.io.Serializable;
import org.apache.solr.client.solrj.beans.Field;
/**
* <b>function:</b> User Entity Bean;全部被添加Annotation @Field 註解的屬性將參與index操做
* @author hoojo
* @createDate 2011-10-19 下午04:16:00
* @file User.java
* @package com.hoo.entity
* @project SolrExample
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class User implements Serializable {
/**
* @author Hoojo
*/
private static final long serialVersionUID = 8606788203814942679L;
//@Field
private int id;
@Field
private String name;
@Field
private int age;
/**
* 能夠給某個屬性重命名,likes就是solr index的屬性;在solrIndex中將顯示like爲likes
*/
@Field("likes")
private String[] like;
@Field
private String address;
@Field
private String sex;
@Field
private String remark;
public int getId() {
return id;
}
//setter 方法上面也能夠
@Field
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
//getter、setter
@Override
public String toString() {
return this.id + "#" + this.name + "#" + this.age + "#" + this.like + "#" + this.address + "#" + this.sex + "#" + this.remark;
}
}
測試類代碼以下
package com.hoo.test;
import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.junit.Test;
import com.hoo.entity.User;
/**
* <b>function:</b>SolrInputDocument implements Map, Iterable
* @author hoojo
* @createDate 2011-10-19 下午03:54:54
* @file SolrInputDocumentTest.java
* @package com.hoo.test
* @project SolrExample
* @blog http://blog.csdn.net/IBM_hoojo
* @email hoojo_@126.com
* @version 1.0
*/
public class SolrInputDocumentTest {
public final void fail(Object o) {
System.out.println(o);
}
/**
* <b>function:</b> 建立SolrInputDocument
* @author hoojo
* @createDate 2011-10-21 下午03:38:20
*/
@Test
public void createDoc() {
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", System.currentTimeMillis());
doc.addField("name", "SolrInputDocument");
doc.addField("age", 22, 2.0f);
doc.addField("like", new String[] { "music", "book", "sport" });
doc.put("address", new SolrInputField("guangzhou"));
doc.setField("sex", "man");
doc.setField("remark", "china people", 2.0f);
fail(doc);
}
/**
* <b>function:</b> 利用DocumentObjectBinder對象將SolrInputDocument 和 User對象相互轉換
* @author hoojo
* @createDate 2011-10-21 下午03:38:40
*/
@Test
public void docAndBean4Binder() {
SolrDocument doc = new SolrDocument();
doc.addField("id", 456);
doc.addField("name", "SolrInputDocument");
doc.addField("likes", new String[] { "music", "book", "sport" });
doc.put("address", "guangzhou");
doc.setField("sex", "man");
doc.setField("remark", "china people");
DocumentObjectBinder binder = new DocumentObjectBinder();
User user = new User();
user.setId(222);
user.setName("JavaBean");
user.setLike(new String[] { "music", "book", "sport" });
user.setAddress("guangdong");
fail(doc);
// User ->> SolrInputDocument
fail(binder.toSolrInputDocument(user));
// SolrDocument ->> User
fail(binder.getBean(User.class, doc));
SolrDocumentList list = new SolrDocumentList();
list.add(doc);
list.add(doc);
//SolrDocumentList ->> List
fail(binder.getBeans(User.class, list));
}
/**
* <b>function:</b> SolrInputDocument的相關方法
* @author hoojo
* @createDate 2011-10-21 下午03:44:30
*/
@Test
public void docMethod() {
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", System.currentTimeMillis());
doc.addField("name", "SolrInputDocument");
doc.addField("age", 23, 1.0f);
doc.addField("age", 22, 2.0f);
doc.addField("age", 24, 0f);
fail(doc.entrySet());
fail(doc.get("age"));
//排名有用,相似百度競價排名
doc.setDocumentBoost(2.0f);
fail(doc.getDocumentBoost());
fail(doc.getField("name"));
fail(doc.getFieldNames());//keys
fail(doc.getFieldValues("age"));
fail(doc.getFieldValues("id"));
fail(doc.values());
}
}