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();
}
}
}