搜索引擎solr

企業級搜索solr應用

一 。solr簡介

    solr是以lucene爲內核開發的企業級搜索應用  應用程序可以通過http請求方式來提交索引,查詢索引,提供了比lucene更豐富的查詢語言,是

一個高性能,高可用環境全文搜索引擎

二 。solr安裝配置

     1》下載solr安裝包  solr所有版本 (http://archive.apache.org/dist/lucene/solr/) 

           這裏下載 solr-5.5.4

     2》安裝 解壓將solr-5.5.4\server\solr-webapp下的webapp 拷貝到tomcat\webapps目錄下 改名爲solr 啓動tomcat

       直接訪問 出現404  找到tomcat/logs/localhost.2017-08-17.log 日誌  出現以下異常

[html] view plain copy
  1. java.lang.NoClassDefFoundError: Failed to initialize Apache Solr: Could not find necessary SLF4j logging jars.   
  2. If using Jetty, the SLF4j logging jars need to go in the jetty lib/ext directory. For other containers,   
  3. the corresponding directory should be used. For more information, see: http://wiki.apache.org/solr/SolrLogging  
  4.     at org.apache.solr.servlet.CheckLoggingConfiguration.check(CheckLoggingConfiguration.java:27)  
  5.     at org.apache.solr.servlet.BaseSolrFilter.<clinit>(BaseSolrFilter.java:30)  


      可用看到缺少SLF4j包 應該去 應該去 解壓包 /server/lib/ext下找到並拷貝到 tomcat/solr/lib目錄下  然後重啓

    繼續訪問 出現以下錯誤 

[html] view plain copy
  1. java.lang.NoSuchMethodError: javax.servlet.ServletInputStream.isFinished()Z  
  2.     org.apache.solr.servlet.SolrDispatchFilter.consumeInputFully(SolrDispatchFilter.java:284)  
  3.     org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:274)  
  4.     org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208)  
    明顯是Servlet版本不一致  tomcat6不支持solr5.54 加大tomcat版本 tomcat7也不支持 換成tomcat8  啓動後訪問 依然錯誤:

[html] view plain copy
  1. org.apache.solr.common.SolrException: Error processing the request. CoreContainer is either not initialized or shutting down.  
  2.     org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:217)  
  3.     org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208)  
   是因爲需要配置solrhome和solrhome的配置環境

   3》配置solrhome

     找到 tomcat\solr\WEB-INF\web.xml 編輯  找到以下這段(配置solrhome)  去掉註釋 將第二個參數配置爲本地任意一個目錄即可 

[html] view plain copy
  1. <env-entry>  
  2.    <env-entry-name>solr/home</env-entry-name>  
  3.    <env-entry-value>D:\learn\solr-5.5.4\home</env-entry-value>  
  4.    <env-entry-type>java.lang.String</env-entry-type>  
  5. </env-entry>  
   找到solr解壓包/server/solr目錄拷貝所有文件到 以上web.xml指定的路徑D:\learn\solr-5.5.4\home下 重啓tomcat 訪問

   http://localhost:8080/solor/index.html  或者 http://localhost:8080/solr/admin.html  

  

   4》配置core(core類似於數據庫可以插入多個document(數據庫錶行)每個document擁有多個 field 數據庫的列)

   solrhome下新建一個core目錄  比如mycore

   拷貝 solr解壓包下\server\solr\configsets\basic_configs到新建目錄 mycore中

  進入solr管理網頁 點擊 core admin 添加該core

 

  點擊Add core後 成功後 檢查 mycore目錄 發現多了 core.properties和data兩個資源


 登陸solr管理網站發現 列表中多了mycore


 4》配置文件理解

    core/conf目錄下的兩個配置文件非常重要 

    managed-schema 主要用於配置 可以提交到該core的所有field定義,field的類型定義,唯一標識符等

    常用配置如下:

