⑴ solr查詢某個欄位最大值,如何實現
q:查詢的關鍵字,此參數最為重要,例如,q=id:1,默認為q=*:*,類似於sql中的where 1=1。
fq(filter query):過濾查詢,提供一個可選的篩選器查詢。返回在q查詢符合結果中同時符合的fq條件的查詢結果,例如:q=id:1&fq=sort:[1 TO 5]&fq=section:0,找關鍵字id為1 的,並且sort是1到5之間,section=0的。還能寫成fq=+sort[1 TO 5] +section:0]。性能方面的考慮:每個fq下面的記錄都會單獨緩存。可以考慮把經常在一起的fq條件用+方式寫。
sort:排序方式,例如id desc 表示按照 「id」 降序。id desc, price asc先按id降序,再按price升序。sum(x_f, y_f) desc按x_f和y_f欄位的和降序。
start,rows:分頁參數,類似於start,limite的功能。啥都不輸的話默認值分別為start=0,limit=10。
⑵ java web 怎麼用solr
我們下載的Solr包後,進入Solr所在的目錄,我們可以看到以下幾個目錄:build、client、dist、example、lib、site、src。下面分別對其進行介紹。
1) build:該目錄是在ant build過程中生成的,其中包含了未被打包成jar或是war的class文件以及一些文檔文件。
2) client:該目錄包含了特定語言的Solr客戶端API,使得使用其他語言的用戶能通過HTTP用XML與Solr進行通話。現在該目錄裡面雖然包含javascript、python、ruby三個子目錄,但是到目前為止只包含一部分的ruby的代碼,其他語言仍是空的。另外,Solr的Java客戶端稱為SolrJ,其代碼位於src/solrj目錄下面。在之後的文章中我會詳細介紹Solr客戶端的使用。
3) dist:該目錄包含build過程中產生的war和jar文件,以及相關的依賴文件。還記得上一篇文章中,我們在build 1.4版本的Solr源代碼後需要部署example嗎?其實就是將該目錄下面的apache-solr-1.4.war部署到Jetty上面去,並重命名為solr.war。
4) example:這個目錄實際上是Jetty的安裝目錄。其中包含了一些樣例數據和一些Solr的配置。
其中一些子目錄也比較重要,這里也對它們稍作介紹。
l example/etc:該目錄包含了Jetty的配置,在這里我們可以將Jetty的默認埠從8983改為80埠。
l 將其中的8983埠換成80埠。注意更改埠後啟動Jetty可能會提示你沒有許可權,你需要使用sudo java -jar start.jar來運行。
l example/multicore:該目錄包含了在Solr的multicore中設置的多個home目錄。在之後的文章中我會對其進行介紹。
l example/solr:該目錄是一個包含了默認配置信息的Solr的home目錄。
詳見下面的「solr home說明」
l example/webapps:Jetty的webapps目錄,該目錄通常用來放置Java的Web應用程序。在Solr中,前面提到的solr.war文件就部署在這里。
5) lib:該目錄包含了所有Solr的API所依賴的庫文件。其中包括Lucene,Apache commons utilities和用來處理XML的Stax庫。
6) site:該目錄僅僅包含了Solr的官網的網頁內容,以及一些教程的PDF文檔。
7) src:該目錄包含了Solr項目的整個源代碼。這里對其各個子目錄也做相應的介紹。
l src/java:該目錄存放的是Solr使用Java編寫的源代碼。
l src/scripts:該目錄存放的是配置Solr伺服器的Unix BashShell腳本,在後面介紹多伺服器配置中將會有重要的作用。
l src/solrj:前面提到過該目錄存放的是Solr的Java版本的客戶端代碼。
l src/test:該目錄存放的是測試程序的源代碼和測試文件。
l src/webapp:該目錄存放的是管理Solr的Web頁面,包括Servlet和JSP文件,其構成了前面提到的WAR文件。管理Solr的JSP頁面在web/admin目錄下面,如果你有興趣折騰Solr可以找到相應的JSP的頁面對其進行設置
1.4.2 Solr home說明
所謂的Solr home目錄實際上是一個運行的Solr實例所對應的配置和數據(Lucene索引)。在上一篇文章中我提到過在Solr的example/solr目錄就是一個Solr用做示例的默認配置home目錄。實際上example/multicore也是一個合法的Solr home目錄,只不過是用來做mult-core設置的。那麼我們來看看example/solr這個目錄裡面都有些什麼。
example/solr目錄下主要有以下一些目錄和文件:
1) bin:如果你需要對Solr進行更高級的配置,該目錄建議用來存放Solr的復制腳本。
2) conf :該目錄下麵包含了各種配置文件,下面列出了兩個最為重要的配置文件。其餘的.txt和.xml文件被這兩個文件所引用,如用來對文本進行特殊的處理。
l conf/schema.xml:該文件是索引的schema,包含了域類型的定義以及相關聯的analyzer鏈。
l conf/solrconfig.xml:該文件是Solr的主配置文件。
l conf/xslt:該目錄包含了各種XSLT文件,能將Solr的查詢響應轉換成不同的格式,如:Atom/RSS等。
3) data:包含了Lucene的二進制索引文件。
4) lib:該目錄是可選的。用來放置附加的Java JAR文件,Solr在啟動時會自動載入該目錄下的JAR文件。這就使得用戶可以對Solr的發布版本(solr.war)進行擴展。如果你的擴展並不對Solr本身進行修改,那麼就可以將你的修改部署到JAR文件中放到這里。
Solr是如何找到運行所需要的home目錄的呢?
Solr首先檢查名為solr.solr.home的Java系統屬性,有幾種不同的方式來設置該Java系統屬性。一種不管你使用什麼樣的Java應用伺服器或Servlet引擎都通用的方法是在調用Java的命令行中進行設置。所以,你可以在啟動Jetty的時候顯式地指定Solr的home目錄java -Dsolr.solr.home=solr/ -jar start.jar。另一種通用的方法是使用JNDI,將home目錄綁定到java:comp/env/solr/home。並向src/webapp/web/WEB-INF/web.xml添加以下一段代碼:
1 <env-entry>
2 <env-entry-name>solr/home</env-entry-name>
3 <env-entry-value>solr/</env-entry-value>
4 <env-entry-type>java.lang.String</env-entry-type>
5 </env-entry>
實際上這段XML在web.xml文件中已經存在,你只需要把原來注釋掉的xml取消注釋,添加你所要指向的home目錄即可。因為修改了web.xml文件,所以你需要運行antdist-war來重新打包之後再部署WAR文件。
最後,如果Solr的home目錄既沒有通過Java系統屬性指定也沒有通過JNDI指定,那麼他將默認指向solr/。
在產品環境中,我們必須設置Solr的home目錄而不是讓其默認指向solr/。而且應該使用絕對路徑,而不是相對路徑,因為你有可能從不同的目錄下面啟動應用伺服器。
註:Jetty 是一個開源的servlet容器,它為基於Java的web內容,例如JSP和servlet提供運行環境。Jetty是使用Java語言編寫的,它的API以一組JAR包的形式發布。開發人員可以將Jetty容器實例化成一個對象,可以迅速為一些獨立運行(stand-alone)的Java應用提供網路和web連接。
我們先從使用者的角度出發,最先看到的當然是servlet,因為Solr本身是個獨立的網路應用程序,需要在Servlet容器中運行來提供服務,所以servlet是用戶接觸的最外層。我們看看org.apache.solr.servlet包。這個包很簡單,只有兩個類:SolrServlet和SolrUpdateServlet.我們很容易從類名中猜出這兩個類的用途。
SolrServlet類繼承HttpServlet類,只有四個方法:
· init()
· destroy()
· doGet()
· doPost()
SolrServlet類中除了普通的Java類對象(包括Servlet相關的)外,有四個Solr本身的類,還有一個Solr本身的異常。其中兩個類和一個異常屬於org.apache.solr.core包,兩個類屬於org.apache.solr.request包。屬於core包的有:
· Config:
· SolrCore:
屬於request包的有:
· SolrQueryResponse:
· QueryResponseWriter:
分析一下這個SolrServlet類。首先servlet會調用init()方法進行初始化:通過Context查找java:comp/env/solr/home來確定Solr的主目錄(home),接著調用Config.setInstanceDir(home)方法設置這個實例的目錄。然後通過SolrCore.getSolrCore()來獲得一個SolrCore實例。destroy()方法將會在Servlet對象銷毀時調用,僅僅調用core.close()關閉SolrCore實例。
當用戶請求進來時doPost()簡單地將任務交給doGet()完成,主要的任務由doGet()完成。分析一下doGet()方法:
1) 使用SolrCore和doGet()參數request生成一個SolrServletRequest對象(注意:這個SolrServletRequest類不是公開類,位於org.apache.solr.servlet包中,繼承了SolrQueryRequestBase類,僅僅接受SolrCore和HttpServletRequest對象作為參數)
2) 然後SolrCore執行execute()方法(參數為SolrServletRequest和SolrQueryResponse)
由此可見,真正的處理核心是SolrCore的execute方法
⑶ solr組件的角色有哪些
Solr它是一種開放源碼的、基於 Lucene Java 的搜索伺服器,易於加入到 Web 應用程序中。
二、Solr 提供了層面搜索(就是統計)、命中醒目顯示並且支持多種輸出格式(包括XML/XSLT 和JSON等格式)。它易於安裝和配置,而且附帶了一個基於 HTTP 的
管理界面。Solr已經在眾多大型的網站中使用,較為成熟和穩定。
三、Solr 包裝並擴展了 Lucene,所以Solr的基本上沿用了Lucene的相關術語。更重要的是,Solr 創建的索引與 Lucene 搜索引擎庫完全兼容。
四、通過對Solr 進行適當的配置,某些情況下可能需要進行編碼,Solr 可以閱讀和使用構建到其他 Lucene 應用程序中的索引。
五、此外,很多 Lucene 工具(如Nutch、 Luke)也可以使用Solr 創建的索引。可以使用 Solr 的表現優異的基本搜索功能,也可以對它進行擴展從而滿足企業的需要。
solr的優點
通過上面Solr的簡介,可知solr的優點包括以下幾個方面:
①高級的全文搜索功能;
②專為高通量的網路流量進行的優化;
③基於開放介面(XML和HTTP)的標准;
④綜合的HTML管理界面;
⑤可伸縮性-能夠有效地復制到另外一個Solr搜索伺服器;
⑥使用XML配置達到靈活性和適配性;
⑦可擴展的插件體系。
solr VS Lucene!?
在比較solr和Lucene之前,要知道什麼是Lucene,那麼首先就來回顧Lucene是個什麼東東?
Lucene是一個基於Java的全文信息檢索工具包,它不是一個完整的搜索應用程序,而是為你的應用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta(雅加達) 家族中的一個開源項目。也是目前最為流行的基於Java開源全文檢索工具包。目前已經有很多應用程序的搜索功能是基於 Lucene ,比如Eclipse 幫助系統的搜 索功能。Lucene能夠為文本類型的數據建立索引,所以你只要把你要索引的數據格式轉化的文本格式,Lucene 就能對你的文檔進行索引和搜索。
那麼,solr和它相比,是」輸「了?還是「贏」了呢?
其實,Solr與Lucene 並不是競爭對立關系,恰恰相反Solr 依存於Lucene,因為Solr底層的核心技術是使用Lucene 來實現的,Solr和Lucene的本質區別有以下三點:搜索伺服器,企業級和管理。Lucene本質上是搜索庫,不是獨立的應用程序,而Solr是。Lucene專注於搜索底層的建設,而Solr專注於企業應用。Lucene不負責支撐搜索服務所必須的管理,而Solr負責。所以說,一句話概括 Solr: Solr是Lucene面向企業搜索應用的擴展。
下面是solr和 lucene的架構圖:
這個圖很繁瑣,看不懂,大家不要灰心,在後面的代碼里你就能夠了解了這個圖所講的。
不難看出,綠色的就是lucene的模塊,而藍色的就是solr擴展了lucene。從圖上可以看出以下幾點:
a. 一個真正的擁有動態欄位(Dynamic Field)和唯一鍵(Unique Key)的數據模式(Data Schema)
b. 對Lucene查詢語言的強大擴展!
c. 支持對結果進行動態的分組和過濾
d. 高級的,可配置的文本分析
e. 高度可配置和可擴展的緩存機制
f. 性能優化
g. 支持通過XML進行外部配置
h. 擁有一個管理界面
i. 可監控的日誌
j. 支持高速增量式更新(Fast incremental Updates)和快照發布(Snapshot Distribution)
說到這,solr的簡介就到此結束了,相信大家也對solr有了初步的了解,下面開始介紹一下solr的常用屬性有哪些?
solr的使用屬性及配置文件
Document 包括一個或多個 Field。Field 包括名稱、內容以及告訴 Solr 如何處理內容的元數據。
例如,Field可以包含字元串、數字、布爾值或者日期,也可以包含你想添加的任何類型,只需用在solr的配置文件中進行相應的配置即可。Field可以使用大量的選項來描述,這些
選項告訴 Solr 在索引和搜索期間如何處理內容。
現在,查看以下圖片 中列出的重要屬性的子集:
在這就先提一下solr的重要文件之一,就是schema.xml的配置文件。
(一) schema.xml
schema.xml這個配置文件可以在你下載solr包的安裝解壓目錄的\solr\example\solr\collection1\conf中找到,它就是solr模式關聯的文件。
打開這個配置文件,你會發現有詳細的注釋。模式組織主要分為三個重要配置:
一、Fieldtype
Fieldtype:就是屬性類型的意思,像int,String,Boolean種類型,而在此配置文件中,FieldType就有這種定義屬性的功能,看下面的圖片:
圖片上有我們熟悉的int,String,boolean,那麼,後面的配置,是什麼呢?那麼我們就來介紹一下後面的參數:
二、Field
Field:是添加到索引文件中出現的屬性名稱,而聲明類型就需要用到上面的type,如圖所示:
ps:①field: 固定的欄位設置;②dynamicField: 動態的欄位設置,用於後期自定義欄位,*號通配符.例如: test_i就是int類型的動態欄位。
還有一個特殊的欄位Field,一般用於檢索時用的欄位這樣就只對這一個欄位進行索引分詞就行了Field的dest欄位如果有多個source一定要設置
⑷ solr 名稱 關鍵字兩個欄位權重設置
大家都知道,在SQL腳本中設置多欄位做關鍵字相對比較簡單,例:primary
key(id1,id2)
,但用腳本建資料庫就比較麻煩了。
下面我們來介紹一下具體的解決方法:
1.把要設置為關鍵字的其中一個欄位設為主鍵。
2.在設為主鍵的欄位上右鍵單擊選擇索引/健,出現索引/健對話框。
3.找到常規----列,單擊右邊的小按鈕,出現索引列對話框。
4.至此,我們就可以選擇幾個欄位作為關鍵字了。
注釋:第一個步驟不能省略。
⑸ 集群 solr 搜索 怎麼收集結果
Facet 是 solr 的高級搜索功能之一 , 可以給用戶提供更友好的搜索體驗 . 在搜索關鍵字的同時 ,能夠按照 Facet 的欄位進行分組並統計 .
二. Facet 欄位
1. 適宜被Facet 的欄位
一般代表了實體的某種公共屬性 , 如商品的分類 , 商品的製造廠家 , 書籍的出版商等等 .
2. Facet 欄位的要求
Facet 的欄位必須被索引 . 一般來說該欄位無需分詞 , 無需存儲 .
無需分詞是因為該欄位的值代表了一個整體概念 , 如電腦的品牌 」 聯想 」 代表了一個整體概念 , 如果拆成 」 聯 」,」 想 」 兩個字都不具有實際意義 . 另外該欄位的值無需進行大小寫轉換等處理 , 保持其原貌即可 .
無需存儲是因為一般而言用戶所關心的並不是該欄位的具體值 , 而是作為對查詢結果進行分組的一種手段 , 用戶一般會沿著這個分組進一步深入搜索 .
3. 特殊情況
對於一般查詢而言 , 分詞和存儲都是必要的 . 比如 CPU 類型 」Intel 酷睿 2 雙核 P7570」,拆分成 」Intel」,」 酷睿 」,」P7570」 這樣一些關鍵字並分別索引 , 可能提供更好的搜索體驗 . 但是如果將 CPU 作為 Facet 欄位 , 最好不進行分詞 . 這樣就造成了矛盾 , 解決方法為 ,將 CPU 欄位設置為不分詞不存儲 , 然後建立另外一個欄位為它的 COPY, 對這個 COPY 的欄位進行分詞和存儲 .
schema.xml
<types>
<fieldType name="string" class="solr.StrField" omitNorms="true"/>
<fieldType name="tokened" class="solr.TextField" >
<analyzer>
……
</analyzer>
</fieldType>
……
</types>
<fields>
<field name=」cpu」 type=」string」 indexed=」true」 stored=」false」/>
<field name=」cpuCopy」 type=」 tokened」 indexed=」true」 stored=」true」/>
……
</fields>
<Field source="cpu" dest="cpuCopy"/>
三. Facet 組件
Solr 的默認 requestHandler(org.apache.solr.handler.component.SearchHandler) 已經包含了 Facet 組件 (org.apache.solr.handler.component.FacetComponent). 如果自定義 requestHandler 或者對默認的 requestHandler 自定義組件列表 , 那麼需要將 Facet 加入到組件列表中去 .
solrconfig.xml
<requestHandler name="standard" class="solr.SearchHandler" default="true">
……
<arr name="components">
<str>自定義組件名</str>
<str>facet</str>
……
</arr>
</requestHandler>
四. Facet 查詢
進行 Facet 查詢需要在請求參數中加入 」facet=on」 或者 」facet=true」 只有這樣 Facet 組件才起作用 .
1. Field Facet
Facet 欄位通過在請求中加入 」facet.field」 參數加以聲明 , 如果需要對多個欄位進行 Facet查詢 , 那麼將該參數聲明多次 . 比如
/select?q=聯想
&facet=on
&facet.field=cpu
&facet.field=videoCard
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries"/>
<lst name="facet_fields">
<lst name="cpu">
<int name="Intel 酷睿2雙核 T6600">48</int>
<int name="Intel 奔騰雙核 T4300">28</int>
<int name="Intel 酷睿2雙核 P8700">18</int>
<int name="Intel 酷睿2雙核 T6570">11</int>
<int name="Intel 酷睿2雙核 T6670">11</int>
<int name="Intel 奔騰雙核 T4400">9</int>
<int name="Intel 酷睿2雙核 P7450">9</int>
<int name="Intel 酷睿2雙核 T5870">8</int>
<int name="Intel 賽揚雙核 T3000">7</int>
<int name="Intel 奔騰雙核 SU4100">6</int>
<int name="Intel 酷睿2雙核 P8400">6</int>
<int name="Intel 酷睿2雙核 SU7300">5</int>
<int name="Intel 酷睿 i3 330M">4</int>
</lst>
<lst name="videoCard">
<int name="ATI Mobility Radeon HD 4">63</int>
<int name="NVIDIA GeForce G 105M">24</int>
<int name="NVIDIA GeForce GT 240M">21</int>
<int name="NVIDIA GeForce G 103M">8</int>
<int name="NVIDIA GeForce GT 220M">8</int>
<int name="NVIDIA GeForce 9400M G">7</int>
<int name="NVIDIA GeForce G 210M">6</int>
</lst>
</lst>
<lst name="facet_dates"/>
</lst>
各個 Facet 欄位互不影響 , 且可以針對每個 Facet 欄位設置查詢參數 . 以下介紹的參數既可以應用於所有的 Facet 欄位 , 也可以應用於每個單獨的 Facet 欄位 . 應用於單獨的欄位時通過
f.欄位名.參數名=參數值
這種方式調用 . 比如 facet.prefix 參數應用於 cpu 欄位 , 可以採用如下形式
f.cpu.facet.prefix=Intel
1.1 facet.prefix
表示 Facet 欄位值的前綴 . 比如 」facet.field=cpu&facet.prefix=Intel」, 那麼對 cpu欄位進行 Facet 查詢 , 返回的 cpu 都是以 」Intel」 開頭的 ,」AMD」 開頭的 cpu 型號將不會被統計在內 .
1.2 facet.sort
表示 Facet 欄位值以哪種順序返回 . 可接受的值為 true(count)|false(index,lex). true(count) 表示按照 count 值從大到小排列 . false(index,lex) 表示按照欄位值的自然順序( 字母 , 數字的順序 ) 排列 . 默認情況下為 true(count). 當 facet.limit 值為負數時 ,默認 facet.sort= false(index,lex).
1.3 facet.limit
限制 Facet 欄位返回的結果條數 . 默認值為 100. 如果此值為負數 , 表示不限制 .
1.4 facet.offset
返回結果集的偏移量 , 默認為 0. 它與 facet.limit 配合使用可以達到分頁的效果 .
1.5 facet.mincount
限制了 Facet 欄位值的最小 count, 默認為 0. 合理設置該參數可以將用戶的關注點集中在少數比較熱門的領域 .
1.6 facet.missing
默認為 」」, 如果設置為 true 或者 on, 那麼將統計那些該 Facet 欄位值為 null 的記錄.
1.7 facet.method
取值為 enum 或 fc, 默認為 fc. 該欄位表示了兩種 Facet 的演算法 , 與執行效率相關 .
enum 適用於欄位值比較少的情況 , 比如欄位類型為布爾型 , 或者欄位表示中國的所有省份.Solr 會遍歷該欄位的所有取值 , 並從 filterCache 里為每個值分配一個 filter( 這里要求 solrconfig.xml 里對 filterCache 的設置足夠大 ). 然後計算每個 filter 與主查詢的交集 .
fc( 表示 Field Cache) 適用於欄位取值比較多 , 但在每個文檔里出現次數比較少的情況 .Solr 會遍歷所有的文檔 , 在每個文檔內搜索 Cache 內的值 , 如果找到就將 Cache 內該值的count 加 1.
1.8 facet.enum.cache.minDf
當 facet.method=enum 時 , 此參數其作用 ,minDf 表示 minimum document frequency. 也就是文檔內出現某個關鍵字的最少次數 . 該參數默認值為 0. 設置該參數可以減少 filterCache 的內存消耗 , 但會增加總的查詢時間 ( 計算交集的時間增加了 ). 如果設置該值的話 ,官方文檔建議優先嘗試 25-50 內的值 .
2. Date Facet
日期類型的欄位在文檔中很常見 , 如商品上市時間 , 貨物出倉時間 , 書籍上架時間等等 . 某些情況下需要針對這些欄位進行 Facet. 不過時間欄位的取值有無限性 , 用戶往往關心的不是某個時間點而是某個時間段內的查詢統計結果 . Solr 為日期欄位提供了更為方便的查詢統計方式 .當然 , 欄位的類型必須是 DateField( 或其子類型 ).
需要注意的是 , 使用 Date Facet 時 , 欄位名 , 起始時間 , 結束時間 , 時間間隔這 4 個參數都必須提供 .
與 Field Facet 類似 ,Date Facet 也可以對多個欄位進行 Facet. 並且針對每個欄位都可以單獨設置參數 .
2.1 facet.date
該參數表示需要進行 Date Facet 的欄位名 , 與 facet.field 一樣 , 該參數可以被設置多次 , 表示對多個欄位進行 Date Facet.
2.2 facet.date.start
起始時間 , 時間的一般格式為 」 1995-12-31T23:59:59Z」, 另外可以使用 」NOW」,」YEAR」,」MONTH」 等等 , 具體格式可以參考 org.apache.solr.schema. DateField 的 java doc.
2.3 facet.date.end
結束時間 .
2.4 facet.date.gap
時間間隔 . 如果 start 為 2009-1-1,end 為 2010-1-1.gap 設置為 」+1MONTH」 表示間隔1 個月 , 那麼將會把這段時間劃分為 12 個間隔段 . 注意 」+」 因為是特殊字元所以應該用 」%2B」 代替 .
2.5 facet.date.hardend
取值可以為 true|false, 默認為 false. 它表示 gap 迭代到 end 處採用何種處理 . 舉例說明 start 為 2009-1-1,end 為 2009-12-25,gap 為 」+1MONTH」,hardend 為 false 的話最後一個時間段為 2009-12-1 至 2010-1-1;hardend 為 true 的話最後一個時間段為 2009-12-1 至 2009-12-25.
2.6 facet.date.other
取值范圍為 before|after|between|none|all, 默認為 none.
before 會對 start 之前的值做統計 .
after 會對 end 之後的值做統計 .
between 會對 start 至 end 之間所有值做統計 . 如果 hardend 為 true 的話 , 那麼該值就是各個時間段統計值的和 .
none 表示該項禁用 .
all 表示 before,after,all 都會統計 .
舉例 :
&facet=on
&facet.date=date
&facet.date.start=2009-1-1T0:0:0Z
&facet.date.end=2010-1-1T0:0:0Z
&facet.date.gap=%2B1MONTH
&facet.date.other=all
返回結果 :
3. Facet Query
Facet Query 利用類似於 filter query 的語法提供了更為靈活的 Facet. 通過 facet.query 參數 , 可以對任意欄位進行篩選 .
例 1:
&facet=on
&facet.query=date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]
&facet.query=date:[2009-4-1T0:0:0Z TO 2009-5-1T0:0:0Z]
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries">
<int name="date:[2009-1-1T0:0:0Z TO 2009-2-1T0:0:0Z]">5</int>
<int name="date:[2009-4-1T0:0:0Z TO 2009-5-1T0:0:0Z]">3</int>
</lst>
<lst name="facet_fields"/>
<lst name="facet_dates"/></lst>
例 2:返回結果 :
例 3:
&facet=on
&facet.query=cpu:[A TO G]
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries">
<int name="cpu:[A TO G]">11</int>
</lst>
<lst name="facet_fields"/>
<lst name="facet_dates"/>
</lst>
4. key 操作符
可以用 key 操作符為 Facet 欄位取一個別名 .
例 :
&facet=on
&facet.field={!key=中央處理器}cpu
&facet.field={!key=顯卡}videoCard
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries"/>
<lst name="facet_fields">
<lst name="中央處理器">
<int name="Intel 酷睿2雙核 T6600">48</int>
<int name="Intel 奔騰雙核 T4300">28</int>
<int name="Intel 酷睿2雙核 P8700">18</int>
<int name="Intel 酷睿2雙核 T6570">11</int>
<int name="Intel 酷睿2雙核 T6670">11</int>
<int name="Intel 奔騰雙核 T4400">9</int>
<int name="Intel 酷睿2雙核 P7450">9</int>
<int name="Intel 酷睿2雙核 T5870">8</int>
<int name="Intel 賽揚雙核 T3000">7</int>
<int name="Intel 奔騰雙核 SU4100">6</int>
<int name="Intel 酷睿2雙核 P8400">6</int>
<int name="Intel 酷睿2雙核 SU7300">5</int>
<int name="Intel 酷睿 i3 330M">4</int>
</lst>
<lst name="顯卡">
<int name="ATI Mobility Radeon HD 4">63</int>
<int name="NVIDIA GeForce G 105M">24</int>
<int name="NVIDIA GeForce GT 240M">21</int>
<int name="NVIDIA GeForce G 103M">8</int>
<int name="NVIDIA GeForce GT 220M">8</int>
<int name="NVIDIA GeForce 9400M G">7</int>
<int name="NVIDIA GeForce G 210M">6</int>
</lst>
</lst>
<lst name="facet_dates"/>
</lst>
5. tag 操作符和 ex 操作符
當查詢使用 filter query 的時候 , 如果 filter query 的欄位正好是 Facet 欄位 , 那麼查詢結果往往被限制在某一個值內 .
例 :
&fq=screenSize:14
&facet=on
&facet.field=screenSize
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries"/>
<lst name="facet_fields">
<lst name=" screenSize">
<int name="14.0">107</int>
<int name="10.2">0</int>
<int name="11.1">0</int>
<int name="11.6">0</int>
<int name="12.1">0</int>
<int name="13.1">0</int>
<int name="13.3">0</int>
<int name="14.1">0</int>
<int name="15.4">0</int>
<int name="15.5">0</int>
<int name="15.6">0</int>
<int name="16.0">0</int>
<int name="17.0">0</int>
<int name="17.3">0</int>
</lst>
</lst>
<lst name="facet_dates"/>
</lst>
可以看到 , 屏幕尺寸 (screenSize) 為 14 寸的產品共有 107 件 , 其它尺寸的產品的數目都是0, 這是因為在 filter 里已經限制了 screenSize:14. 這樣 , 查詢結果中 , 除了 screenSize=14 的這一項之外 , 其它項目沒有實際的意義 .
有些時候 , 用戶希望把結果限制在某一范圍內 , 又希望查看該范圍外的概況 . 比如上述情況 ,既要把查詢結果限制在 14 寸屏的筆記本 , 又想查看一下其它屏幕尺寸的筆記本有多少產品 . 這個時候需要用到 tag 和 ex 操作符 .
tag 就是把一個 filter 標記起來 ,ex(exclude) 是在 Facet 的時候把標記過的 filter 排除在外 .
例 :
&fq={!tag=aa}screenSize:14
&facet=on
&facet.field={!ex=aa}screenSize
返回結果 :
<lst name="facet_counts">
<lst name="facet_queries"/>
<lst name="facet_fields">
<lst name=" screenSize">
<int name="14.0">107</int>
<int name="14.1">40</int>
<int name="13.3">34</int>
<int name="15.6">22</int>
<int name="15.4">8</int>
<int name="11.6">6</int>
<int name="12.1">5</int>
<int name="16.0">5</int>
<int name="15.5">3</int>
<int name="17.0">3</int>
<int name="17.3">3</int>
<int name="10.2">1</int>
<int name="11.1">1</int>
<int name="13.1">1</int>
</lst>
</lst>
<lst name="facet_dates"/>
</lst>
這樣其它屏幕尺寸的統計信息就有意義了 .
五. SolrJ 對 Facet 的支持
SolrServer server = getSolrServer();//獲取SolrServer
SolrQuery query = new SolrQuery();//建立一個新的查詢
query.setQuery("*:*");
query.setFacet(true);//設置facet=on
query.addFacetField(new String[] { "cpu", "videoCard" });//設置需要facet的欄位
query.setFacetLimit(10);//限制facet返回的數量
QueryResponse response = server.query(query);
List<FacetField> facets = response.getFacetFields();//返回的facet列表
for (FacetField facet : facets) {
System.out.println(facet.getName());
System.out.println("----------------");
List<Count> counts = facet.getValues();
for (Count count : counts) {
System.out.println(count.getName() + ":" + count.getCount());
}
System.out.println();
}
⑹ 如何使用Solr索引MySql資料庫
在solr與tomcat整合文章中,我用的索引庫是mycore,現在就以這個為例。
首先要准備jar包:solr-dataimporthandler-4.8.1.jar、solr-dataimporthandler-extras-4.8.1.jar和mysql-connector-java-5.0.7-bin.jar這三個包到solr的tomcat的webapps\solr\WEB-INF\lib下
在這個文件夾的conf下配置兩個文件,添加一個文件。先配置solrconfig.xml。
在該文件下添加一個新節點。
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
在solrconfig.xml的同目錄下創建data-config.xml。
配置:
復制代碼
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/courseman"
user="root"
password="mysql" />
<document>
<entity name="student"
query="SELECT * FROM student">
<field column="id" name="id" />
<field column="name" name="name" />
<field column="gender" name="gender" />
<field column="major" name="major" />
<field column="grade" name="grade" />
</entity>
</document>
</dataConfig>
復制代碼
schemal.xml的配置
復制代碼
<?xml version="1.0" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding right ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<schema name="example core one" version="1.1">
<fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<!-- general -->
<field name="id" type="int" indexed="true" stored="true" />
<field name="gender" type="string" indexed="true" stored="true" />
<field name="name" type="string" indexed="true" stored="true" />
<field name="major" type="string" indexed="true" stored="true" />
<field name="grade" type="string" indexed="true" stored="true" />
<field name="_version_" type="long" indexed="true" stored="true"/>
<!-- field to use to determine and enforce document uniqueness. -->
<uniqueKey>id</uniqueKey>
<!-- field for the QueryParser to use when an explicit fieldname is absent -->
<defaultSearchField>name</defaultSearchField>
<!-- SolrQueryParser configuration: defaultOperator="AND|OR" -->
<solrQueryParser defaultOperator="OR"/>
</schema>
復制代碼
默認的文件不是這樣的,稍微改動了一下。
field 的type類型是根據fieldtype 的name定義的。class是solr自定義的不能更改。
shcema.xml文件的field欄位的屬性介紹:
(1)name:欄位名稱
(2)type:欄位類型(此處type不是java類型,而是下面定義的fieldType)
(3)indexed:是否索引看true--solr會對這個欄位進行索引,只有經過索引的欄位才能被搜索、排序等;false--不索引
(4)stored:是否存儲看true--存儲,當我們需要在頁面顯示此欄位時,應設為true,否則false。
(5)required:是否必須看true--此欄位為必需,如果此欄位的內容為空,會報異常;false--不是必需
(6)multiValued:此欄位是否可以保存多個值看
(7)omitNorms:是否對此欄位進行解析看有時候我們想通過某個欄位的完全匹配來查詢信息,那麼設置 indexed="true"、omitNorms="true"。
(8)default:設置默認值
有這樣一個FieldType描述:
<fieldType name="text_general" positionIncrementGap="100">
<analyzer type="index">
<tokenizer/>
<filter ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
<filter/>
</analyzer>
<analyzer type="query">
<tokenizer/>
<filter ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
<filter synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter/>
</analyzer>
</fieldType>
屬性說明:
(1)name:類型名稱,<field>中的type引用的就是這個name
(2)class:solr自定義的類型
(3)<analyzer type="index">定義建立索引時使用的分詞器及過濾器
(4)<analyzer type="query">定義搜索時所使用的分詞器及過濾器
(5)<tokenizer/>定義分詞器
(6)<filter/>定義過濾器
uniqueKey屬性
<uniqueKey>id</uniqueKey>
類似於數據表數據的id,solr索引庫中最好定義一個用於標示document唯一性的欄位,此欄位主要用於刪除document。
defaultSearchField屬性
就是你在做query搜尋時若不指定特定欄位做檢索時, Solr就會只查這個欄位.
<defaultSearchField>default</defaultSearchField>
Field屬性
是用來復制你一個欄位里的值到另一欄位用. 如你可以將name里的東西到major里, 這樣solr做檢索時也會檢索到name里的東西.
<Field source="name" dest="major"/>
現在可以將資料庫的數據導入solr了。
點擊Execute就可以了。
⑺ 求助:solr如何通過指定條件修改數據
修改主方法
public int saveContent(String enterpriseId, String enterpriseName, String lableType, String resouce, String pubDate,
String content) {
int state = 0;
LBHttpSolrServer server = SolrUtil.getSolrServer(ap.getEnterprisenewSolrUrl());
SolrQuery query = new SolrQuery();
query.set("q", "enterpriseId:" + enterpriseId);
try {
QueryResponse qr = server.query(query);
List<EnterpriseContentBean> contentList = qr.getBeans(EnterpriseContentBean.class);
// 設置需要保存的文章信息
for (EnterpriseContentBean bean : contentList) {
bean.setEnterpriseId(enterpriseId);
bean.setEnterpriseName(enterpriseName);
List<String> contents = new ArrayList<String>();
contents.add(content);
bean.setContent(contents);
bean.setPubDate(pubDate);
System.out.println("pubDate======>" + pubDate);
List<String> lableTypes = Arrays.asList(lableType.split(","));
bean.setLableType(lableTypes);
bean.setResource(resouce);
bean.setIsVisited_s("1");
}
server.addBeans(contentList);
server.commit();
} catch (SolrServerException e) {
state = 1;
System.out.println("修改solr數據報錯");
e.printStackTrace();
} catch (IOException e) {
state = 1;
System.out.println("修改solr數據報錯");
e.printStackTrace();
}
return state;
}
刪除主方法
public int deletContent(String enterpriseId) {
LBHttpSolrServer server = SolrUtil.getSolrServer(ap.getEnterprisenewSolrUrl());
int state = 0;
try {
server.deleteById(enterpriseId);
server.commit();
} catch (SolrServerException e) {
state = 1;
System.out.println("刪除solr數據報錯");
e.printStackTrace();
} catch (IOException e) {
state = 1;
System.out.println("刪除solr數據報錯");
e.printStackTrace();
}
return state;
}
solr工具類
package com.dinfo.boc.utils;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.LBHttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import com.dinfo.boc.enterprise.bean.EnterpriseContentBean;
import com.dinfo.boc.enterprisenew.bean.SolrQueryResult;
/**
* 與Solr伺服器交互的工具類
* @author qiuyj
*
*/
public class SolrUtil {
/**
* 獲取與指定Solr地址的連接
* @param solrUrl
* @return
*/
public static LBHttpSolrServer getSolrServer(String solrUrl){
final int ONE_HUNDRED_MS = 10000000;
if(solrUrl == null || "".equals(solrUrl)){
throw new RuntimeException("Solr url can not be empty!");
}
LBHttpSolrServer solrServer = null;
try {
solrServer = new LBHttpSolrServer(solrUrl);
solrServer.setConnectionTimeout(ONE_HUNDRED_MS);
} catch (MalformedURLException e) {
e.printStackTrace();
} //SolrUtil.getSolrServer(solrUrl);
//solrServer.(100);
//solrServer.setMaxTotalConnections(100);
return solrServer;
}
/**
* 向指定的Solr地址添加一條數據
* @param solrUrl
* @param doc
* @throws Exception
*/
public static void add(String solrUrl, SolrInputDocument doc) throws Exception {
if(doc == null){
throw new RuntimeException("SolrInputDocument object can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.add(doc);
solr.commit();
}
/**
* 向指定的Solr地址用JavaBean添加一條數據
* @param solrUrl
* @param obj
* @throws Exception
*/
public static void add(String solrUrl, Object obj) throws Exception {
if(obj == null){
throw new RuntimeException("Object to be inserted can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.addBean(obj);
solr.commit();
}
/**
* 向指定Solr地址批量添加數據
* @param solrUrl
* @param docs
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static void addAll(String solrUrl, Collection<? extends Object> objs) throws Exception {
if(objs == null){
throw new RuntimeException("Object collection can not be null!");
}
if(objs.size() == 0){
return;
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
if(objs.iterator().next() instanceof SolrInputDocument){
solr.add((Collection<SolrInputDocument>)objs);
} else {
solr.addBeans(objs);
}
solr.commit();
}
/**
* 根據給定的id,從solr中刪除對應信息
* @param solrUrl
* @param ids
*/
public static void deleteByIds(String solrUrl, String ... ids) throws Exception {
if(ids == null || ids.length == 0){
throw new RuntimeException("Ids can not be empty!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.deleteById(Arrays.asList(ids));
solr.commit();
}
public static void deleteByIds(String solrUrl, Integer ... ids) throws Exception {
if(ids == null || ids.length == 0){
throw new RuntimeException("Ids can not be empty!");
}
List<String> stringIdList = new ArrayList<>(ids.length);
for(Integer id : ids){
stringIdList.add("" + id);
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.deleteById(stringIdList);
solr.commit();
}
/**
* 刪除指定Solr路徑下符合指定查詢條件的數據
* @param solrUrl
* @param condition
* @throws Exception
*/
public static void deleteByCondition(String solrUrl, String condition) throws Exception {
if(condition == null || "".equals(condition)){
throw new RuntimeException("Condition can not be empty!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.deleteByQuery(condition);
solr.commit();
}
/**
* 刪除指定Solr路徑下的所有數據
* @param solrUrl
* @throws Exception
*/
public static void deleteAll(String solrUrl) throws Exception {
deleteByCondition(solrUrl, "*:*");
}
/**
* 根據 指定查詢條件從Solr中查詢數據,並以SolrDocument的List形式返回
* @param solrUrl
* @param query
* @return
* @throws Exception
*/
public static SolrDocumentList queryAndGetSolrDocumentList(String solrUrl, SolrQuery query) throws Exception {
if(query == null){
throw new RuntimeException("SolrQuery object can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
QueryResponse resp = solr.query(query);
return resp.getResults();
}
/**
* 根據 指定查詢條件從Solr中查詢數據,並以QueryResponse形式返回
* @param solrUrl
* @param query
* @return
* @throws Exception
*/
public static QueryResponse queryAndGetSolrQueryResponse(String solrUrl, SolrQuery query) throws Exception {
if(query == null){
throw new RuntimeException("SolrQuery object can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
QueryResponse resp = solr.query(query);
return resp;
}
/**
* 根據 指定查詢條件從Solr中查詢數據,並以Java Bean的List形式返回
* @param solrUrl
* @param query
* @param returnClass 返回的List集合的泛型
* @return
* @throws Exception
*/
public static <T> List<T> queryAndGetBeanList(String solrUrl, SolrQuery query, Class<T> returnClass) throws Exception {
if(query == null){
throw new RuntimeException("SolrQuery object can not be null!");
}
if(returnClass == null){
throw new RuntimeException("Return class can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
QueryResponse resp = solr.query(query);
return resp.getBeans(returnClass);
}
/**
* 根據 指定查詢條件從Solr中查詢數據,並以SolrQueryResult對象的形式返回,其中包含List對象和totalCount
* @param solrUrl
* @param query
* @param returnClass 返回的List集合的泛型
* @return
* @throws Exception
*/
public static <T> SolrQueryResult<T> queryAndGetSolrQueryResult(String solrUrl, SolrQuery query, Class<T> returnClass) throws Exception {
SolrQueryResult<T> result = new SolrQueryResult<T>();
if(query == null){
throw new RuntimeException("SolrQuery object can not be null!");
}
if(returnClass == null){
throw new RuntimeException("Return class can not be null!");
}
LBHttpSolrServer solr = getSolrServer(solrUrl);
solr.setConnectionTimeout(10000);
QueryResponse resp = solr.query(query);
List<T> resultList = resp.getBeans(returnClass);
long totalCount = resp.getResults().getNumFound();
result.setResultList(resultList);
result.setTotalCount(totalCount);
return result;
}
/**
* 根據 指定查詢條件從Solr中查詢數據,並以SolrQueryResult對象的形式返回,其中包含List對象和totalCount
* @param solrUrl
* @param query
* @param returnClass 返回的List集合的泛型
* @return
* @throws Exception
*/
public static <T> SolrQueryResult<T> queryAndGetSolrQueryResult(LBHttpSolrServer solr, SolrQuery query, Class<T> returnClass) throws Exception {
SolrQueryResult<T> result = new SolrQueryResult<T>();
if(query == null){
throw new RuntimeException("SolrQuery object can not be null!");
}
if(returnClass == null){
throw new RuntimeException("Return class can not be null!");
}
QueryResponse resp = solr.query(query);
List<T> resultList = resp.getBeans(returnClass);
long totalCount = resp.getResults().getNumFound();
result.setResultList(resultList);
result.setTotalCount(totalCount);
return result;
}
/**
* 用以過濾一些影響Solr查詢的特殊字元,如左右括弧、星號等
* @param str
* @return
*/
public static String filterSpecialCharacters(String str){
if(str == null){
return str;
}
str = str.replace("(", "\\(");
str = str.replace(")", "\\)");
str = str.replace("*", "\\*");
return str;
}
public static void updateSolrById(LBHttpSolrServer server){
SolrQuery query = new SolrQuery();
String id="";
int state=0;
String name="新疆金風科技股份有限公司";
query.set("q", "enterpriseId:"+id);
try {
QueryResponse qr = server.query(query);
List<EnterpriseContentBean> contentList = qr.getBeans(EnterpriseContentBean.class);
//設置需要保存的文章信息
for(EnterpriseContentBean bean:contentList){
// bean.setEnterpriseId(enterpriseId);
bean.setEnterpriseName(name);
bean.setResource("東方財富網港股頻道");
}
server.addBeans(contentList);
server.commit();
} catch (SolrServerException e) {
state = 1;
e.printStackTrace();
} catch (IOException e) {
state = 1;
e.printStackTrace();
}
}
public static void main(String[] args) {
try {
=new LBHttpSolrServer("http://115.182.226.165:8008/solr/enterprisenew");
enterpriseServer.setConnectionTimeout(10000000);
updateSolrById(enterpriseServer);
System.out.println("over");
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
⑻ solr 建索引的時候能對特殊字元做轉義嗎
解決方法:
在搜索的action中將輸入的參數(kw為keywords的縮寫)做轉義處理,即
import org.apache.solr.client.solrj.util.ClientUtils;
String escapedKw = ClientUtils.escapeQueryChars(kw);
然後拿轉義後的escapedKw去solr中查詢,用戶輸入的參數kw的值不變用於回顯到搜索框中。