查询@SOLR7实践(四)
查询
先说说客户的要求
- 用户只有一个搜索框,可以输入多个关键字进行检索;
- 搜索范围是公文系统包括文件标题(TITLE),文件编号(MARKID),文种(FORM),正文(CONTENT)等字段,通讯录包括名字(TITLE),部门(ORGNAME),手机号码(MOBILE),邮件地址(EMAIL)等字段;
- 字段的重要程度 标题>正文;
- 相关度相同时按时间倒序排列;
- 搜索结果可以按照时间范围进行过滤。
SOLR检索的参数说明,可参考如下文章
https://blog.csdn.net/yuwenruli/article/details/8448575
https://lucene.apache.org/solr/guide/6_6/common-query-parameters.html
https://www.cnblogs.com/Lxiaojiang/p/6800398.html
https://lucene.apache.org/solr/guide/6_6/the-dismax-query-parser.html
https://lucene.apache.org/solr/guide/6_6/the-extended-dismax-query-parser.html
结合伪代码说一下怎么实现的(相信我,代码一定跑不通的)
// 变量说明
// 用户输入搜索关键字(如:I like beijing)
String keyword;
// keyword用空格拆分的数组(如:[I, like, beijing])
String[] keywords;
// keywords用*连接的字符串(如:*I*like*beijing*)
String keywordJoinStart;
// keyword加"包裹的字符串(如:"I like beijing")
String keywordQuot;
// keywords每个元素加"包裹(如:["I", "like", "beijing"])
String keywordsQuot;
// 创建solr客户端
HttpSolrClient server = new HttpSolrClient.Builder(solrUrl).build();
// 创建solr查询器
SolrQuery query = new SolrQuery();
// TITLE,CONTENT,SRCHFLD 字段类型为text_ik
// TITLE_COPY 拷贝自TITLE,字段类型为string
// SRCHFLD 拷贝自除TITLE,CONTENT之外的查询字段
// *用于模糊匹配可以用在string类型的字段,不能用在text_ik类型的字段
// ”用于精确匹配可以用在string类型也可以用在text_ik类型的字段
// 对TITLE_COPY字段进行了正向的模糊匹配,这个开销是非常大的,整个搜索速度慢了10倍!!!
// 好在目前客户对搜索速度还可以接受。
// 调查过原因是单个的英数字在经过IK分词器后被遗弃了,
// 更深层次的原因是 LowerCaseTokenizerFactory 会过滤掉单个英数字。
// 解决方法有文章提出用EdgeNGramFilterFactory 替换 LowerCaseTokenizerFactory ,但对英文字母的大小写的支持会变差。
query.setParam("q","(TITLE_COPY:keywordJoinStart) OR (TITLE:keywordQuot) OR (CONTENT:keywordQuot) OR (SRCHFLD:keywordQuot) OR (SRCHFLD:keywordsQuot[0] AND ... AND SRCHFLD:keywordsQuot[n])");
//设置返回字段列表 * 全部索引字段,score 索引的评分
query.setParam("fl", "*,score");
// 设置返回结果的开始记录数(从0开始)和总记录数,完成分页功能
query.setParam("start", start);
query.setParam("rows", rows);
// 设置过滤字段,完成数据权限过滤
// SOLR处理fq时是默认使用缓存的,测试过query.addFilterQuery(filterQuery) 和 query.addFilterQuery(filterQueries[i]) 等写法,可能受限于测试环境和测试数据的原因,搜索速度未有明显提升
query.setParam("fq",filterQuery);
// 设置结果排序,先按评分排,再按时间排
query.addSort("score", ORDER.desc);
query.addSort("CREATETIME", ORDER.desc);
// 高亮显示
// 中文高亮显示总是有问题,要么漏词,要么只能标红单字。没有找到相关解决方法,使用了一个变通的方案,自己编码对搜索结果再进行高亮设置。
query.setParam("hl", highLight);
// 设置高亮显示的字段列表
query.setParam("hl.fl",flFieldList);
// 设置高亮显示的前缀
query.setParam("hl.simple.pre",flSimplePre);
// 设置高亮显示的后缀
query.setParam("hl.simple.post",flSimplePost);
// 设置highlighted片段的最大数,默认值是1,不需要修改
query.setParam("hl.snippets",flSnippets);
// 设置高亮显示的snippet返回的最大字节数
query.setParam("hl.fragsize",flFragsize);
// 设置eDisMax模式
query.setParam("defType", "edismax");
// 设置字段权重,影响结果排序
// 排序试了很多方法,记录下目前的方案(仍有部分数据未能排在应该的位置)
// 只说一下可以影响排序的SOLR参数和方法
// 参数 q, sort, dismax中 qf,pf,bq,bf,edismax中qf,pf,bq,bf,boost
// 方法 对字段升压,对搜索关键字升压,自己构造函数生成权重值等
// 对q中使用到的字段,按照重要性设置不同的权重
query.setParam("pf",”TITLE_COPY^100 TITLE^10 CONTENT^2 SRCHFLD“);
// 执行查询接收结果
QueryResponse qResponse = new QueryResponse();
qResponse = server.query(query);
server.close();
对于多个搜索关键字分布在多个字段中的排序问题的一个解决思路,每个字段用一个搜索框,每个字段都使用精确匹配,设置匹配度为100%,不同字段设置不同的权重,最后结果按时间排序。这可能才是用户的内心想要的。