Solrj已经是很强大的solr客户端了。以完全对象的方式对solr进行交互。很小很好很强大。最基本的功能就是管理Solr索引,包括添加、更新、删除和查询等。
在此之前:先介绍一个异常,以前有朋友问过这个,最近查了下solrj的源码。
2014-10-16 17:52:07,486 ERROR [org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrServer] - <error>
org.apache.solr.common.SolrException: Not Found
或者 org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrException: Expected mime type application/xml but got text/html
这是报错的solrj部分源代码
method = new HttpPost(server.getBaseURL() + "/update"
+ ClientUtils.toQueryString(requestParams, false));--注意这里路径getBaseURL
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
StringBuilder msg = new StringBuilder();
msg.append(response.getStatusLine().getReasonPhrase()); -----这里NOT FOUND
msg.append("\n\n");
msg.append("\n\n");
msg.append("request: ").append(method.getURI());
handleError(new SolrException(ErrorCode.getErrorCode(statusCode), msg.toString())); --执向这一行异常,并且打印msg,这里打印确实有点坑
} else {
onSuccess(response);
}
通过其端点跟踪 ,不难发现是由于URL拼接而成的路径报错,也就是说服务器的请求路径不对。一般是服务器后面跟踪的core的不对,所导致整个请求路径不对
老习惯:直接代码分析
package com.hhc.searchEngine;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
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.springframework.beans.BeanUtils;
import org.springframework.web.servlet.ModelAndView;
import com.ws.cache.model.FieldInfo;
import com.ws.cache.model.Scheme;
import com.ws.utils.SearchInitException;
import com.ws.utils.StringUtils;
import com.ws.utils.converter.ConverterUtils;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.sql.Clob;
import java.util.*;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
/**
* 基于solr实现的搜索引擎.
*
* @author huhuichao (huhc3@asiainfo.com)
* @version V1.0
* @createTime 2014-10-13
*/
@SuppressWarnings("unchecked")
public class SearchEngine {
private static final Logger logger = Logger.getLogger(SearchEngine.class);
private String server = "http://localhost:8080/solr";
private SolrServer solrServer = null;
private SolrServer getSolrServer(Scheme scheme) throws SearchInitException {
try {
solrServer = scheme.getConcurrentUpdateSolrServer();
} catch (Exception e) {
e.printStackTrace();
logger.error("null solr server path! !");
throw new SearchInitException(
"null solr server path! !");
}
return solrServer;
}
/**
* 根据数据模型
* 增加维护索引
* @param scheme --索引方案
* @param list --数据模型
* @throws Exception
*/
public synchronized void AddSearchIndex(Scheme scheme,List<Map<String, Object>> list)
throws Exception {
SolrServer solrServer = getSolrServer(scheme);
//用来存储数据文档
List<SolrInputDocument> lstDocument=new ArrayList<SolrInputDocument>();
SolrInputDocument document=null;
for(Map<String,Object> map:list){
//map.remove("RN");
//构造数据模型
document=new SolrInputDocument();
/*
* 先数据自定义处理,然后把处理的数据创建相应的索引
*/
for(Entry<String, Object> ety:map.entrySet()){
for(FieldInfo fieldInfo:scheme.getFiledInfos()){
if(ety.getKey().toString().equals(fieldInfo.getFieldcode())){
//取得数据库中字段的值,分析其在数据库中的类型
Object obj=ety.getValue();
//对CLOB字段的处理
if(obj instanceof Clob){
//对这种格式的文本转化成String类型
obj = ConverterUtils.clobToStr((Clob)obj);
}
//防止分词器出现异常。
//对特殊字符处理
if(obj!=null){
obj = obj.toString().trim().replaceAll("\'", "”");
obj = obj.toString().replaceAll("\"", "”");
}
// 保证每个对象的唯一性,而且通过对象的主键可以明确的找到这个对象在solr中的索引
if(scheme.getPkfield().equalsIgnoreCase(fieldInfo.getFieldcode())){
document.addField("primary_key", obj);//主键
document.addField("schecode", scheme.getCode().toLowerCase());//方案code
}else{
document.addField(ety.getKey().toLowerCase(), obj);//ent.getValue()
if(scheme.getInsertsjcfield().equalsIgnoreCase(fieldInfo.getFieldcode())){
document.addField("insertsj", obj);//插入时间戳
}
if(scheme.getUpdatesjcfield().equalsIgnoreCase(fieldInfo.getFieldcode())){
document.addField("updatesj", obj);//更新时间戳
}
}
}
}
}
lstDocument.add(document);
}
solrServer.add(lstDocument);
solrServer.commit();
}
/**
* 删除单个solr文本节点--通过文档id
* @param bean
* @throws Exception
*/
public synchronized void deleteIndex(String id,Scheme scheme) throws Exception {
if (scheme == null) {
logger.warn("Get search bean is empty!");
return;
}
SolrServer server = getSolrServer(scheme);
server.deleteById(id);
server.commit();
}
/**
* 删除多个个solr文本节点--通过文档id集
* @param list--(id的集合)
* @throws Exception
*/
@SuppressWarnings("unchecked")
public synchronized void deleteIndexs(List list,Scheme scheme)
throws Exception {
if (scheme == null) {
logger.warn("Get search bean is empty!");
return;
}
SolrServer server = getSolrServer(scheme);
server.deleteById(list);
server.commit();
}
/**
* solr查询
* @param request
* @return
*/
public ModelAndView solrSearch (HttpServletRequest request){
ModelAndView mav = new ModelAndView("/huhuichao/solr/test.jsp");
Map map = super.getParamValues(request);
//获取拼接好的查询参数
String pueryParams=getQueryParams(map);
map = super.pageXX(map, request);
//创建远程服务--调用方案
SolrServer httpSolrServer = getSolrServer((Scheme)map.get("scheme"));
//设置查询参数
SolrQuery params=new SolrQuery();
params.setParam("q", pueryParams);
//设置查询展示字段-- *,score 的话 查询所有字段。。会很慢。
//params.setParam("fl","c495,c505,c639,c610,c554,c555,c502,score");
//返回结果集。。全文检索从第0页开始 +1
params.setStart((Integer.parseInt(map.get("page").toString())-1)*10);
params.setRows(10);
//设置排序字段
params.setSortField("c610", SolrQuery.ORDER.desc);
//执行查询-返回结果集
try {
QueryResponse reponse = httpSolrServer.query(params);
List list=reponse.getResults();
//组装pager对象
Pager<T> pager=new Pager<T>((int)reponse.getResults().getNumFound(), 10, Integer.parseInt(map.get("page").toString()));
//System.out.println(reponse.getResults());
// for (SolrDocument result : reponse.getResults()) {
// System.out.println(result);
// }
pager.setResults(list);
mav.addObject("pager", pager);
} catch (SolrServerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Pager pager = this.wscbajManager.wscbajQuery(map);
mav.addObject("map", map);
return mav;
}
/**
* 通过索引类型删除索引
* @param indexType
* @param scheme
* @throws Exception
*/
public synchronized void deleteIndexsByIndexType(String indexType,Scheme scheme)
throws Exception {
SolrServer server = getSolrServer(scheme);
UpdateResponse ur = server.deleteByQuery("indexType:" + indexType);
server.commit();
}
/**
* 清空索引
* @param scheme
* @throws Exception
*/
public synchronized void deleteAllIndexs(Scheme scheme) throws Exception {
SolrServer server = getSolrServer(scheme);
UpdateResponse ur = server.deleteByQuery("*:*");
server.commit();
}
/**
* 更新索引<br/>
* 在solr中更新索引也就是创建索引(当有相同ID存在的时候,会覆盖上一个索引节点,否则新建)<br/>
* {@link SolrSearchEngine#doIndex(java.util.List)}
*
* @param Schemes
* 需要更新的方案
* @throws Exception
*/
public void updateIndexs(Scheme scheme,List<Map<String, Object>> list) throws Exception {
this.AddSearchIndex(scheme,list);
}
}
在solrj中 提出了3种常用的删除操作对外接口
这是从其源码中拷贝出来的删除代码
/**
* Deletes a single document by unique ID
* @param id the ID of the document to delete
* @throws IOException If there is a low-level I/O error.
*/
public UpdateResponse deleteById(String id) throws SolrServerException, IOException {
return deleteById(id, -1);
}
/**
* Deletes a list of documents by unique ID
* @param ids the list of document IDs to delete
* @throws IOException If there is a low-level I/O error.
*/
public UpdateResponse deleteById(List<String> ids) throws SolrServerException, IOException {
return deleteById(ids, -1);
}
/**
* Deletes documents from the index based on a query
* @param query the query expressing what documents to delete
* @throws IOException If there is a low-level I/O error.
*/
public UpdateResponse deleteByQuery(String query) throws SolrServerException, IOException {
return deleteByQuery(query, -1);
}
//从这段代码 可以看出,就是循环删除单个文本节点操作
public UpdateRequest deleteById(List<String> ids) {
if (deleteById == null) {
deleteById = new LinkedHashMap<>();
}
for (String id : ids) {
deleteById.put(id, null);
}
return this;
}