全文搜索技術—Solr

1.   學習計劃

  1. Solr的安裝及配置php

a)    Solr整合tomcathtml

b)    Solr後臺管理功能介紹java

c)    配置中文分析器mysql

  2. 使用Solr的後臺管理索引庫程序員

a)    添加文檔web

b)     刪除文檔算法

c)    修改文檔spring

d)    查詢文檔sql

  3. 使用SolrJ管理索引庫數據庫

a)    添加文檔

b)    修改文檔

c)    刪除文檔

d)    查詢文檔

  4. 電商搜索案例實現

a)    案例分析

b)    案例實現

 

2.   需求分析

使用Solr實現電商網站中商品信息搜索功能,能夠根據關鍵字、分類、價格搜索商品信息,也能夠根據價格進行排序。

2.1. 實現方法

在一些大型門戶網站、電子商務網站等都須要站內搜索功能,使用傳統的數據庫查詢方式實現搜索沒法知足一些高級的搜索需求,好比:搜索速度要快、搜索結果按相關度排序、搜索內容格式不固定等,這裏就須要使用全文檢索技術實現搜索功能

2.1.1.   使用Lucene實現

單獨使用Lucene實現站內搜索須要開發的工做量較大,主要表如今:索引維護、索引性能優化、搜索性能優化等,所以不建議採用。

2.1.2.   使用solr實現

基於Solr實現站內搜索擴展性較好而且能夠減小程序員的工做量,由於Solr提供了較爲完備的搜索引擎解決方案,所以在門戶、論壇等系統中經常使用此方案。

 

2.2. 什麼是solr

Solr 是Apache下的一個頂級開源項目,採用Java開發,它是基於Lucene的全文搜索服務器。Solr提供了比Lucene更爲豐富的查詢語言,同時實現了可配置、可擴展,並對索引、搜索性能進行了優化。

Solr能夠獨立運行,運行在Jetty、Tomcat等這些Servlet容器中,Solr 索引的實現方法很簡單,用 POST 方法向 Solr 服務器發送一個描述 Field 及其內容的 XML 文檔,Solr根據xml文檔添加、刪除、更新索引 。Solr 搜索只須要發送 HTTP GET 請求,而後對 Solr 返回Xml、json等格式的查詢結果進行解析,組織頁面佈局。Solr不提供構建UI的功能,Solr提供了一個管理界面,經過管理界面能夠查詢Solr的配置和運行狀況。

 

Solr與Lucene的區別:

Lucene是一個開放源代碼的全文檢索引擎工具包,它不是一個完整的全文檢索引擎,Lucene提供了完整的查詢引擎和索引引擎,目的是爲軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能,或者以Lucene爲基礎構建全文檢索引擎。

 Solr的目標是打造一款企業級的搜索引擎系統,它是一個搜索引擎服務,能夠獨立運行,經過Solr能夠很是快速的構建企業的搜索引擎,經過Solr也能夠高效的完成站內搜索功能。

 

 

 

3.   Solr安裝及配置

3.1. Solr的下載

