一、Solr查询的几个基本参数
查询:
q:主查询参数
qf:过滤查询(不影响评分)
sort:排序,如:sort=price asc
strat:搜索结果的起始页,默认为0
rows:页面大小,默认为10,也可以在配置文件中设置
fl:需要返回的字段列表
df:默认搜索字段,如果在q中没有指定查询的字段,则默认使用df定义的字段查询
wt:返回的字段格式(json、xml、python对象等)
例子:
查询的文档是一个新闻的文档,结构比较简单,包含的字段有:id、url、title、content
查询的url为:http://localhost:8080/solr/news/select?indent=on&q=title:公益&wt=json
查询结果:
{
"responseHeader":{
"status":0,
"QTime":14,
"params":{
"q":"title:公益",
"indent":"on",
"rows":"5",
"wt":"json"}},
"response":{"numFound":22,"start":0,"docs":[
{
"id":"1511527967907",
"title":"萨顶顶的公益三段论",
"url_s":"http://gongyi.sohu.com/20120724/n348917750.shtml",
"_version_":1584951950479196160},
{
"id":"1511527966992",
"title":"思源焦点公益基金救助孩子:永康",
"content":"不满一岁的永康是个饱经病痛折磨的孩子,2011年7月5日出生的他,患有先天性心脏病、疝气,一出生便被遗弃。2012年1月8日,才5个月大的永康被发现呼吸困难,随后送往医院进行抢救治疗,病情稳定后于1月28日出院。2012年2月13号,永康在思源焦点公益基金的帮助下在医院接受手术治疗,术后仅8天,永康突发右侧腹股沟斜疝嵌顿及肠梗阻,又再次进行抢救治疗,术后进重症监护室。3月7日,几经病痛折磨的永康终于康复出院,目前他的病情已经稳定。",
"url_s":"http://gongyi.sohu.com/20120612/n345424232.shtml",
"_version_":1584951949519749120},
{
"id":"1511527967618",
"title":"2011“芯世界”公益创新奖获奖项目",
"content":"2011年7月3日-8日,芯世界组委会带领2011“芯世界”公益创新奖获奖机构代表在韩国开始了一场精彩的社会创新之旅。韩国公益组织的创新理念和运作方式给代表团成员留下了深刻的印象。7月12日在北京中国科学院文献情报中心、7月23日在上海浦东新区峨山路613号公益创业园区,代表团成员与众多公益组织分享了自己的感受和收获。[ 详细 ]5月15日晚9点,2011“芯世界”公益创新奖颁奖典礼在一片温暖的歌声中落下帷幕,2011"芯世界"公益创新奖10强、优秀奖、北京万通基金会项目资助奖以及组委会提名奖揭晓了所有奖项。 [ 获奖名单 ]",
"url_s":"http://gongyi.sohu.com/s2011/xinshijie",
"_version_":1584951950175109120},
{
"id":"1511527967855",
"title":"2011“芯世界”公益创新奖获奖项目",
"content":"2011年7月3日-8日,芯世界组委会带领2011“芯世界”公益创新奖获奖机构代表在韩国开始了一场精彩的社会创新之旅。韩国公益组织的创新理念和运作方式给代表团成员留下了深刻的印象。7月12日在北京中国科学院文献情报中心、7月23日在上海浦东新区峨山路613号公益创业园区,代表团成员与众多公益组织分享了自己的感受和收获。[ 详细 ]5月15日晚9点,2011“芯世界”公益创新奖颁奖典礼在一片温暖的歌声中落下帷幕,2011"芯世界"公益创新奖10强、优秀奖、北京万通基金会项目资助奖以及组委会提名奖揭晓了所有奖项。 [ 获奖名单 ]",
"url_s":"http://gongyi.sohu.com/s2011/xinshijie/",
"_version_":1584951950423621632},
{
"id":"1511527968422",
"title":"思源焦点公益基金医疗救助申请表",
"content":"思源焦点公益基金医疗救助申请表1、姓名姓名2、性别性别3、出生日期出生日期4、户口住址户口住址5、联系人联系人6、电话电话7、健康状况健康状况8、诊治医院诊治医院9、病情诊断病情诊断10、救治方案救治方案11、预算预算12、助医小组成员助医小组成员13、备注备注",
"url_s":"http://gongyi.sohu.com/20120613/n345502187.shtml",
"_version_":1584951951018164224}]
}}
分面:
//todo
高亮:
//todo
分组:
//todo
二、SolrJ主要元素
SolrClient:(从solr5开始,SolrServer就已经改名为SolrClient)作为客户端,连接Solr,发送请求进行增删查改的工 作。
创建方法:
public static final String SERVER_URL = "http://localhost:8080/solr/news";
public static void main(String[] args) throws IOException, SolrServerException {
SolrClient solrClient = new HttpSolrClient.Builder(SERVER_URL).build();
//...
}
SolrQuery:用于设置参查询的条件
最主要的方法:
1、直接通过属性名设置
set( String name, String ... val )set( String name, int val )
set( String name, boolean val )
例如:
query.set(CommonParams.FQ, fq);
query.set(CommonParams.FL, fl);
query.set(CommonParams.SORT, sort);
query.set(CommonParams.START, start);
query.set(CommonParams.ROWS, rows);
2、通过SolrQuery包装后的方法设置查询属性
SolrQuery的方法比较多,但是大部分都可以通过命名来判断用法,下面是一个使用的例子:String queryStr = "*:*"; SolrQuery solrQuery = new SolrQuery(queryStr).setFields("title","content","score"); solrQuery.setHighlight(true); solrQuery.addHighlightField("content"); solrQuery.setFacet(true); //...
QueryResponse:查询结果
查询的返回的结果:
QueryResponse response = solrClient.query(solrQuery);
1、获取文档方法:
a、获取文档列表
public SolrDocumentList getResults()
示例:public static final String SERVER_URL = "http://localhost:8080/solr/news"; public static void main(String[] args) throws IOException, SolrServerException { SolrClient solrClient = new HttpSolrClient.Builder(SERVER_URL).build(); String queryStr = "title:公益"; SolrQuery solrQuery = new SolrQuery(queryStr).setFields("title", "content", "score"); solrQuery.setFacetMinCount(5); solrQuery.setRows(5); QueryResponse response = solrClient.query(solrQuery); SolrDocumentList results = response.getResults(); for (SolrDocument result : results) { prettyPrint(System.out,result); } } static void prettyPrint(PrintStream out, SolrDocument document) { List<String> filedNames = new ArrayList<>(document.getFieldNames()); Collections.sort(filedNames); out.println(); for (String filedName : filedNames) { out.println(String.format("\t%s: %s", filedName, document.getFieldValue(filedName))); } out.println(); }
b、获取bean列表
public <T> List<T> getBeans(Class<T> type)示例:Bean定义:(字段上需要有Solr的@Field注解)public static final String SERVER_URL = "http://localhost:8080/solr/news"; public static void main(String[] args) throws IOException, SolrServerException { SolrClient solrClient = new HttpSolrClient.Builder(SERVER_URL).build(); String queryStr = "title:公益"; SolrQuery solrQuery = new SolrQuery(queryStr).setFields("title","content","score"); solrQuery.setFacetMinCount(5); solrQuery.setRows(5); QueryResponse response = solrClient.query(solrQuery); List<News> beans = response.getBeans(News.class); for (News bean : beans) { System.out.println(bean); } }
public class News { @Field("id") private String id; @Field("url_s") private String url; @Field("title") private String title; @Field("content") private String content; //省略get、set、toString方法 }
2、获取分面
3、获取高亮结果
//todo
SolrInputDocument:新增或更新Solr文档时需要使用的类
三、SolrJ使用示例
因为文件比较长,所以下面只贴出一部分查询的方法,完整文件。。em。。再改改
/** * 查询,可以指定是否高亮以及高亮的字段 * @param klass bean'class * @param q * @param fq * @param fl * @param sort * @param page * @param rows * @param isHighLighting 是否高亮 * @param fieldsNameToHighlinght 需要高亮的字段数组 * @param idName 主键名 * @param hook 钩子方法,调用时可以再次修改查询的功能 * @param <T> * @return * @throws IOException * @throws SolrServerException * @throws NoSuchMethodException * @throws IllegalAccessException * @throws InvocationTargetException */ public <T> List<T> query(Class<T> klass,String q, String[] fq, String[] fl, String sort, int page, int rows ,boolean isHighLighting,String[] fieldsNameToHighlinght,String idName,SolrServiceHook hook) throws IOException, SolrServerException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { SolrQuery query = getSolrQuery(q, fq, fl, sort, page, rows);//根据条件创建SolrQuery对象 hook.modifySolrQuery(query);//调用方法时,可以根据该接口在查询前修改query行为 List<T> results = getBeans(klass, query, isHighLighting, fieldsNameToHighlinght, idName);//获取bean列表(可以附带高亮结果) return results; } //创建bean public SolrQuery getSolrQuery(String q, String[] fq, String[] fl,String sort, int page,int rows) { int start = (Math.max(page, 1) - 1) * rows; SolrQuery query = new SolrQuery(); query.set(CommonParams.Q, q); query.set(CommonParams.FQ, fq); query.set(CommonParams.FL, fl); query.set(CommonParams.SORT, sort); query.set(CommonParams.START, start); query.set(CommonParams.ROWS, rows); return query; } //获取QueryRespiose public QueryResponse getSolrResponse(SolrQuery query) throws IOException, SolrServerException { return solrClient.query(query); }
public <T> List<T> getBeans(Class<T> klass, SolrQuery query,boolean isHighLighting,String[] fieldsNameToHighlinght,String idName) throws IOException, SolrServerException, NoSuchMethodException, IllegalAccessException, InvocationTargetException { if (isHighLighting) { query.setHighlight(true); for (String fieldNameToHighlight : fieldsNameToHighlinght) { query.addHighlightField(fieldNameToHighlight); } query.setHighlightSimplePre(HIGHLIGHT_SIMPLE_PRE); query.setHighlightSimplePost(HIGHLIGHT_SIMPLE_POST); } //查询 QueryResponse response = getSolrResponse(query); //获取结果 List<T> results = response.getBeans(klass); //将高亮字段注入到需要高亮的字段中 if (isHighLighting) { if (ServiceUtils.isEmpty(idName)) { //--如果输入的idName为空,则通过反射遍历字段中solr@Field注解,如果注解value中带有“id”,则使用该字段,否则使用默认名"id" Field[] fields = klass.getDeclaredFields(); for (Field field : fields) { org.apache.solr.client.solrj.beans.Field annotation = field.getAnnotation(org.apache.solr.client.solrj.beans.Field.class); if (annotation == null) { continue; } String annoValue = annotation.value(); if (ServiceUtils.isEmpty(annoValue)) { continue; } if (annoValue.toLowerCase().indexOf("id") != -1) { idName = annoValue; break; } } //遍历后idName依然为空,则使用默认字段 if (idName == null) { idName = ID_NAME; } } setHighLightValue(results, response, idName, fieldsNameToHighlinght); } return results; }
/** * 根据query获取相应的bean列表 * 1、如果需要高亮,设置高亮查询参数 * 2、查询 * 3、获取查询结果--bean列表 * 4、<strong>如果未设置高亮则直接返回< > * 5、获取主键字段名(用于确定bean对应的高亮结果);如果输入的id为空,则遍历bean字段的注解value值,使用遇到的第一个带有"id"的字段作为id * 6、获取高亮结果并设置到bean中 * @param klass bean'Class,用于反射设置值 * @param query * @param isHighLighting * @param fieldsNameToHighlinght * @param idName * @param <T> * @return * @throws IOException * @throws SolrServerException * @throws NoSuchMethodException * @throws IllegalAccessException * @throws InvocationTargetException */
/**
* 将高亮段落注入到bean中
* 1、获取主键字段值
* 2、获取高亮结果(map类型,key为文档id,value为查询结果(map类型,key为字段名,value为该字段的高亮结果))
* 3、主键值和文档主键值进行比对
* 4、使用反射,将高亮结果设置设置到相应的字段中
* @param beans bean列表
* @param response solrResponse
* @param idFieldName bean中主键字段名
* @param fields 高亮的字段
* @param <T>
* @return
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalAccessException
*/public <T> List<T> setHighLightValue(List<T> beans, QueryResponse response,String idFieldName,String[] fields) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { if (beans.isEmpty() || fields.length == 0 || StringUtils.isEmpty(idFieldName)) { return beans; } Class<T> klass = (Class<T>) beans.get(0).getClass(); Field idField = null;// Map<String, Field> fieldMap = new HashMap<>(fields.length); for (String field : fields) { try { Field fieldWithRef = klass.getDeclaredField(field); fieldWithRef.setAccessible(true); fieldMap.put(field, fieldWithRef); } catch (NoSuchFieldException e) {// e.printStackTrace(); } } try { idField = klass.getDeclaredField(idFieldName); idField.setAccessible(true); } catch (NoSuchFieldException e) { return beans; } Map<String, Map<String, List<String>>> highlightingMap = response.getHighlighting(); for (T item : beans) { Object id = idField.get(item); for (Map.Entry<String, Map<String, List<String>>> highlighting : highlightingMap.entrySet()) { if (!highlighting.getKey().equals(id.toString())) { continue; } //遍历每个需要设置的字段 for (String field : fields) { List<String> valueList = highlighting.getValue().get(field); if (valueList == null || valueList.isEmpty()) { continue; } StringBuilder stringBuilder = new StringBuilder(); for (String s : valueList) { stringBuilder.append(s).append(this.GAP); } String value = stringBuilder.toString(); if (ServiceUtils.isEmpty(value)) { continue; } //使用反射设置高亮 try { Field subField = fieldMap.get(field); ServiceUtils.setValue(item,subField,value); } catch (IllegalAccessException e) { e.printStackTrace(); } } break; } } return beans; }