一 。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 日誌 出現以下異常
-
java.lang.NoClassDefFoundError: Failed to initialize Apache Solr: Could not find necessary SLF4j logging jars.
-
If using Jetty, the SLF4j logging jars need to go in the jetty lib/ext directory. For other containers,
-
the corresponding directory should be used. For more information, see: http://wiki.apache.org/solr/SolrLogging
-
at org.apache.solr.servlet.CheckLoggingConfiguration.check(CheckLoggingConfiguration.java:27)
-
at org.apache.solr.servlet.BaseSolrFilter.<clinit>(BaseSolrFilter.java:30)
可用看到缺少SLF4j包 應該去 應該去 解壓包 /server/lib/ext下找到並拷貝到 tomcat/solr/lib目錄下 然後重啓
繼續訪問 出現以下錯誤
-
java.lang.NoSuchMethodError: javax.servlet.ServletInputStream.isFinished()Z
-
org.apache.solr.servlet.SolrDispatchFilter.consumeInputFully(SolrDispatchFilter.java:284)
-
org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:274)
-
org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208)
明顯是Servlet版本不一致 tomcat6不支持solr5.54 加大tomcat版本 tomcat7也不支持 換成tomcat8 啓動後訪問 依然錯誤:
-
org.apache.solr.common.SolrException: Error processing the request. CoreContainer is either not initialized or shutting down.
-
org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:217)
-
org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:208)
是因爲需要配置solrhome和solrhome的配置環境
3》配置solrhome
找到 tomcat\solr\WEB-INF\web.xml 編輯 找到以下這段(配置solrhome) 去掉註釋 將第二個參數配置爲本地任意一個目錄即可
-
<env-entry>
-
<env-entry-name>solr/home</env-entry-name>
-
<env-entry-value>D:\learn\solr-5.5.4\home</env-entry-value>
-
<env-entry-type>java.lang.String</env-entry-type>
-
</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的類型定義,唯一標識符等
常用配置如下:
-
定義字段 _version_ 類型爲long indexed="true" 會進行分詞索引 stored="true"表示存儲到磁盤
-
<field name="_version_" type="long" indexed="true" stored="true"/>
-
定義字段 id required="true" 表示所有的document必須添加id字段 multiValued="false" 表示是否是多值字段
-
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
-
定義動態字段 所以_i結尾的字段都可以寫入到當前的core
-
<dynamicField name="*_i" type="int" indexed="true" stored="true"/>
-
定義唯一標識符的字段
-
<uniqueKey>id</uniqueKey>
-
定義字段類型的別名
-
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
solrconfig.xml 主要用於配置solor的主要配置信息 比如lucene版本 緩存 數據目錄 請求路徑映射 等
-
表示lucene版本
-
<luceneMatchVersion>5.5.4</luceneMatchVersion>
-
表示數據目錄 默認是data目錄
-
<dataDir>${solr.data.dir:}</dataDir>
-
自動提交配置
-
<autoCommit>
-
當超過15000ms後自動提交所有數據
-
<maxTime>${solr.autoCommit.maxTime:15000}</maxTime>
-
是否馬上就可以查詢到
-
<openSearcher>false</openSearcher>
-
</autoCommit>
-
表示當路徑爲 /select時查詢所有的數據
-
<requestHandler name="/select" class="solr.SearchHandler">
-
<!-- default values for query parameters can be specified, these
-
will be overridden by parameters in the request
-
-->
-
<lst name="defaults">
-
<str name="echoParams">explicit</str>
-
<int name="rows">10</int>
-
</lst>
-
</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 設置參數爲 路徑,路徑來設置需要搜索的核
-
String shards = "localhost:8080/solr/mycore,localhost:8080/solr/mycore1";
-
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
-
<dependency>
-
<groupId>org.apache.lucene</groupId>
-
<artifactId>lucene-core</artifactId>
-
<version>5.3.1</version>
-
</dependency>
-
<dependency>
-
<groupId>com.janeluo</groupId>
-
<artifactId>ikanalyzer</artifactId>
-
<version>2012_u6</version>
-
<exclusions>
-
<exclusion>
-
<groupId>org.apache.lucene</groupId>
-
<artifactId>lucene-core</artifactId>
-
</exclusion>
-
</exclusions>
-
</dependency>
在項目中 添加完整的包名和類名 和 ik中一致 拷貝源代碼
代碼修改對應的方法即可
IKAnalyzer
-
/**
-
-
*
-
*/
-
package org.wltea.analyzer.lucene;
-
-
import java.io.Reader;
-
-
import org.apache.lucene.analysis.Analyzer;
-
import org.apache.lucene.analysis.Tokenizer;
-
-
/**
-
*/
-
public final class IKAnalyzer extends Analyzer {
-
-
private boolean useSmart;
-
-
public boolean useSmart() {
-
return useSmart;
-
}
-
-
public void setUseSmart(boolean useSmart) {
-
this.useSmart = useSmart;
-
}
-
-
/**
-
-
*/
-
public IKAnalyzer() {
-
this(false);
-
}
-
-
/**
-
*/
-
public IKAnalyzer(boolean useSmart) {
-
super();
-
this.useSmart = useSmart;
-
}
-
-
/**這裏就去掉了 Reader的一個參數
-
*/
-
@Override
-
protected TokenStreamComponents createComponents(String fieldName) {
-
Tokenizer _IKTokenizer = new IKTokenizer(this.useSmart());
-
return new TokenStreamComponents(_IKTokenizer);
-
}
-
-
}
IKTokenizer
-
/**
-
*
-
*/
-
package org.wltea.analyzer.lucene;
-
-
import java.io.IOException;
-
import java.io.Reader;
-
-
import org.apache.lucene.analysis.Tokenizer;
-
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
-
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
-
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
-
-
import org.wltea.analyzer.core.IKSegmenter;
-
import org.wltea.analyzer.core.Lexeme;
-
-
-
public final class IKTokenizer extends Tokenizer {
-
-
-
private IKSegmenter _IKImplement;
-
-
-
private final CharTermAttribute termAtt;
-
-
private final OffsetAttribute offsetAtt;
-
-
private final TypeAttribute typeAtt;
-
-
private int endPosition;
-
-
//去掉了其中Reader的第一個構造參數
-
public IKTokenizer(boolean useSmart) {
-
super();//去掉super中的構造參數
-
offsetAtt = addAttribute(OffsetAttribute.class);
-
termAtt = addAttribute(CharTermAttribute.class);
-
typeAtt = addAttribute(TypeAttribute.class);
-
_IKImplement = new IKSegmenter(input, useSmart);
-
}
-
-
-
@Override
-
public boolean incrementToken() throws IOException {
-
-
clearAttributes();
-
Lexeme nextLexeme = _IKImplement.next();
-
if (nextLexeme != null) {
-
-
termAtt.append(nextLexeme.getLexemeText());
-
-
termAtt.setLength(nextLexeme.getLength());
-
-
offsetAtt.setOffset(nextLexeme.getBeginPosition(), nextLexeme.getEndPosition());
-
-
endPosition = nextLexeme.getEndPosition();
-
-
typeAtt.setType(nextLexeme.getLexemeTypeString());
-
-
return true;
-
}
-
-
return false;
-
}
-
-
/*
-
* (non-Javadoc)
-
* @see org.apache.lucene.analysis.Tokenizer#reset(java.io.Reader)
-
*/
-
@Override
-
public void reset() throws IOException {
-
super.reset();
-
_IKImplement.reset(input);
-
}
-
-
@Override
-
public final void end() {
-
// set final offset
-
int finalOffset = correctOffset(this.endPosition);
-
offsetAtt.setOffset(finalOffset, finalOffset);
-
}
-
}
將編譯好的class文件替換原始jar包即可
將solrhome下 配置文件managed-schema 添加一個字段類型 使用ik分詞器
-
<fieldType name="text_ik" class="solr.TextField" >
-
<analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
-
<analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
-
</fieldType>
不能修改 StrField 不支持自定義分詞器
<fieldType name="string" class="solr.StrField" sortMissingLast="true" >
</fieldType>
然後將對應需要進行中文分詞的字段使用 text_ik該字段類型 比如
-
<dynamicField name="*_s" type="text_ik" indexed="true" stored="true" />
重啓 或者 cloud環境下重新生成collection 插入數據即可實現中文分詞 通過某些中文關鍵字搜索
三。solr客戶端
solr提供的solrj java客戶端可以使用java來添加和查詢索引
使用maven引入solrj的依賴庫
-
-
<dependency>
-
<groupId>org.apache.solr</groupId>
-
<artifactId>solr-solrj</artifactId>
-
<version>5.5.3</version>
-
</dependency>
使用客戶端操作添加和查詢索引的代碼
-
public class TestCrud {
-
//請求的url
-
public static final String url="http://localhost:8080/solr/mycore";
-
/**
-
* 測試寫入數據到solr
-
* @throws IOException
-
* @throws SolrServerException
-
*/
-
@Test
-
public void testWriteDoc() throws SolrServerException, IOException{
-
HttpSolrClient hsc=new HttpSolrClient(url);
-
SolrInputDocument sid=new SolrInputDocument();
-
sid.addField("id", 1);
-
sid.addField("name_s","張三");
-
hsc.add(sid);
-
hsc.commit();
-
hsc.close();
-
}
-
/**
-
* 測試從solr讀取數據
-
* @throws IOException
-
* @throws SolrServerException
-
*/
-
@Test
-
public void testReadDoc() throws SolrServerException, IOException{
-
HttpSolrClient hsc=new HttpSolrClient(url);
-
SolrQuery sq=new SolrQuery();
-
sq.setQuery("name_s:*");
-
sq.set("sort", "id asc");
-
sq.setStart(0);
-
sq.setRows(1);
-
SolrDocumentList sdl=hsc.query(sq).getResults();
-
for(SolrDocument sd:sdl){
-
System.out.println(sd.getFieldValue("name_s"));
-
}
-
hsc.close();
-
}
-
/**
-
* 測試通過id刪除
-
* @throws IOException
-
* @throws SolrServerException
-
*/
-
@Test
-
public void testDelDoc() throws SolrServerException, IOException{
-
HttpSolrClient hsc=new HttpSolrClient(url);
-
hsc.deleteById("1");
-
hsc.commit();
-
hsc.close();
-
}
-
}
使用javabean的方式操作
javabean定義
-
import org.apache.solr.client.solrj.beans.Field;
-
public class UserInfo {
-
public UserInfo() {
-
}
-
@Field
-
private String id;
-
@Field
-
private String name_s;
-
@Field
-
private int age_i;
-
}
執行代碼如下:
-
/**
-
* 測試寫入數據到solr
-
* @throws IOException
-
* @throws SolrServerException
-
*/
-
@Test
-
public void testWriteDoc() throws SolrServerException, IOException{
-
HttpSolrClient hsc=new HttpSolrClient(url);
-
UserInfo ui=new UserInfo();
-
ui.setId("2");
-
ui.setName_s("李四");
-
ui.setAge_i(100);
-
hsc.addBean(ui);
-
hsc.commit();
-
hsc.close();
-
}
-
/**
-
* 測試從solr讀取數據
-
* @throws IOException
-
* @throws SolrServerException
-
*/
-
@Test
-
public void testReadDoc() throws SolrServerException, IOException{
-
HttpSolrClient hsc=new HttpSolrClient(url);
-
SolrQuery sq=new SolrQuery();
-
sq.setQuery("name_s:*");
-
sq.set("sort", "id asc");
-
sq.setStart(0);
-
sq.setRows(1);
-
List<UserInfo> sdl=hsc.query(sq).getBeans(UserInfo.class);
-
for(UserInfo sd:sdl){
-
System.out.println(sd.getName_s());
-
}
-
hsc.close();
-
}
四。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下設置爲:
-
set JAVA_OPTS=-Dsolr.solr.home=D:/learn/solr-5.5.4/home -Dbootstrap_confdir=D:/learn/solr-5.5.4/home/collection1/conf
-
-Dcollection.configName=myconf -DnumShards=3 -DzkHost=localhost:2181
其他tomcat 設置爲
-
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)
-
http://localhost:8081/solr/admin/collections?action=CREATE&name=collection1&numShards=3&replicationFactor=3&maxShardsPerNode=3&collection.configName=myconf
》》查看zookeeper信息和集羣分片信息
查看zookeeper中寫入的數據
查看分片到哪些節點
五。solr一些其他高級查詢(參考代碼)
-
package cn.et.solor;
-
-
import java.io.IOException;
-
import java.util.List;
-
import java.util.Map;
-
-
import org.apache.solr.client.solrj.SolrQuery;
-
import org.apache.solr.client.solrj.SolrRequest;
-
import org.apache.solr.client.solrj.SolrServerException;
-
import org.apache.solr.client.solrj.impl.CloudSolrClient;
-
import org.apache.solr.client.solrj.response.FacetField;
-
import org.apache.solr.client.solrj.response.Group;
-
import org.apache.solr.client.solrj.response.GroupCommand;
-
import org.apache.solr.client.solrj.response.GroupResponse;
-
import org.apache.solr.client.solrj.response.PivotField;
-
import org.apache.solr.client.solrj.response.QueryResponse;
-
import org.apache.solr.client.solrj.response.FacetField.Count;
-
import org.apache.solr.common.params.GroupParams;
-
import org.apache.solr.common.util.NamedList;
-
import org.junit.Test;
-
/**
-
* 支持一些高級特性 比如高亮 分類 分組 mtl(相似)
-
{"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"}
-
{"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"}
-
{"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"}
-
{"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"}
-
{"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"}
-
{"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"}
-
{"id":"7","country_s":"中國","provice_s":"湖南省","city_s":"長沙市","age_i":"18","name_s":"張三","desc_s":"張三來自長沙市 是公務員一名"}
-
{"id":"8","country_s":"中國","provice_s":"湖南省","city_s":"岳陽市","age_i":"15","name_s":"李四","desc_s":"李四來自岳陽市 是一名清潔工"}
-
{"id":"9","country_s":"中國","provice_s":"湖南省","city_s":"株洲市","age_i":"33","name_s":"李光四","desc_s":"李光四 老家岳陽市 來自株洲 是李四的侄子"}
-
{"id":"10","country_s":"中國","provice_s":"廣東省","city_s":"深圳市","age_i":"67","name_s":"王五","desc_s":"王五來自深圳市 是來自深圳的一名海關緝私精英"}
-
{"id":"11","country_s":"中國","provice_s":"廣東省","city_s":"廣州市","age_i":"89","name_s":"王冠宇","desc_s":"王冠宇是王五的兒子"}
-
*/
-
public class TestCloud {
-
/**
-
* 連接solrcloud
-
* @return
-
*/
-
public CloudSolrClient getCloudSolrClient(){
-
String zkHost="localhost:2181";
-
CloudSolrClient csc=new CloudSolrClient(zkHost);
-
csc.setDefaultCollection("collection1");//集合名稱
-
return csc;
-
}
-
/**
-
* solrcloud保存 修改 刪除和單機相同
-
*/
-
@Test
-
public void save() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
UserInfo ui=new UserInfo();
-
ui.setId("4");
-
ui.setName_s("王五");
-
ui.setAge_i(100);
-
csc.addBean(ui);
-
csc.commit();
-
csc.close();
-
}
-
/**
-
* solrcloud 刪除
-
*/
-
//@Test
-
public void delete() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
csc.deleteByQuery("*:*");
-
csc.commit();
-
csc.close();
-
}
-
-
/**
-
* solrcloud高亮顯示
-
* 必須設置中文分詞器
-
*/
-
@Test
-
public void queryHign() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
SolrQuery sq=new SolrQuery();
-
sq.setQuery("desc_s:王五");
-
sq.addHighlightField("desc_s");
-
sq.setHighlight(true);
-
sq.setHighlightSimplePre("<font color=red>");
-
sq.setHighlightSimplePost("</font>");
-
QueryResponse qr=csc.query(sq);
-
List<UserInfo> userInfo=qr.getBeans(UserInfo.class);
-
Map<String, Map<String, List<String>>> highlighting = qr.getHighlighting();
-
System.out.println(highlighting);
-
for(UserInfo ui:userInfo){
-
System.out.println(ui.getName_s());
-
}
-
System.out.println(userInfo.size());
-
csc.commit();
-
csc.close();
-
}
-
-
/**
-
* Facet 面 用於對搜索的結果進行分類
-
* 比如按國家分類 addFacetField 表示按某些字段進行分類是普通分類 結果爲:
-
* country_s
-
美國:6
-
中國:5
-
sq.addFacetQuery("age_i:[1 TO 20]");
-
sq.addFacetQuery("age_i:[21 TO 50]");
-
sq.addFacetQuery("age_i:[51 TO *]");
-
可以將多個範圍值 添加到FacetQuery可以獲取到這些Query的統計數量 比如
-
{age_i:[1 TO 20]=3, age_i:[20 TO 50]=5, age_i:[50 TO *]=5}
-
其他 參考 https://wiki.apache.org/solr/SimpleFacetParameters#facet.query_:_Arbitrary_Query_Faceting
-
*/
-
@Test
-
public void queryFacet() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
SolrQuery sq=new SolrQuery();
-
-
sq.setFacet(true);
-
//按字段分類 相同的歸於一類
-
sq.addFacetField("country_s");
-
//特殊分類 添加範圍
-
sq.addFacetQuery("age_i:[1 TO 20]");
-
sq.addFacetQuery("age_i:[21 TO 50]");
-
sq.addFacetQuery("age_i:[51 TO *]");
-
//這隻facet字段分類的前綴
-
sq.setFacetPrefix("");
-
//根據 count 數量 升序和降序 也可以根據索引
-
sq.setFacetSort("count asc");
-
sq.setQuery("*:*");
-
QueryResponse qr=csc.query(sq);
-
List<FacetField> ff=qr.getFacetFields();
-
//獲取到範圍分類的對應統計數量
-
System.out.println(qr.getFacetQuery());
-
//獲取到根據字段分類的對應統計數量
-
for(FacetField ftmp:ff){
-
System.out.println(ftmp.getName());
-
List<Count> cou=ftmp.getValues();
-
for (Count count : cou){
-
System.out.println(count.getName()+":"+ count.getCount());
-
}
-
}
-
csc.commit();
-
csc.close();
-
}
-
-
/**
-
* Facet 參考https://wiki.apache.org/solr/SimpleFacetParameters#Pivot_.28ie_Decision_Tree.29_Faceting
-
* 可以按照多維度來進行分類
-
* 比如按照國家分類後 再按照省份分類(國家和省份字段不要使用中文分詞器 否則分類被拆成很多類別)
-
*
-
* 結果一般爲:
-
* 美國6:
-
* 加利福尼亞州3
-
* 德克薩斯州3
-
* 中國5:
-
* 湖南省3
-
* 廣東省2
-
-
*/
-
@Test
-
public void queryFacetPivot() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
SolrQuery sq=new SolrQuery();
-
sq.setFacet(true);
-
//按國家和省份進行二維分類 同一個字符串使用,隔開
-
sq.addFacetPivotField("country_s,provice_s");
-
sq.setQuery("*:*");
-
QueryResponse qr=csc.query(sq,SolrRequest.METHOD.POST);
-
NamedList<List<PivotField>> ff=qr.getFacetPivot();
-
//獲取到根據字段分類的對應統計數量
-
for(Map.Entry<String,List<PivotField>> me:ff){
-
List<PivotField> lpf=me.getValue();
-
for(PivotField pf:lpf){
-
System.out.println("一級分類:"+pf.getValue()+pf.getCount()+"---->");
-
List<PivotField> clpf=pf.getPivot();
-
for(PivotField cpf:clpf){
-
System.out.println("二級分類:"+cpf.getValue()+cpf.getCount());
-
}
-
}
-
}
-
csc.commit();
-
csc.close();
-
}
-
/**
-
* 分組是分類的升級 同時可以獲取到分組下的一部分元素(https://cwiki.apache.org/confluence/display/solr/Result+Grouping)
-
分組的字段的數據如果是集羣環境 要求數據被寫入到一個分片中 否則無法分組查詢
-
*/
-
@Test
-
public void queryGroup() throws IOException, SolrServerException{
-
CloudSolrClient csc=getCloudSolrClient();
-
SolrQuery sq=new SolrQuery();
-
//sq.setParam("shards.tolerant", true);
-
sq.setParam(GroupParams.GROUP,true);
-
sq.setParam(GroupParams.GROUP_FIELD, "country_s");
-
sq.setParam("group.ngroups", true);
-
//sq.setParam(GroupParams.GROUP_LIMIT, "5");
-
sq.setQuery("*:*");
-
sq.setRows(10);
-
QueryResponse qr=csc.query(sq);
-
GroupResponse ff=qr.getGroupResponse();
-
-
for(GroupCommand me:ff.getValues()){
-
System.out.println(me.getName());
-
List<Group> groups=me.getValues();
-
System.out.println(groups);
-
-
}
-
csc.commit();
-
csc.close();
-
}
-
}