從Solr官方網站(http://lucene.apache.org/solr/ )下載Solr4.10.3,根據Solr的運行環境,Linux下須要下載lucene-4.10.3.tgz,windows下須要下載lucene-4.10.3.zip。

Solr使用指南可參考:https://wiki.apache.org/solr/FrontPage。

3.2. Solr的文件夾結構

將solr-4.10.3.zip解壓:

 

 

 

bin:solr的運行腳本

contrib:solr的一些貢獻軟件/插件,用於加強solr的功能。

dist:該目錄包含build過程當中產生的war和jar文件,以及相關的依賴文件。

docs:solr的API文檔

example:solr工程的例子目錄:

  • example/solr:

       該目錄叫作solrHome,是一個包含了默認配置信息的Solr的Core目錄。

  • example/multicore:

       該目錄包含了在Solr的multicore中設置的多個Core目錄。

  • example/webapps:

    該目錄中包括一個solr.war,該war可做爲solr的運行實例工程。

licenses:solr相關的一些許可信息

3.3. 運行環境

solr 須要運行在一個Servlet容器中,Solr4.10.3要求jdk使用1.7以上,Solr默認提供Jetty(java寫的Servlet容器),這裏使用Tocmat做爲Servlet容器,環境以下:

 

Solr:Solr4.10.3

Jdk:jdk1.7.0_72

Tomcat:apache-tomcat-7.0.53

3.4. Solr整合tomcat

3.4.1.   Solr Home與SolrCore

建立一個Solr home目錄,SolrHome是Solr運行的主目錄,目錄中包括了運行Solr實例全部的配置文件和數據文件,Solr實例就是SolrCore,一個SolrHome能夠包括多個SolrCore(Solr實例),每一個SolrCore提供單獨的搜索和索引服務。

 

example\solr是一個solr home目錄結構,以下:

 

上圖中「collection1」是一個SolrCore(Solr實例)目錄 ,目錄內容以下所示:

  

說明:

collection1:叫作一個Solr運行實例SolrCore,SolrCore名稱不固定,一個solr運行實例對外單獨提供索引和搜索接口。

solrHome中能夠建立多個solr運行實例SolrCore。

一個solr的運行實例對應一個索引目錄。

conf是SolrCore的配置文件目錄 。

data目錄存放索引文件須要建立

 

3.4.2.   整合步驟

第一步:安裝tomcat。D:\temp\apache-tomcat-7.0.53

第二步:把solr的war包複製到tomcat 的webapp目錄下。

把\solr-4.10.3\dist\solr-4.10.3.war複製到D:\temp\apache-tomcat-7.0.53\webapps下。

更名爲solr.war
第三步:solr.war解壓。使用壓縮工具解壓或者啓動tomcat自動解壓。解壓以後刪除solr.war

第四步:把\solr-4.10.3\example\lib\ext目錄下的全部的jar包(日誌)添加到solr工程中

第五步:配置solrHome和solrCore。

  1)建立一個solrhome(存放solr全部配置文件的一個文件夾)。\solr-4.10.3\example\solr目錄就是一個標準的solrhome。

  2)把\solr-4.10.3\example\solr文件夾複製到D:\temp\0108路徑下,更名爲solrhome,更名不是必須的,是爲了便於理解。

  3)在solrhome下有一個文件夾叫作collection1這就是一個solrcore。就是一個solr的實例。一個solrcore至關於mysql中一個數據庫。Solrcore之間是相互隔離。  

    1. 在solrcore中有一個文件夾叫作conf,包含了索引solr實例的配置信息。
    2. 在conf文件夾下有一個solrconfig.xml。配置實例的相關信息。若是使用默認配置能夠不用作任何修改。

    Xml的配置信息:

    Lib:solr服務依賴的擴展包,默認的路徑是collection1\lib文件夾,若是沒有就建立一個

    dataDir:配置了索引庫的存放路徑。默認路徑是collection1\data文件夾,若是沒有data文件夾,會自動建立。

    requestHandler

 

 

 

第六步:告訴solr服務器配置文件也就是solrHome的位置。修改web.xml使用jndi的方式告訴solr服務器。

Solr/home名稱必須是固定的。

 

 

 

第七步:啓動tomcat

第八步:訪問http://localhost:8080/solr/

 

3.5. Solr後臺管理

3.5.1.   管理界面

 

 

3.5.2.   Dashboard

儀表盤,顯示了該Solr實例開始啓動運行的時間、版本、系統資源、jvm等信息。

3.5.3.   Logging

Solr運行日誌信息

3.5.4.   Cloud

Cloud即SolrCloud,即Solr雲(集羣),當使用Solr Cloud模式運行時會顯示此菜單,以下圖是Solr Cloud的管理界面:

 

 

3.5.5.   Core Admin

Solr Core的管理界面。Solr Core 是Solr的一個獨立運行實例單位,它能夠對外提供索引和搜索服務,一個Solr工程能夠運行多個SolrCore(Solr實例),一個Core對應一個索引目錄。

 

添加solrcore:

第一步:複製collection1更名爲collection2

第二步:修改core.properties。name=collection2

第三步:重啓tomcat

3.5.6.   java properties

Solr在JVM 運行環境中的屬性信息,包括類路徑、文件編碼、jvm內存設置等信息。

 

3.5.7.   Tread Dump

顯示Solr Server中當前活躍線程信息,同時也能夠跟蹤線程運行棧信息。

3.5.8.   Core selector

選擇一個SolrCore進行詳細操做,以下:

 

 

3.5.9.   Analysis

 

 

經過此界面能夠測試索引分析器和搜索分析器的執行狀況。

3.5.10.  Dataimport

能夠定義數據導入處理器,從關係數據庫將數據導入 到Solr索引庫中

3.5.11.  Document

經過此菜單能夠建立索引更新索引刪除索引等操做,界面以下:

 

 

/update表示更新索引,solr默認根據id(惟一約束)域來更新Document的內容,若是根據id值搜索不到id域則會執行添加操做,若是找到則更新。

3.5.12.  Query

 

經過/select執行搜索索引,必須指定「q」查詢條件方可搜索。

3.6. 配置中文分析器

3.6.1.   Schema.xml

schema.xml,在SolrCore的conf目錄下,它是Solr數據表配置文件,它定義了加入索引的數據的數據類型。主要包括FieldTypesFields和其餘的一些缺省設置。

 

 

3.6.1.1  FieldType域類型定義

