schema.xml
<?xml version="1.0" ?>
<schema name="testcore" version="1.5">
<types>
<fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<!-- 原始 ik分詞器 -->
<fieldType name="text_ik" class="solr.TextField">
<analyzer type="index" useSmart="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
<analyzer type="query" useSmart="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
</types>
<fields>
<!-- 業務字段 -->
<field name="id" type="string" indexed="true" stored="true" multiValued="false" />
<field name="sname" type="string" indexed="true" stored="true" multiValued="false" />
<field name="slocation" type="string" indexed="true" stored="true" multiValued="false" />
<field name="sdes" type="text_ik" indexed="true" stored="true" multiValued="false" />
<field name="sarea" type="string" indexed="true" stored="true" multiValued="false" />
<field name="spopulation" type="long" indexed="true" stored="true" multiValued="false" />
<!-- 多值字段 -->
<field name="smemo" type="text_ik" indexed="true" stored="true" multiValued="true" />
<!-- 拷貝字段 source和dest都支持通配符 -->
<copyField source="sname" dest="smemo" />
<copyField source="sarea" dest="smemo" />
<!-- 動態字段 -->
<dynamicField name="exts_l_*" type="long" indexed="true" stored="true" multiValued="false" />
<dynamicField name="exts_s_*" type="string" indexed="true" stored="true" multiValued="false" />
<dynamicField name="exts_t_*" type="text_ik" indexed="true" stored="true" multiValued="false" />
<field name="exts" type="text_ik" indexed="true" stored="true" multiValued="true"/>
<copyField source="exts_l_*" dest="exts"/>
<copyField source="exts_s_*" dest="exts"/>
<copyField source="exts_t_*" dest="exts"/>
<!-- general -->
<field name="name" type="string" indexed="true" stored="true" multiValued="false" />
<field name="type" type="string" indexed="true" stored="true" multiValued="false" />
<field name="_version_" type="long" indexed="true" stored="true"/>
</fields>
<!-- 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>
maven依賴
<!-- solr 必須 -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>4.7.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!-- fastjson 不必須 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
示例代碼
import com.alibaba.fastjson.JSONObject;
import org.apache.http.client.HttpClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.impl.HttpClientUtil;
import org.apache.solr.client.solrj.impl.LBHttpSolrServer;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import java.util.*;
/**
* solrcloud java api demo
*
*/
public class App
{
/**
* ZooKeeper地址
*/
private static String zkHostString = "127.0.0.1:2181";
/**
* collection默認名稱
*/
private static String defaultCollection = "testindex";
/**
* 客戶端連接超時時間
*/
private static int zkClientTimeout = 5000;
/**
* ZooKeeper連接超時時間
*/
private static int zkConnectTimeout = 5000;
/**
* solr cloud服務
*/
private static CloudSolrServer cloudSolrServer;
public static void main( String[] args) {
init(true);
try {
deleteIndexAllFromSolrCloud(true);
createIndexToSolrCloud(true);
updateIndexToSolrCloud1(false);
updateIndexToSolrCloud2(false);
searchIndexFromSolrCloud(true);
deleteIndexFromSolrCloud(false);
} catch (Exception e) {
e.printStackTrace();
} finally {
close();
}
}
/**
* 初始化
*/
public static void init(boolean exe) {
if(exe) {
// 擴大併發連接數
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, 100);
params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, 50);
HttpClient client = HttpClientUtil.createClient(params);
LBHttpSolrServer lbServer = new LBHttpSolrServer(client);
cloudSolrServer = new CloudSolrServer(zkHostString,lbServer);
cloudSolrServer.setDefaultCollection(defaultCollection);
cloudSolrServer.setZkClientTimeout(zkClientTimeout);
cloudSolrServer.setZkConnectTimeout(zkConnectTimeout);
cloudSolrServer.connect();
}
}
/**
* 關閉
*/
public static void close(){
cloudSolrServer.shutdown();
}
/**
* 創建索引
* @throws Exception
*/
public static void createIndexToSolrCloud(boolean exe) throws Exception {
if(exe) {
SolrInputDocument document1 = new SolrInputDocument();
document1.addField("id", "10001");
document1.addField("sname", "中國");
document1.addField("slocation", "亞洲");
document1.addField("sdes", "中華人民共和國是一個美麗的國家");
document1.addField("sarea", "大");
document1.addField("spopulation", 1300000000);
document1.addField("exts_l_l", 100);
document1.addField("exts_s_s", "北京");
document1.addField("exts_t_t", "天安門");
SolrInputDocument document2 = new SolrInputDocument();
document2.addField("id", "10002");
document2.addField("sname", "美國");
document2.addField("slocation", "北美洲");
document2.addField("sdes", "美利堅合衆國是一個美麗的國家");
document2.addField("sarea", "大");
document2.addField("spopulation", 200000000);
document2.addField("exts_l_l", 100);
document2.addField("exts_s_s", "拉斯維加斯");
document2.addField("exts_t_t", "賭場");
//cloudSolrServer.add(document1);
//cloudSolrServer.add(document2);
Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
docs.add(document1);
docs.add(document2);
cloudSolrServer.add(docs);
cloudSolrServer.commit();
}
}
/**
* 更新索引,全屬性更新,否則只保留更新的屬性,其他屬性則丟失
* @param exe
* @throws Exception
*/
public static void updateIndexToSolrCloud1(boolean exe) throws Exception
{
if(exe) {
SolrInputDocument document2 = new SolrInputDocument();
document2.addField("id", "10002");
document2.addField("sname", "美國-2");
document2.addField("slocation", "北美洲");
document2.addField("sdes", "美利堅合衆國是一個美麗的國家");
document2.addField("sarea", "大");
document2.addField("spopulation", 200000000);
// 用這種方式更新必須是全屬性更新,否則只保留更新的屬性,其他屬性則丟失
cloudSolrServer.add(document2);
cloudSolrServer.commit();
}
}
/**
* 更新索引,局部屬性更新
* @param exe
* @throws Exception
*/
public static void updateIndexToSolrCloud2(boolean exe) throws Exception
{
if(exe) {
SolrInputDocument doc = new SolrInputDocument();
// 局部更新需要指定文檔的id(在schema.xml中配置的主鍵),
// 主鍵不需要添加set、add等信息, 其他需要原子更新的field需要構造爲Map
doc.addField("id", "10002");
// 局部更新需要藉助Map, 這個Map的Key必須是“set”
Map<String, String> publisherMap = new HashMap<>();
publisherMap.put("set", "美國-2");
// 修改屬性值, key是field, value是上述的Map
doc.addField("sname", publisherMap);
/**
// 在已有的基礎上, 再添加多個值, 注意: 此field必須是multi-valued類型
Map<String, List<String>> smemoMap = new HashMap<>();
List<String> list = new ArrayList();
list.add("紐約");
list.add("洛杉磯");
// 局部添加需要藉助Map, 這個Map的Key必須是“add”
smemoMap.put("add", list);
// 修改圖書的倉庫城市, key是field, value是上述的Map
doc.addField("smemo", smemoMap);
*/
// 在已有數字的基礎上: 每個增加8888, 注意: 此field必須是數值類型
Map<String, Long> spopulationMap = new HashMap<>();
// 局部自增需要藉助Map, 這個Map的Key必須是“inc”
spopulationMap.put("inc", 8888L);
// 修改數值類型屬性內容, key是field, value是上述的Map
doc.addField("spopulation", spopulationMap);
// _version_ < 0: 如果待修改的文檔存在, 則拒絕修改; 如果不存在, 則添加文檔;
// _version_ = 0: 如果待修改的文檔存在, 則修改這個文檔; 如果不存在, 則添加文檔;
// _version_ = 1: 如果待修改的文檔存在, 則更新這個文檔; 如果不存在, 會拒絕修改它, 並拋出類似的錯誤信息.
doc.addField("_version_", 0);
// 爲了提高效率, 可以使用批量操作
Collection<SolrInputDocument> updateDocList = new ArrayList<>();
updateDocList.add(doc);
// 添加提交文檔List
UpdateResponse rsp = cloudSolrServer.add(updateDocList);
//System.out.println("操作狀態: " + rsp.getStatus());
// 提交策略: 不用手動提交, 交由Solr服務根據配置自動進行軟提交;
// 如果要手動提交, 不要使用無參方法, 推薦指定提交策略: 是否等待刷新(建議不等待: 會阻塞)、等待可搜索(建議不等待: 會阻塞)、軟提交
UpdateResponse rspCommit = cloudSolrServer.commit(false, false, true);
System.out.println("提交狀態: " + " result:" + rspCommit.getStatus() + ", 操作時間: " + rspCommit.getQTime());
}
}
/**
* 搜索索引
* @throws Exception
*/
public static void searchIndexFromSolrCloud(boolean exe) throws Exception {
if(exe) {
SolrQuery query = new SolrQuery();
// q
query.setQuery("sdes:美麗");
//query.setQuery("sarea:(\"大\" OR \"小\")");
//query.setQuery("smemo:(\"大\" OR \"小\")");
// fq
query.setFilterQueries("slocation:*");
// sort
query.setSort("id", SolrQuery.ORDER.desc);
// start, rows
query.setStart(0);
query.setRows(100);
// fl
query.setFields("id,sname,sdes,sarea,slocation,spopulation,smemo");
// df
query.set("df", "id");
// hl
query.setHighlight(true);
query.addHighlightField("sdes");
query.setHighlightSimplePre("<font color=\"red\">");
query.setHighlightSimplePost("</font>");
// facet
query.setFacet(true);
query.addFacetQuery("sname:中國");
query.addFacetField("sarea");
try {
QueryResponse response = cloudSolrServer.query(query);
// 獲取高亮結果
Map<String, Map<String, List<String>>> highlighting= response.getHighlighting();
// 獲取查詢結果
SolrDocumentList docs = response.getResults();
System.out.println("文檔個數: " + docs.getNumFound());
System.out.println("查詢時間: " + response.getQTime());
for (SolrDocument doc : docs) {
String id = (String) doc.getFieldValue("id");
String sdes = (String) doc.getFieldValue("sdes");
String sname = (String) doc.getFieldValue("sname");
// 多值
List<String> smemo = (ArrayList) doc.getFieldValue("smemo");
String highlightSdes="";
List<String> list = highlighting.get(id).get("sdes");
if (list != null) {
highlightSdes = list.get(0);
}
System.out.println("id: " + id);
System.out.println("sname: " + sname);
System.out.println("sdes: " + sdes);
System.out.println("highlightSdes: " + highlightSdes);
System.out.println("smemo: " + JSONObject.toJSONString(smemo));
System.out.println();
}
// 獲取facet過濾統計結果
Map<String,Integer> facetQueries = response.getFacetQuery();
// 獲取facet分組統計結果
List<FacetField> facetFields= response.getFacetFields();
System.out.println("facetQueries:"+JSONObject.toJSONString(facetFields));
System.out.println("facetFields:"+JSONObject.toJSONString(facetFields));
} catch (SolrServerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 刪除索引文檔
* @throws Exception
*/
public static void deleteIndexFromSolrCloud(boolean exe) throws Exception {
if(exe) {
// 根據id刪除
UpdateResponse response = cloudSolrServer.deleteById("10002");
// 根據多個id刪除
// cloudSolrServer.deleteById(ids);
cloudSolrServer.commit();
}
}
/**
* 刪除索引所有記錄
* @param exe
* @throws Exception
*/
public static void deleteIndexAllFromSolrCloud(boolean exe) throws Exception {
if(exe) {
// 自動查詢條件刪除
cloudSolrServer.deleteByQuery("*:*");
cloudSolrServer.commit();
}
}
}