[html] view plain copy
  1. 定義字段 _version_ 類型爲long  indexed="true" 會進行分詞索引  stored="true"表示存儲到磁盤  
  2. <field name="_version_" type="long" indexed="true" stored="true"/>  
  3. 定義字段 id required="true" 表示所有的document必須添加id字段 multiValued="false" 表示是否是多值字段  
  4. <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />   
  5. 定義動態字段 所以_i結尾的字段都可以寫入到當前的core  
  6. <dynamicField name="*_i"  type="int"    indexed="true"  stored="true"/>  
  7. 定義唯一標識符的字段  
  8. <uniqueKey>id</uniqueKey>  
  9. 定義字段類型的別名  
  10. <fieldType name="string" class="solr.StrField" sortMissingLast="true" />  
  solrconfig.xml 主要用於配置solor的主要配置信息 比如lucene版本 緩存 數據目錄 請求路徑映射 等 

[html] view plain copy
  1. 表示lucene版本  
  2. <luceneMatchVersion>5.5.4</luceneMatchVersion>  
  3. 表示數據目錄 默認是data目錄  
  4. <dataDir>${solr.data.dir:}</dataDir>   
  5. 自動提交配置  
  6. <autoCommit>   
  7.        當超過15000ms後自動提交所有數據  
  8.        <maxTime>${solr.autoCommit.maxTime:15000}</maxTime>   
  9.        是否馬上就可以查詢到  
  10.        <openSearcher>false</openSearcher>   
  11. </autoCommit>  
  12. 表示當路徑爲 /select時查詢所有的數據  
  13. <requestHandler name="/select" class="solr.SearchHandler">  
  14.     <!-- default values for query parameters can be specified, these  
  15.          will be overridden by parameters in the request  
  16.       -->  
  17.      <lst name="defaults">  
  18.        <str name="echoParams">explicit</str>  
  19.        <int name="rows">10</int>  
  20.      </lst>  
  21. </requestHandler>  
 嘗試在界面上添加數據和查詢數據

 添加數據

 



 查詢結果

 