下邊「text_general」是Solr默認提供的FieldType,經過它說明FieldType定義的內容:

  

FieldType子結點包括:name,class,positionIncrementGap等一些參數:

name:是這個FieldType的名稱

class:是Solr提供的包solr.TextField,solr.TextField 容許用戶經過分析器來定製索引和查詢,分析器包括一個分詞器tokenizer)和多個過濾器filter

positionIncrementGap:可選屬性,定義在同一個文檔中此類型數據的空白間隔,避免短語匹配錯誤,此值至關於Lucene的短語查詢設置slop值,根據經驗設置爲100。

例如:搜索big car,若是document中存的是big  red  car,就沒法搜索到了, positionIncrementGap就是設置big和car中間最大的間隔距離,只要在距離內就能搜索到.

 

在FieldType定義的時候最重要的就是定義這個類型的數據在創建索引進行查詢的時候要使用的分析器analyzer,包括分詞和過濾

 

索引分析器中:使用solr.StandardTokenizerFactory標準分詞器,solr.StopFilterFactory停用詞過濾器,solr.LowerCaseFilterFactory小寫過濾器。

搜索分析器中:使用solr.StandardTokenizerFactory標準分詞器,solr.StopFilterFactory停用詞過濾器,這裏還用到了solr.SynonymFilterFactory同義詞過濾器。

3.6.1.2  Field定義

  solr索引字段在solrhome\collection1\conf\schema.xml配置文件中,相似下面這些,包含在<fields>與</fields>之間的。

  在fields結點內定義具體的Field,filed定義包括name,type(爲以前定義過的各類FieldType),indexed(是否被索引),stored(是否被儲存),multiValued(是否存儲多個值)等屬性。

  以下:

  <field name="name" type="text_general" indexed="true" stored="true"/>

  <field name="features" type="text_general" indexed="true" stored="true" multiValued="true"/>

 

  multiValued:該Field若是要存儲多個值時設置爲true,solr容許一個Field存儲多個值,好比存儲一個用戶的好友id(多個),商品的圖片(多個,大圖和小圖),經過使用solr查詢要看出返回給客戶端是數組:

   

 

3.6.1.3  uniqueKey

Solr中默認定義惟一主鍵keyid域,以下:

   

Solr在刪除、更新索引時使用id域進行判斷,也能夠自定義惟一主鍵。

注意在建立索引時必須指定惟一約束。

3.6.1.4  copyField複製域

copyField複製域,能夠將多個Field複製到一個Field中,以便進行統一的檢索:

好比,輸入關鍵字搜索title標題內容content,

定義title、content、text的域:

 

  

  

根據關鍵字只搜索text域的內容就至關於搜索title和content,將title和content複製到text中,以下:

 

 

3.6.1.5  dynamicField(動態字段)

動態字段就是不用指定具體的名稱,只要定義字段名稱的規則,例如定義一個 dynamicField,name 爲*_i,定義它的type爲text,那麼在使用這個字段的時候,任何以_i結尾的字段都被認爲是符合這個定義的,例如:name_i,gender_i,school_i等。

 

自定義Field名爲:product_title_t,「product_title_t」和scheam.xml中的dynamicField規則匹配成功,以下:

 

「product_title_t」是以「_t」結尾。

 

建立索引

 

 

搜索索引:

 

 

 

3.6.2.   安裝中文分詞器

使用IKAnalyzer中文分析器。

 

第一步:把IKAnalyzer2012FF_u1.jar添加到solr/WEB-INF/lib目錄下。

第二步:複製IKAnalyzer的配置文件自定義詞典停用詞詞典到solr的classpath下。

也就是在apache-tomcat-7.0.54\webapps\solr\WEB-INF目錄下新建classes目錄,將配置文件和詞典放進去.

 

第三步:在schema.xml中添加一個自定義的fieldType,使用中文分析器。

<!-- IKAnalyzer-->

    <fieldType name="text_ik" class="solr.TextField">

      <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>

    </fieldType>

 

第四步:定義field,指定field的type屬性爲text_ik

<!--IKAnalyzer Field-->

   <field name="title_ik" type="text_ik" indexed="true" stored="true" />

   <field name="content_ik" type="text_ik" indexed="true" stored="false" multiValued="true"/>

 

第四步:重啓tomcat

測試:

 

 

3.7. 設置業務系統Field

若是不使用Solr提供的Field能夠針對具體的業務須要自定義一套Field,以下是商品信息Field:

 

<!--product-->

   <field name="product_name" type="text_ik" indexed="true" stored="true"/>

   <field name="product_price"  type="float" indexed="true" stored="true"/>

   <field name="product_description" type="text_ik" indexed="true" stored="false" />

   <field name="product_picture" type="string" indexed="false" stored="true" />

   <field name="product_catalog_name" type="string" indexed="true" stored="true" />

 

   <field name="product_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>

   <copyField source="product_name" dest="product_keywords"/>

   <copyField source="product_description" dest="product_keywords"/>

 

 

4.   Solr管理索引庫

4.1. 維護索引

4.1.1.   添加/更新文檔

添加單個文檔

 

批量導入數據

使用dataimport插件批量導入數據。

第一步:把dataimport插件依賴的jar包添加到solrcore(collection1\lib)中

 

 

還須要mysql的數據庫驅動。

第二步:配置solrconfig.xml文件,添加一個requestHandler

 <requestHandler name="/dataimport"

class="org.apache.solr.handler.dataimport.DataImportHandler">

    <lst name="defaults">

      <str name="config">data-config.xml</str>

     </lst>

  </requestHandler> 

 


第三步:建立一個data-config.xml,保存到collection1\conf\目錄下 

<?xml version="1.0" encoding="UTF-8" ?> 

<dataConfig>  

<dataSource type="JdbcDataSource"  

                driver="com.mysql.jdbc.Driver"  

                url="jdbc:mysql://localhost:3306/lucene"  

                user="root"  

                password="root"/>  

<document>  

       <entity name="product" query="SELECT pid,name,catalog_name,price,description,picture FROM products ">

               <field column="pid" name="id"/>

               <field column="name" name="product_name"/>

               <field column="catalog_name" name="product_catalog_name"/>

               <field column="price" name="product_price"/>

               <field column="description" name="product_description"/>

               <field column="picture" name="product_picture"/>

       </entity>  

</document>  

 

</dataConfig>

 

 

第四步:重啓tomcat

 

第五步:點擊「execute」按鈕導入數據

 

 

導入數據前會先清空索引庫,而後再導入。

 

4.1.2.   刪除文檔

刪除索引格式以下:

 

1) 刪除制定ID的索引

<delete>

       <id>8</id>

</delete>

 

 

2) 刪除查詢到的索引數據

<delete>

       <query>product_catalog_name:幽默雜貨</query>

</delete>

 

3) 刪除全部索引數據

 <delete>

       <query>*:*</query>

</delete>

 

4.2. 查詢索引