查詢的參數列表

  q表示查詢的條件  字段名:值的格式

  fq表示filter query 過濾條件 和q是and的關係支持各種邏輯運算符 (參考https://cwiki.apache.org/confluence/display/solr/The+Standard+Query+Parser)

  sort表示排序 的字段  字段名 asc|desc 

  start 表示從第幾行開始  rows表示查詢的總行數

  fl表示查詢顯示的列 比如只需要查詢 name_s,sex_i 這兩列 使用,隔開

  df表示默認的查詢字段 一般不設置

  Raw Query Parameters表示原始查詢字段 可以使用 start=0&rows=10這種url的方式傳入參數

  wt(write type)表示寫入的格式 可以使用json和xml

  shards 多核同時搜索 solrhome拷貝mycore爲mycore1  管理平臺添加core   設置參數爲 路徑,路徑來設置需要搜索的核

[html] view plain copy
  1. String shards = "localhost:8080/solr/mycore,localhost:8080/solr/mycore1";   
  2. query.set("shards", shards);  

  其他參考(https://cwiki.apache.org/confluence/display/solr/Common+Query+Parameters)

 5》配置中文分詞器

   默認solr 沒有使用中文分詞器  所有搜索的詞 都是整個句子就是一個詞 搜索時 將單詞全部寫入才能搜索或者使用* 需要配置中文分詞器

目前比較好用的分詞器 是IK  2012年停更 只支持到 Lucene4.7 所有 solr5.5 需要lucene5支持  需要修改部分源碼來支持solr5.5

 找到 IKAnalyzer類   需要重寫  protected TokenStreamComponents createComponents(String fieldName) 方法

 找到 IKTokenizer類 需要重寫構造方法  public IKTokenizer(Reader in, boolean useSmart) 爲  public IKTokenizer(boolean useSmart) {

 在任意項目中 使用maven 引用lucene5 和ik

[html] view plain copy
  1. <dependency>  
  2.           <groupId>org.apache.lucene</groupId>  
  3.           <artifactId>lucene-core</artifactId>  
  4.           <version>5.3.1</version>  
  5.         </dependency>  
  6.         <dependency>  
  7.             <groupId>com.janeluo</groupId>  
  8.             <artifactId>ikanalyzer</artifactId>  
  9.             <version>2012_u6</version>  
  10.             <exclusions>  
  11.                 <exclusion>  
  12.                     <groupId>org.apache.lucene</groupId>  
  13.                      <artifactId>lucene-core</artifactId>  
  14.                 </exclusion>  
  15.             </exclusions>  
  16.         </dependency>  
在項目中 添加完整的包名和類名 和 ik中一致 拷貝源代碼



代碼修改對應的方法即可

IKAnalyzer

[html] view plain copy
  1. /**  
  2.   
  3.  *  
  4.  */  
  5. package org.wltea.analyzer.lucene;  
  6.   
  7. import java.io.Reader;  
  8.   
  9. import org.apache.lucene.analysis.Analyzer;  
  10. import org.apache.lucene.analysis.Tokenizer;  
  11.   
  12. /**  
  13.  */  
  14. public final class IKAnalyzer extends Analyzer {  
  15.   
  16.   private boolean useSmart;  
  17.   
  18.   public boolean useSmart() {  
  19.     return useSmart;  
  20.   }  
  21.   
  22.   public void setUseSmart(boolean useSmart) {  
  23.     this.useSmart = useSmart;  
  24.   }  
  25.   
  26.   /**  
  27.   
  28.    */  
  29.   public IKAnalyzer() {  
  30.     this(false);  
  31.   }  
  32.   
  33.   /**  
  34.    */  
  35.   public IKAnalyzer(boolean useSmart) {  
  36.     super();  
  37.     this.useSmart = useSmart;  
  38.   }  
  39.   
  40.   /**這裏就去掉了 Reader的一個參數  
  41.    */  
  42.   @Override  
  43.   protected TokenStreamComponents createComponents(String fieldName) {  
  44.     Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart());  
  45.     return new TokenStreamComponents(_IKTokenizer);  
  46.   }  
  47.   
  48. }  
IKTokenizer

[html] view plain copy
  1. /**  
  2.  *   
  3.  */  
  4. package org.wltea.analyzer.lucene;  
  5.   
  6. import java.io.IOException;  
  7. import java.io.Reader;  
  8.   
  9. import org.apache.lucene.analysis.Tokenizer;  
  10. import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;  
  11. import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;  
  12. import org.apache.lucene.analysis.tokenattributes.TypeAttribute;  
  13.   
  14. import org.wltea.analyzer.core.IKSegmenter;  
  15. import org.wltea.analyzer.core.Lexeme;  
  16.   
  17.   
  18. public final class IKTokenizer extends Tokenizer {  
  19.   
  20.   
  21.   private IKSegmenter _IKImplement;  
  22.   
  23.   
  24.   private final CharTermAttribute termAtt;  
  25.   
  26.   private final OffsetAttribute offsetAtt;  
  27.   
  28.   private final TypeAttribute typeAtt;  
  29.   
  30.   private int endPosition;  
  31.   
  32.   //去掉了其中Reader的第一個構造參數  
  33.   public IKTokenizer(boolean useSmart) {  
  34.     super();//去掉super中的構造參數  
  35.     offsetAtt = addAttribute(OffsetAttribute.class);  
  36.     termAtt = addAttribute(CharTermAttribute.class);  
  37.     typeAtt = addAttribute(TypeAttribute.class);  
  38.     _IKImplement = new IKSegmenter(input, useSmart);  
  39.   }  
  40.   
  41.    
  42.   @Override  
  43.   public boolean incrementToken() throws IOException {  
  44.   
  45.     clearAttributes();  
  46.     Lexeme nextLexeme = _IKImplement.next();  
  47.     if (nextLexeme != null) {  
  48.   
  49.       termAtt.append(nextLexeme.getLexemeText());  
  50.      
  51.       termAtt.setLength(nextLexeme.getLength());  
  52.         
  53.       offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());  
  54.      
  55.       endPosition = nextLexeme.getEndPosition();  
  56.     
  57.       typeAtt.setType(nextLexeme.getLexemeTypeString());  
  58.   
  59.       return true;  
  60.     }  
  61.   
  62.     return false;  
  63.   }  
  64.   
  65.   /*  
  66.    * (non-Javadoc)  
  67.    * @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)  
  68.    */  
  69.   @Override  
  70.   public void reset() throws IOException {  
  71.     super.reset();  
  72.     _IKImplement.reset(input);  
  73.   }  
  74.   
  75.   @Override  
  76.   public final void end() {  
  77.     // set final offset  
  78.     int finalOffset = correctOffset(this.endPosition);  
  79.     offsetAtt.setOffset(finalOffset, finalOffset);  
  80.   }  
  81. }  
將編譯好的class文件替換原始jar包即可

將solrhome下 配置文件managed-schema 添加一個字段類型 使用ik分詞器

[html] view plain copy
  1. <fieldType name="text_ik" class="solr.TextField" >  
  2.       <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>     
  3.       <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>   
  4.     </fieldType>  
不能修改 StrField 不支持自定義分詞器

<fieldType name="string" class="solr.StrField" sortMissingLast="true" >
</fieldType>


然後將對應需要進行中文分詞的字段使用 text_ik該字段類型 比如

[html] view plain copy
  1. <dynamicField name="*_s"  type="text_ik"  indexed="true"  stored="true" />  
重啓 或者 cloud環境下重新生成collection 插入數據即可實現中文分詞  通過某些中文關鍵字搜索

三。solr客戶端

  solr提供的solrj java客戶端可以使用java來添加和查詢索引 

使用maven引入solrj的依賴庫

[html] view plain copy
  1. <!-- https://mvnrepository.com/artifact/org.apache.solr/solr-solrj -->  
  2. <dependency>  
  3.     <groupId>org.apache.solr</groupId>  
  4.     <artifactId>solr-solrj</artifactId>  
  5.     <version>5.5.3</version>  
  6. </dependency>  
使用客戶端操作添加和查詢索引的代碼

[html] view plain copy
  1. public class TestCrud {  
  2.     //請求的url  
  3.     public static final String url="http://localhost:8080/solr/mycore";  
  4.     /**  
  5.      * 測試寫入數據到solr  
  6.      * @throws IOException   
  7.      * @throws SolrServerException   
  8.      */  
  9.     @Test  
  10.     public void testWriteDoc() throws SolrServerException, IOException{  
  11.         HttpSolrClient hsc=new HttpSolrClient(url);  
  12.         SolrInputDocument sid=new SolrInputDocument();  
  13.         sid.addField("id", 1);  
  14.         sid.addField("name_s","張三");  
  15.         hsc.add(sid);  
  16.         hsc.commit();  
  17.         hsc.close();  
  18.     }  
  19.     /**  
  20.      * 測試從solr讀取數據  
  21.      * @throws IOException   
  22.      * @throws SolrServerException   
  23.      */  
  24.     @Test  
  25.     public void testReadDoc() throws SolrServerException, IOException{  
  26.         HttpSolrClient hsc=new HttpSolrClient(url);  
  27.         SolrQuery sq=new SolrQuery();  
  28.         sq.setQuery("name_s:*");  
  29.         sq.set("sort", "id asc");  
  30.         sq.setStart(0);  
  31.         sq.setRows(1);  
  32.         SolrDocumentList sdl=hsc.query(sq).getResults();  
  33.         for(SolrDocument sd:sdl){  
  34.             System.out.println(sd.getFieldValue("name_s"));  
  35.         }  
  36.         hsc.close();  
  37.     }  
  38.     /**  
  39.      * 測試通過id刪除  
  40.      * @throws IOException   
  41.      * @throws SolrServerException   
  42.      */  
  43.     @Test  
  44.     public void testDelDoc() throws SolrServerException, IOException{  
  45.         HttpSolrClient hsc=new HttpSolrClient(url);  
  46.         hsc.deleteById("1");  
  47.         hsc.commit();  
  48.         hsc.close();  
  49.     }  
  50. }  

使用javabean的方式操作

javabean定義

[html] view plain copy
  1. import org.apache.solr.client.solrj.beans.Field;  
  2. public class UserInfo {  
  3.     public UserInfo() {  
  4.     }  
  5.     @Field  
  6.     private String id;  
  7.     @Field  
  8.     private String name_s;  
  9.     @Field  
  10.     private int age_i;  
  11. }  
執行代碼如下:

[html] view plain copy
  1. /**  
  2.      * 測試寫入數據到solr  
  3.      * @throws IOException   
  4.      * @throws SolrServerException   
  5.      */  
  6.     @Test  
  7.     public void testWriteDoc() throws SolrServerException, IOException{  
  8.         HttpSolrClient hsc=new HttpSolrClient(url);  
  9.         UserInfo ui=new UserInfo();  
  10.         ui.setId("2");  
  11.         ui.setName_s("李四");  
  12.         ui.setAge_i(100);  
  13.         hsc.addBean(ui);  
  14.         hsc.commit();  
  15.         hsc.close();  
  16.     }  
  17.     /**  
  18.      * 測試從solr讀取數據  
  19.      * @throws IOException   
  20.      * @throws SolrServerException   
  21.      */  
  22.     @Test  
  23.     public void testReadDoc() throws SolrServerException, IOException{  
  24.         HttpSolrClient hsc=new HttpSolrClient(url);  
  25.         SolrQuery sq=new SolrQuery();  
  26.         sq.setQuery("name_s:*");  
  27.         sq.set("sort", "id asc");  
  28.         sq.setStart(0);  
  29.         sq.setRows(1);  
  30.         List<UserInfo> sdl=hsc.query(sq).getBeans(UserInfo.class);  
  31.         for(UserInfo sd:sdl){  
  32.             System.out.println(sd.getName_s());  
  33.         }  
  34.         hsc.close();  
  35.     }  


四。solr集羣安裝

  1》集羣方式:

   solr集羣目前有兩種方式 主從模式和solrcloud模式(推薦方式)

solrcloud通過zookeeper管理集羣 通過將索引切片的方式分發到不同的後端服務器中 後端服務器 可以通過一主多從的方式來實現高可用  一主多從

通過leader的管理方式 leader負責寫入  從機負責分攤併發讀取  leader掛掉後 從機選舉出新的leader繼續進行管理

 2》solrcloud集羣概念

   solrcloud分爲邏輯層和物理層 

   邏輯層:

      》Cluster(表示zookeeper集羣) 用於管理solrcloud的實例collection

      》Collection 表示一個solrcloud的實例 能夠被切分爲多個片

      》Shards (片) 一個Collection 可以被切分爲多個片 片的個數決定了併發量的大小 每個片擁有多個備份 其中包括leader 負責寫入  replica負責容災和讀請求

                   

  物理層:

      》 Cluster由多個solr 節點(物理機器)組成  每個節點對應linux的後臺進程

      》 Node(節點) 每個節點由多個Core組成   

      》 Core 每個片在該節點的拷貝都屬於一個core  可能每個片都有一份拷貝在當前機器上 當前機器 可能有多個core

      》Replica 是每個切片的一份拷貝  必須使用使用相同的配置 該配置需要寫入到zookeeper中 

      

 3》solrcloud集羣實現(僞集羣)

   》》拷貝三份tomcat  分別修改server.xml tomcat端口  (8080,8081,8082)

   》》同單機安裝拷貝solr應用到webapps目錄下 修改web.xml 分別指向不同的solrhome

           比如我的配置  

tomcat1 8080 D:\learn\solr-5.5.4\home
tomcat2 8081 D:\learn\solr-5.5.4\home1
tomcat3 8082 D:\learn\solr-5.5.4\home2

   》》拷貝 solr解壓包下\server\solr到新建目錄D:\learn\solr-5.5.4\home中 同時拷貝到hom1和home2     

            solr解壓包下\server\solr\configsets\basic_configs到新建目錄D:\learn\solr-5.5.4\home(只拷貝home 不拷貝home1和home2) 改名爲

           collections1 

   》》tomcat/bin下的 catalina.cmd添加  

tomcat1下設置爲:

[html] view plain copy
  1. set JAVA_OPTS=-Dsolr.solr.home=D:/learn/solr-5.5.4/home -Dbootstrap_confdir=D:/learn/solr-5.5.4/home/collection1/conf   
  2. -Dcollection.configName=myconf -DnumShards=3 -DzkHost=localhost:2181  
其他tomcat 設置爲 

[html] view plain copy
  1. set JAVA_OPTS=-Dsolr.solr.home=D:/learn/solr-5.5.4/home  -DzkHost=localhost:2181  
  》》這裏假設本機開啓了zookeeper 端口是2181 當然可以開啓多個zookeeper地址使用,隔開(參考http://blog.csdn.net/liaomin416100569/article/details/71642091)

  依次啓動 zookeeper  和所有的tomcat  訪問 http://localhost:8080/solr/admin.html

  》》使用命令創建collection (其他操作參考 https://cwiki.apache.org/confluence/display/solr/Collections+API)

[html] view plain copy
  1. http://localhost:8081/solr/admin/collections?action=CREATE&name=collection1&numShards=3&replicationFactor=3&maxShardsPerNode=3&collection.configName=myconf  

  》》查看zookeeper信息和集羣分片信息

 查看zookeeper中寫入的數據

   

查看分片到哪些節點



五。solr一些其他高級查詢(參考代碼)

[html] view plain copy
  1. package cn.et.solor;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import org.apache.solr.client.solrj.SolrQuery;  
  8. import org.apache.solr.client.solrj.SolrRequest;  
  9. import org.apache.solr.client.solrj.SolrServerException;  
  10. import org.apache.solr.client.solrj.impl.CloudSolrClient;  
  11. import org.apache.solr.client.solrj.response.FacetField;  
  12. import org.apache.solr.client.solrj.response.Group;  
  13. import org.apache.solr.client.solrj.response.GroupCommand;  
  14. import org.apache.solr.client.solrj.response.GroupResponse;  
  15. import org.apache.solr.client.solrj.response.PivotField;  
  16. import org.apache.solr.client.solrj.response.QueryResponse;  
  17. import org.apache.solr.client.solrj.response.FacetField.Count;  
  18. import org.apache.solr.common.params.GroupParams;  
  19. import org.apache.solr.common.util.NamedList;  
  20. import org.junit.Test;  
  21. /**  
  22.  * 支持一些高級特性 比如高亮 分類 分組 mtl(相似)  
  23. {"id":"1","country_s":"美國","provice_s":"加利福尼亞州","city_s":"舊金山","age_i":"30","name_s":"John","desc_s":"John is come from austrina  John,s Dad is Johh Super"}  
  24. {"id":"2","country_s":"美國","provice_s":"加利福尼亞州","city_s":"好萊塢","age_i":"40","name_s":"Mike","desc_s":"Mike is come from austrina  Mike,s Dad  is Mike Super"}  
  25. {"id":"3","country_s":"美國","provice_s":"加利福尼亞州","city_s":"聖地牙哥","age_i":"50","name_s":"Cherry","desc_s":"Cherry is come from austrina  Cherry,s Dad  is Cherry Super"}  
  26. {"id":"4","country_s":"美國","provice_s":"德克薩斯州","city_s":"休斯頓","age_i":"60","name_s":"Miya","desc_s":"Miya is come from austrina  Miya,s Dad  is Miya Super"}  
  27. {"id":"5","country_s":"美國","provice_s":"德克薩斯州","city_s":"大學城","age_i":"70","name_s":"fubos","desc_s":"fubos is come from austrina  fubos,s Dad  is fubos Super"}  
  28. {"id":"6","country_s":"美國","provice_s":"德克薩斯州","city_s":"麥亞倫","age_i":"20","name_s":"marry","desc_s":"marry is come from austrina  marry,s Dad  is marry Super"}  
  29. {"id":"7","country_s":"中國","provice_s":"湖南省","city_s":"長沙市","age_i":"18","name_s":"張三","desc_s":"張三來自長沙市 是公務員一名"}  
  30. {"id":"8","country_s":"中國","provice_s":"湖南省","city_s":"岳陽市","age_i":"15","name_s":"李四","desc_s":"李四來自岳陽市 是一名清潔工"}  
  31. {"id":"9","country_s":"中國","provice_s":"湖南省","city_s":"株洲市","age_i":"33","name_s":"李光四","desc_s":"李光四 老家岳陽市 來自株洲 是李四的侄子"}  
  32. {"id":"10","country_s":"中國","provice_s":"廣東省","city_s":"深圳市","age_i":"67","name_s":"王五","desc_s":"王五來自深圳市  是來自深圳的一名海關緝私精英"}  
  33. {"id":"11","country_s":"中國","provice_s":"廣東省","city_s":"廣州市","age_i":"89","name_s":"王冠宇","desc_s":"王冠宇是王五的兒子"}  
  34.  */  
  35. public class TestCloud {  
  36.     /**  
  37.      * 連接solrcloud  
  38.      * @return  
  39.      */  
  40.     public CloudSolrClient getCloudSolrClient(){  
  41.         String zkHost="localhost:2181";  
  42.         CloudSolrClient csc=new CloudSolrClient(zkHost);  
  43.         csc.setDefaultCollection("collection1");//集合名稱  
  44.         return csc;  
  45.     }  
  46.     /**  
  47.      * solrcloud保存 修改 刪除和單機相同  
  48.      */  
  49.     @Test  
  50.     public void save() throws IOException, SolrServerException{  
  51.         CloudSolrClient csc=getCloudSolrClient();  
  52.         UserInfo ui=new UserInfo();  
  53.         ui.setId("4");  
  54.         ui.setName_s("王五");  
  55.         ui.setAge_i(100);  
  56.         csc.addBean(ui);  
  57.         csc.commit();  
  58.         csc.close();  
  59.     }  
  60.     /**  
  61.      * solrcloud 刪除  
  62.      */  
  63.     //@Test  
  64.     public void delete() throws IOException, SolrServerException{  
  65.         CloudSolrClient csc=getCloudSolrClient();  
  66.         csc.deleteByQuery("*:*");  
  67.         csc.commit();  
  68.         csc.close();  
  69.     }  
  70.   
  71.     /**  
  72.      * solrcloud高亮顯示  
  73.      * 必須設置中文分詞器  
  74.      */  
  75.     @Test  
  76.     public void queryHign() throws IOException, SolrServerException{  
  77.         CloudSolrClient csc=getCloudSolrClient();  
  78.         SolrQuery sq=new SolrQuery();  
  79.         sq.setQuery("desc_s:王五");  
  80.         sq.addHighlightField("desc_s");  
  81.         sq.setHighlight(true);  
  82.         sq.setHighlightSimplePre("<font color=red>");  
  83.         sq.setHighlightSimplePost("</font>");  
  84.         QueryResponse qr=csc.query(sq);  
  85.         List<UserInfo> userInfo=qr.getBeans(UserInfo.class);  
  86.         Map<String, Map<String, List<String>>> highlighting = qr.getHighlighting();  
  87.         System.out.println(highlighting);  
  88.         for(UserInfo ui:userInfo){  
  89.             System.out.println(ui.getName_s());  
  90.         }  
  91.         System.out.println(userInfo.size());  
  92.         csc.commit();  
  93.         csc.close();  
  94.     }  
  95.       
  96.     /**  
  97.      * Facet 面 用於對搜索的結果進行分類   
  98.      *  比如按國家分類   addFacetField 表示按某些字段進行分類是普通分類  結果爲:  
  99.      *   country_s  
  100.             美國:6  
  101.             中國:5  
  102.         sq.addFacetQuery("age_i:[1 TO 20]");  
  103.         sq.addFacetQuery("age_i:[21 TO 50]");  
  104.         sq.addFacetQuery("age_i:[51 TO *]");  
  105.         可以將多個範圍值 添加到FacetQuery可以獲取到這些Query的統計數量 比如  
  106.          {age_i:[1 TO 20]=3, age_i:[20 TO 50]=5, age_i:[50 TO *]=5}   
  107.         其他 參考 https://wiki.apache.org/solr/SimpleFacetParameters#facet.query_:_Arbitrary_Query_Faceting   
  108.      */  
  109.     @Test  
  110.     public void queryFacet() throws IOException, SolrServerException{  
  111.         CloudSolrClient csc=getCloudSolrClient();  
  112.         SolrQuery sq=new SolrQuery();  
  113.           
  114.         sq.setFacet(true);  
  115.         //按字段分類 相同的歸於一類  
  116.         sq.addFacetField("country_s");  
  117.         //特殊分類 添加範圍  
  118.         sq.addFacetQuery("age_i:[1 TO 20]");  
  119.         sq.addFacetQuery("age_i:[21 TO 50]");  
  120.         sq.addFacetQuery("age_i:[51 TO *]");  
  121.         //這隻facet字段分類的前綴  
  122.         sq.setFacetPrefix("");  
  123.         //根據 count 數量 升序和降序 也可以根據索引   
  124.         sq.setFacetSort("count asc");  
  125.         sq.setQuery("*:*");  
  126.         QueryResponse qr=csc.query(sq);  
  127.         List<FacetField> ff=qr.getFacetFields();  
  128.         //獲取到範圍分類的對應統計數量  
  129.         System.out.println(qr.getFacetQuery());  
  130.         //獲取到根據字段分類的對應統計數量  
  131.         for(FacetField ftmp:ff){  
  132.             System.out.println(ftmp.getName());  
  133.             List<Count> cou=ftmp.getValues();  
  134.             for (Count count : cou){  
  135.                 System.out.println(count.getName()+":"+ count.getCount());  
  136.             }  
  137.         }  
  138.         csc.commit();  
  139.         csc.close();  
  140.     }  
  141.       
  142.     /**  
  143.      * Facet  參考https://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting  
  144.      *  可以按照多維度來進行分類    
  145.      *    比如按照國家分類後  再按照省份分類(國家和省份字段不要使用中文分詞器 否則分類被拆成很多類別)  
  146.      *      
  147.      *  結果一般爲:  
  148.      *    美國6:  
  149.      *      加利福尼亞州3    
  150.      *      德克薩斯州3  
  151.      *    中國5:  
  152.      *      湖南省3  
  153.      *      廣東省2  
  154.   
  155.      */  
  156.     @Test  
  157.     public void queryFacetPivot() throws IOException, SolrServerException{  
  158.         CloudSolrClient csc=getCloudSolrClient();  
  159.         SolrQuery sq=new SolrQuery();  
  160.         sq.setFacet(true);  
  161.         //按國家和省份進行二維分類  同一個字符串使用,隔開  
  162.         sq.addFacetPivotField("country_s,provice_s");  
  163.         sq.setQuery("*:*");  
  164.         QueryResponse qr=csc.query(sq,SolrRequest.METHOD.POST);  
  165.         NamedList<List<PivotField>> ff=qr.getFacetPivot();  
  166.         //獲取到根據字段分類的對應統計數量  
  167.         for(Map.Entry<String,List<PivotField>> me:ff){  
  168.             List<PivotField> lpf=me.getValue();  
  169.             for(PivotField pf:lpf){  
  170.                 System.out.println("一級分類:"+pf.getValue()+pf.getCount()+"---->");  
  171.                 List<PivotField> clpf=pf.getPivot();  
  172.                 for(PivotField cpf:clpf){  
  173.                     System.out.println("二級分類:"+cpf.getValue()+cpf.getCount());  
  174.                 }  
  175.             }  
  176.         }  
  177.         csc.commit();  
  178.         csc.close();  
  179.     }  
  180.     /**  
  181.      * 分組是分類的升級 同時可以獲取到分組下的一部分元素(https://cwiki.apache.org/confluence/display/solr/Result+Grouping)  
  182.        分組的字段的數據如果是集羣環境 要求數據被寫入到一個分片中 否則無法分組查詢  
  183.      */  
  184.     @Test  
  185.     public void queryGroup() throws IOException, SolrServerException{  
  186.         CloudSolrClient csc=getCloudSolrClient();  
  187.         SolrQuery sq=new SolrQuery();  
  188.         //sq.setParam("shards.tolerant", true);  
  189.         sq.setParam(GroupParams.GROUP,true);  
  190.         sq.setParam(GroupParams.GROUP_FIELD, "country_s");  
  191.         sq.setParam("group.ngroups", true);  
  192.         //sq.setParam(GroupParams.GROUP_LIMIT, "5");  
  193.         sq.setQuery("*:*");  
  194.         sq.setRows(10);  
  195.         QueryResponse qr=csc.query(sq);  
  196.         GroupResponse ff=qr.getGroupResponse();  
  197.           
  198.         for(GroupCommand me:ff.getValues()){  
  199.             System.out.println(me.getName());  
  200.              List<Group> groups=me.getValues();  
  201.              System.out.println(groups);  
  202.               
  203.         }  
  204.         csc.commit();  
  205.         csc.close();  
  206.     }  
  207. }  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章