經過/select搜索索引,Solr制定一些參數完成不一樣需求的搜索:

 4.2.1  q - 查詢

  1. q - 查詢字符串,必須的,若是查詢全部使用*:*。

  

 

 

  4.2.2  fq - 過濾查詢

  2. fq - (filter query過慮查詢,做用:在q查詢符合結果中同時是fq查詢符合的,例如::

   

 

  過濾查詢價格從1到20的記錄。

  也能夠在「q」查詢條件中使用product_price:[1 TO 20],以下:

   

  也可使用「*」表示無限,例如:

  20以上:product_price:[20 TO *]

  20如下:product_price:[* TO 20]

  4.2.3  sort - 排序

  3. sort - 排序,格式:sort=<field name>+<desc|asc>[,<field name>+<desc|asc>]… 。示例:

按價格降序

   

 4.2.4  start rows - 分頁

  4. start - 分頁顯示使用,開始記錄下標,從0開始

  5. rows - 指定返回結果最多有多少條記錄,配合start來實現分頁。

   

   顯示前10條。

 4.2.5  fl - 指定返回字段

  6. fl - 指定返回那些字段內容,用逗號或空格分隔多個。

   

  顯示商品圖片、商品名稱、商品價格

 4.2.6  df - 指定搜索字段

  7. df-指定一個搜索Field

  

  也能夠在SolrCore目錄 中conf/solrconfig.xml文件中指定默認搜索Field,指定後就能夠直接在「q」查詢條件中輸入關鍵字。

   

4.2.7  wt - 指定出處格式 

  8. wt - (writer type)指定輸出格式,能夠有 xml, json, php, phps, 後面 solr 1.3增長的,要用通知咱們,由於默認沒有打開。

 

4.2.8  hl - 高亮顯示

  9. hl 是否高亮 ,設置高亮Field,設置格式前綴和後綴。

   

 

5.   使用SolrJ管理索引庫

5.1. 什麼是solrJ

solrj是訪問Solr服務的java客戶端,提供索引和搜索的請求方法,SolrJ一般在嵌入在業務系統中,經過SolrJ的API接口操做Solr服務,以下圖:

 

 

 

5.2. 依賴的jar包

 

5.3. 添加文檔

5.3.1.   實現步驟

第一步:建立一個java工程

第二步:導入jar包。包括solrJ的jar包。還須要

 

第三步:使用SolrServer和Solr服務器創建鏈接。HttpSolrServer對象創建鏈接。SolrServer是抽象類,鏈接單機版solr使用httpSolrServer,連接集羣版使用CloudSolrServer。

第四步:建立一個SolrInputDocument對象,而後添加域

第五步:將SolrInputDocument添加到索引庫

第六步:提交

5.3.2.   代碼實現

 1 //向索引庫中添加索引
 2 
 3      @Test
 4 
 5      public void addDocument() throws Exception {
 6 
 7          //和solr服務器建立鏈接
 8 
 9          //參數:solr服務器的地址
10 
11          SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
12 
13          //建立一個文檔對象
14 
15          SolrInputDocument document = new SolrInputDocument();
16 
17          //向文檔中添加域
18 
19          //第一個參數:域的名稱,域的名稱必須是在schema.xml中定義的
20 
21          //第二個參數:域的值
22 
23          document.addField("id", "c0001");
24 
25          document.addField("title_ik", "使用solrJ添加的文檔");
26 
27          document.addField("content_ik", "文檔的內容");
28 
29          document.addField("product_name", "商品名稱");
30 
31          //把document對象添加到索引庫中
32 
33          solrServer.add(document);
34 
35          //提交修改
36 
37          solrServer.commit();
38 
39         
40 
41      }

 

@Test
    public void testIndexCreate() throws Exception{
        //建立和Solr服務端鏈接
        SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
        
        //建立solr文檔對象
        SolrInputDocument doc = new SolrInputDocument();
        //域要先定義後使用,還有注意必需要有id主鍵域
        //solr中沒有專用的修改方法, 會自動根據id進行查找,若是找到了則刪除原來的將新的加入就是修改,若是沒找到,將新的直接加入則就是新增
        doc.addField("id", "a001");
        doc.addField("product_name", "檯燈1`111");
        doc.addField("product_price", "12.5");
        
        //將文檔加入solrServer對象中
        solrServer.add(doc);
        
        //提交
        solrServer.commit();
    }
View Code

 

5.4. 刪除文檔 

5.4.1.   根據id刪除

 1 //刪除文檔,根據id刪除
 2 
 3      @Test
 4 
 5      public void deleteDocumentByid() throws Exception {
 6 
 7          //建立鏈接
 8 
 9          SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
10 
11          //根據id刪除文檔
12 
13          solrServer.deleteById("c0001");
14 
15          //提交修改
16 
17          solrServer.commit();
18 
19      }

 

 

5.4.2.   根據查詢刪除 

查詢語法徹底支持Lucene的查詢語法。

 1 //根據查詢條件刪除文檔
 2 
 3      @Test
 4 
 5      public void deleteDocumentByQuery() throws Exception {
 6 
 7          //建立鏈接
 8 
 9          SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
10 
11          //根據查詢條件刪除文檔,這裏是刪除全部*:*
12 
13          solrServer.deleteByQuery("*:*");
14 
15          //提交修改
16 
17          solrServer.commit();
18 
19      }

 

  

5.5. 修改文檔

在solrJ中修改沒有對應的update方法,只有add方法,只須要添加一條新的文檔,和被修改的文檔id一致就,能夠修改了。本質上就是先刪除後添加

 

5.6. 查詢文檔

5.6.1.   簡單查詢

 1 //查詢索引
 2 
 3      @Test
 4 
 5      public void queryIndex() throws Exception {
 6 
 7          //建立鏈接,連接solr服務端
 8 
 9          SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
10 
11          //建立一個query對象,solr查詢條件對象
12 
13          SolrQuery query = new SolrQuery();
14 
15          //設置查詢條件
16 
17          query.setQuery("*:*");
18 
19          //查詢,執行查詢並獲取查詢響應對象
20 
21          QueryResponse queryResponse = solrServer.query(query);
22 
23          //取查詢結果,從查詢響應中獲取查詢結果集對象
24 
25          SolrDocumentList solrDocumentList = queryResponse.getResults();
26 
27          //共查詢到商品數量
28 
29          System.out.println("共查詢到商品數量:" + solrDocumentList.getNumFound());
30 
31          //遍歷查詢的結果
32 
33          for (SolrDocument solrDocument : solrDocumentList) {
34 
35               System.out.println(solrDocument.get("id"));
36 
37               System.out.println(solrDocument.get("product_name"));
38 
39               System.out.println(solrDocument.get("product_price"));
40 
41               System.out.println(solrDocument.get("product_catalog_name"));
42 
43               System.out.println(solrDocument.get("product_picture"));
44 
45              
46 
47          }
48 
49      }

 

5.6.2.   複雜查詢 

其中包含查詢過濾分頁排序高亮顯示等處理。

例子1:

//複雜查詢索引
    @Test
    public void queryIndex2() throws Exception {
        //建立鏈接
        SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
        //建立一個query對象
        SolrQuery query = new SolrQuery();
        //設置查詢條件
        query.setQuery("鑽石");
        //過濾條件
        query.setFilterQueries("product_catalog_name:幽默雜貨");
        //排序條件
        query.setSort("product_price", ORDER.asc);
        //分頁處理
        query.setStart(0);
        query.setRows(10);
        //結果中域的列表
        query.setFields("id","product_name","product_price","product_catalog_name","product_picture");
        //設置默認搜索域
        query.set("df", "product_keywords");
        //高亮顯示
        query.setHighlight(true);
        //高亮顯示的域
        query.addHighlightField("product_name");
        //高亮顯示的前綴
        query.setHighlightSimplePre("<em>");
        //高亮顯示的後綴
        query.setHighlightSimplePost("</em>");
        //執行查詢
        QueryResponse queryResponse = solrServer.query(query);
        //取查詢結果
        SolrDocumentList solrDocumentList = queryResponse.getResults();
        //共查詢到商品數量
        System.out.println("共查詢到商品數量:" + solrDocumentList.getNumFound());
        //遍歷查詢的結果
        for (SolrDocument solrDocument : solrDocumentList) {
            System.out.println(solrDocument.get("id"));
            //取高亮顯示
            String productName = "";
            Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
            List<String> list = highlighting.get(solrDocument.get("id")).get("product_name");
            //判斷是否有高亮內容
            if (null != list) {
                productName = list.get(0);
            } else {
                productName = (String) solrDocument.get("product_name");
            }
            
            System.out.println(productName);
            System.out.println(solrDocument.get("product_price"));
            System.out.println(solrDocument.get("product_catalog_name"));
            System.out.println(solrDocument.get("product_picture"));
            
        }
    }
View Code

 

 

例子2

 

@Test
    public void testIndexSearch2() throws Exception{
        //鏈接solr服務端
        SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
        
        //建立solr查詢條件對象
        SolrQuery solrQuery = new SolrQuery();
        //查詢關鍵字輸入
        solrQuery.setQuery("檯燈");
        //設置默認搜索域
        solrQuery.set("df", "product_keywords");
        //設置過濾查詢
        solrQuery.addFilterQuery("product_price:[1 TO 100]");
        //設置排序,這裏是降序
        solrQuery.setSort("product_price", ORDER.desc);
        //=======設置分頁========
        //設置起始條數
        solrQuery.setStart(0);
        //設置查詢多少條
        solrQuery.setRows(50);
        
        //========設置高亮顯示=======
        //高亮默認是關閉的,因此要手動開啓
        solrQuery.setHighlight(true);
        //設置須要高亮顯示的域
        solrQuery.addHighlightField("product_name");
        //設置高亮前綴
        solrQuery.setHighlightSimplePre("<span style=\"color:red\">");
        //設置高亮後綴
        solrQuery.setHighlightSimplePost("</span>");
        
        //===================查詢並獲取查詢響應對象=====================================
        QueryResponse queryResponse = solrServer.query(solrQuery);
        //從查詢響應中獲取查詢結果集對象
        SolrDocumentList results = queryResponse.getResults();
        //打印一共查詢到多少條記錄,也就是記錄總數
        System.out.println("=====count====" + results.getNumFound());
        //遍歷查詢結果集
        for(SolrDocument doc : results){
            System.out.println("============="+doc.get("id"));
            //獲取高亮
            Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
            List<String> list = highlighting.get(doc.get("id")).get("product_name");
            if(list != null && list.size() > 0){
                String hlName = list.get(0);
                System.out.println("=======high lighting=====" + hlName);
            }
            
            System.out.println("============="+doc.get("product_name"));
            System.out.println("============="+doc.get("product_price"));
            System.out.println("====================================================");
        }
    }
View Code

 

 

 

6.   案例實現

6.1. 原型分析

 

 

6.2. 系統架構

 

 

6.3. 工程搭建

建立一個web工程導入jar包

  一、springmvc的相關jar包

  二、solrJ的jar包

  三、Example\lib\ext下的jar包

 

6.3.1.   Springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
        
    <context:component-scan base-package="com.itheima.jd"/>
    <!-- 配置註解驅動,若是配置此標籤能夠不用配置處理器映射器和適配器 -->
    <mvc:annotation-driven/>
        <!-- 配置視圖解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- SolrServer的配置 -->
    <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
        <constructor-arg index="0" value="http://localhost:8080/solr"/>
    </bean>
</beans>
View Code

 

6.3.2.   Web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>solr-jd</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <!-- 配置前段控制器 -->
  <servlet>
      <servlet-name>springmvc</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <init-param>
          <!-- 指定springmvc配置文件的路徑 
              若是不指定默認爲:/WEB-INF/${servlet-name}-servlet.xml
          -->
          <param-name>contextConfigLocation</param-name>
          <param-value>classpath:springmvc.xml</param-value>
      </init-param>
  </servlet>
  <servlet-mapping>
      <servlet-name>springmvc</servlet-name>
      <url-pattern>*.action</url-pattern>
  </servlet-mapping>
  <!-- 解決post亂碼問題 -->
  <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
View Code

 

 

6.4. Dao

功能:接收service層傳遞過來的參數,根據參數查詢索引庫,返回查詢結果。

參數:SolrQuery對象

返回值:一個商品列表List<ProductModel>,還須要返回查詢結果的總數量。

返回:ResultModel

方法定義:ResultModel queryProduct(SolrQuery query) throws Exception;

 

 

商品對象模型:

public class ProductModel {
    // 商品編號
    private String pid;
    // 商品名稱
    private String name;
    // 商品分類名稱
    private String catalog_name;
    // 價格
    private float price;
    // 商品描述
    private String description;
    // 圖片名稱
    private String picture;
}

 

 

 

返回值對象模型

public class ResultModel {
    // 商品列表
    private List<ProductModel> productList;
    // 商品總數
    private Long recordCount;
    // 總頁數
    private int pageCount;
    // 當前頁
    private int curPage;
}

 

 

 dao

@Repository
public class ProductDaoImpl implements ProductDao {

    @Autowired
    private SolrServer solrServer;
    
    @Override
    public ResultModel queryProduct(SolrQuery query) throws Exception {
        
        ResultModel resultModel  = new ResultModel();
        //根據query對象查詢商品列表
        QueryResponse queryResponse = solrServer.query(query);
        SolrDocumentList solrDocumentList = queryResponse.getResults();
        //取查詢結果的總數量
        resultModel.setRecordCount(solrDocumentList.getNumFound());
        List<ProductModel> productList = new ArrayList<>();
        //遍歷查詢結果
        for (SolrDocument solrDocument : solrDocumentList) {
            //取商品信息
            ProductModel productModel = new ProductModel();
            productModel.setPid((String) solrDocument.get("id"));
            //取高亮顯示
            String productName = "";
            Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
            List<String> list = highlighting.get(solrDocument.get("id")).get("product_name");
            if (null != list) {
                productName = list.get(0);
            } else {
                productName = (String) solrDocument.get("product_name");
            }
            productModel.setName(productName);
            if(null == doc.get("product_price")){
                productModel.setPrice(0f);
            }else{
                productModel.setPrice((float)doc.get("product_price"));
            }
            productModel.setCatalog_name((String) solrDocument.get("product_catalog_name"));
            productModel.setPicture((String) solrDocument.get("product_picture"));
            //添加到商品列表
            productList.add(productModel);
        }
        //商品列表添加到resultmodel中
        resultModel.setProductList(productList);
        return resultModel;
    }

}
View Code

 

6.5. Service 

功能:接收action傳遞過來的參數,根據參數拼裝一個查詢條件,調用dao層方法,查詢商品列表。接收返回的商品列表和商品的總數量,根據每頁顯示的商品數量計算總頁數。

參數:

  一、查詢條件:字符串

  二、商品分類的過濾條件:商品的分類名稱,字符串

  三、商品價格區間:傳遞一個字符串,知足格式:「0-100、101-200、201-*」

  四、排序條件:頁面傳遞過來一個升序或者降序就能夠,默認是價格排序。0:升序1:降序

  五、分頁信息:每頁顯示的記錄條數建立一個常量60條。傳遞一個當前頁碼就能夠了。

業務邏輯

  一、根據參數建立查詢對象

  二、調用dao執行查詢。

  三、根據總記錄數計算總頁數。

  返回值:ResultModel

 

方法定義:ResultModel queryProduct(String queryString, String caltalog_name, String price, String sort, Integer page) throws Exception;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDao productDao;
    
    @Override
    public ResultModel queryProduct(String queryString, String caltalog_name,
            String price, String sort, Integer page) throws Exception {
        //拼裝查詢條件
        SolrQuery query = new SolrQuery();
        //查詢條件
        if (null != queryString && !"".equals(queryString)) {
            query.setQuery(queryString);
        } else {
            query.setQuery("*:*");
        }
        //商品分類名稱過濾
        if (null != caltalog_name && !"".equals(caltalog_name)) {
            query.addFilterQuery("product_catalog_name:" + caltalog_name);
        }
        //價格區間過濾
        if (null != price && !"".equals(price)) {
            String[] strings = price.split("-");
            query.addFilterQuery("product_price:["+strings[0]+" TO "+strings[1]+"]");
        }
        //排序條件
        if ("1".equals(sort)) {
            query.setSort("product_price", ORDER.desc);
        } else {
            query.setSort("product_price", ORDER.asc);
        }
        //分頁處理
        if (null == page) {
            page = 1;
        }
        //start
        int start = (page-1) * Commons.PAGE_SIZE;
        query.setStart(start);
        query.setRows(Commons.PAGE_SIZE);
        //設置默認搜索域
        query.set("df", "product_keywords");
        //高亮設置
        query.setHighlight(true);
        query.addHighlightField("product_name");
        query.setHighlightSimplePre("<span style=\"color:red\">");
        query.setHighlightSimplePost("</span>");
        
        //查詢商品列表
        ResultModel resultModel = productDao.queryProduct(query);
        //計算總頁數
        long recordCount = resultModel.getRecordCount();
        int pages = (int) (recordCount/Commons.PAGE_SIZE);
        if (recordCount % Commons.PAGE_SIZE > 0) {
            pages ++;
        }
        resultModel.setPageCount(pages);
        resultModel.setCurPage(page);
        
        return resultModel;
    }

}
View Code

 

6.6. controller 

功能:接收頁面傳遞過來的參數調用service查詢商品列表。將查詢結果返回給jsp頁面,還須要查詢參數的回顯。

 

參數:

  一、查詢條件:字符串

  二、商品分類的過濾條件:商品的分類名稱,字符串

  三、商品價格區間:傳遞一個字符串,知足格式:「0-100、101-200、201-*」

  四、排序條件:頁面傳遞過來一個升序或者降序就能夠,默認是價格排序。0:升序1:降序

  五、分頁信息:每頁顯示的記錄條數建立一個常量60條。傳遞一個當前頁碼就能夠了。

  六、Model:至關於request。

 

  返回結果:String類型,就是一個jsp的名稱。

 

方法定義:String queryProduct(String queryString, String caltalog_name, String price, String sort, Integer page, Model model) throws Exception;

@Controller

public class ProductAction {

    

     @Autowired

     private ProductService productService;

    

     @RequestMapping("/list")

     public String queryProduct(String queryString, String catalog_name, String price,

              String sort, Integer page, Model model) throws Exception {

         //查詢商品列表

         ResultModel resultModel = productService.queryProduct(queryString, catalog_name, price, sort, page);

         //列表傳遞給jsp

         model.addAttribute("result", resultModel);

         //參數回顯

         model.addAttribute("queryString", queryString);

         model.addAttribute("caltalog_name", catalog_name);

         model.addAttribute("price", price);

         model.addAttribute("sort", sort);

         model.addAttribute("page", page);

         

         return "product_list";

     }

}
View Code

7.  總結

  • 7.1.  solr是一個全文檢索引擎系統,經過部署到tomcat下就能夠獨立運行,經過http協議對外提供全文檢索服務,就是索引和文檔的正刪改查服務

  • 7.2.  solr直接操做索引庫和文檔庫, 咱們的業務系統中可使用solrJ(solr的客戶端,就是一堆jar包)來調用solr服務端,讓solr服務端操做文檔庫和索引庫,完成正刪改查的任務,將結果返回給solrJ客戶端,咱們在業務系統中就能夠,獲取到結果真後返回給客戶在瀏覽器中顯示.

  • 7.3.  solrHome:solrhome就是solr最核心的目錄, 一個solrhome中能夠有多個solr實例

  • 7.4.  solrCore:一個solrCore就是一個solr實例,solr中實例與實例之間他們的索引庫和文檔庫是相互隔離的每一個實例對外單獨的提供索引和文檔的增刪改查服務,默認實例叫作collection1

  • 7.5.  文檔和索引的增長和修改必需要有id, 主鍵域,沒有會報錯

  • 7.6.  域名和類型必須先在schema.xml中定義後使用,若是沒有定義就使用會報錯

  • 7.7.  域的分類

      普通域:string long 等

      動態域:起到模糊匹配的效果,能夠模糊匹配沒有定義過的域名
        例如:xxxx這個域名沒有定義,可是xxxx_s這個域名模糊匹配了*_s這個域,因此至關於xxxx_s這個域定義了

      主鍵域:<uniqueKey>id</uniqueKey> 通常主鍵域就用默認的這個就能夠不須要更改或者添加

      複製域: 複製域用於查詢的時候從多個域中進行查詢,這樣能夠將多個域複製到某一個統一的域中,而後搜索的時候從這個統一的域中進行查詢,就至關於從多個域中查詢了.

  • 7.8.  是否存儲和是否索引無關, 索引後就能查詢,不索引就不能根據這個域搜索, 存儲後就能取出來裏面的內容,不存儲就取不出這個域內容

  • 7.9.  通常企業中將數據所有放入數據庫中, 因爲查詢的時候須要使用like模糊查詢,模糊查詢數據庫中使用的是全表掃描算法,這樣效率低級,因此須要使用全文檢索,來優化查詢速度.
相關文章
相關標籤/搜索