在浏览本文前希望你已经对solr已有一定的了解,可以参考我的其他文章进行学习
本项目需要额外启动一个solr:如何搭建solr的配置环境
本项目中用到了该文的第二种方法来导入数据:solr数据导入的两种方法
本文写了点在配置时遇到的坑和几个参数的意义:solr中域的作用和坑
如果~~你实在不想配置,没关系,在百度云中我上传了两个版本,solr-7.7.2-jetty是没有配置数据库链接的版本,solr-7.7.2-jetty-connectDB是配置了数据库链接的版本,里面均含有本项目的实体类配置、数据库中的实体类数据,直接启动就能用
链接:https://pan.baidu.com/s/1h2279pQZIDgCMLiP4DREbA
提取码:ziem
项目地址:https://github.com/g992987642/boot-solr
项目展示:

这里的所有数据都是通过solr查出来的,邮箱的高亮也是通过solr实现(这个高亮确实是天坑)。
注意:solr入门我感觉并不难,但是有不少小坑需要踩,基本也是能通过搜索引擎解决的,但是如何用好确实是一门学问,本项目只是简单入门。
先是用.sql文件创建一个数据库啦,然后修改对应的配置(记得去改哦),.sql文件已经放在项目的doc文件夹中了

注意,本项目是通过mybatis查询后再添加到solr的方式进行存储的,如果是第一次运行,请在数据库创建完成后,打开框选中的代码行,进行导入,后续运行注释该行即可。

然后是配置SolrConfig类,与redisTemplate类似,为了注入solrTemplate

在service的实现类中实现了两种高亮查询的方式,一种是通过solrTemplate(这是Spring
data的封装类,但是如果想实现只对查询字符串高亮而不是整个字段的话,本例中并没有实现),还有一种是通过solrClient自带的查询方式(需要设置的参数比较多,当然也比较自由,实现了一部分准确字符串高亮)
即solrTemplate只实现了 查询qq 得到结果992987642@qq.com (全部高亮)
用solrClient实现了查询qq,得到结果992987642@qq.com(准确字符串高亮)

注意:在solr中高亮的实现是通过查询所有结果后,再将高亮域进行高亮实现的,所有查询结果与高亮域查询结果存储在不同地方,需要通过高亮域置换所有查询结果中应该高亮的地方,才能实现高亮。
说下下面方法的思路:使用solrClient时,需要配置查询的分页和高亮域,得到所有域的信息和高亮域的信息(注意,这两个域是分开查询出来的),例如查询结果为[{id: "123", field: "<em>xxx</em>"}],被<em></em>修饰的xxx就是高亮部分,需要通过未高亮的域的值替换为高亮的值来实现。
private ResponseCode solrQuerySearch(String keyword, Integer current, Integer rows) {
if (StringUtils.isEmpty(keyword)) {
return new ResponseCode("请输入查询内容");
}
if (current == 1) {
current = 0;
} else {
current = (current - 1) * rows;
}
SolrQuery query = new SolrQuery();
query.setStart(current);
query.setRows(rows);
query.set("wt", "json");
try {
String[] fields = {"item_username", "item_email", "item_qq", "item_password"}; //设置solr中定义的域
//高亮配置
String[] lightNames = {"item_username", "item_email", "item_qq"}; //设置需要高亮的域
//这里对应了solr管理页面中是否高亮的选项
query.setParam("hl", "true");
query.setParam("hl.fl", lightNames);
query.setHighlightSimplePre("<em style='color: red'>");
query.setHighlightSimplePost("</em>");
/**
* 设置查询关键字的域
* 一般对应solr中的复制域(<copyFiled>)。
* 因为用户查询的数据不确定是什么,定义在复制域中的字段,Solr会自动进行多字段查询匹配
*/
//query.set("q", "keyword:*" + keyword + "*"); //在Solr中查询语句:/select?q=keyword:*xxx*,这种方式也不会让准确字符串高亮
query.set("q", "keyword:" + keyword );//在Solr中查询语句:/select?q=keyword:xxx,只有这种方式才能准确字符串高亮
QueryResponse response = solrClient.query(query);
//获取被高亮的数据集合,其中的数据结构类似:[{id: "123", field: "<em>xxx</em>"}]
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
SolrDocumentList documents = response.getResults(); //获取匹配结果
long numFound = documents.getNumFound(); //获取匹配的数据个数
if (numFound != 0) {
List<Object> entityList = new ArrayList<>();
for (SolrDocument document : documents) {
//documents中存放了匹配的所有数据(未高亮),而highlighting中存放了高亮匹配的数据(高亮)
//通过id主键获取到id值,在highlighting中通过id值获取对应的高亮数据
Map<String, List<String>> listMap = highlighting.get(document.getFieldValue("id").toString());
for (int i = 0; i < lightNames.length; i++) {
if (listMap.get(lightNames[i]) != null) {
//根据设置的高亮域,将documents中未高亮的域的值替换为高亮的值
document.setField(lightNames[i], listMap.get(lightNames[i]).get(0));
}
}
Map<String, Object> fieldMap = new HashMap<>();
for (int i = 0; i < fields.length; i++) {
//前端需要的是实体类的名称email,不是solr里的item_email
fieldMap.put(fields[i].split("_")[1], String.valueOf(document.getFieldValue(fields[i])));
}
entityList.add(fieldMap);
}
return new ResponseCode(entityList, numFound);
} else {
return new ResponseCode("未搜索到任何结果");
}
} catch (Exception e) {
e.printStackTrace();
return new ResponseCode("服务器异常");
}
}
private ResponseCode solrTemplateSearch(String keyword, Integer current, Integer rows) {
//高亮配置
HighlightQuery query = new SimpleHighlightQuery();
String[] fieldNames = {"item_username", "item_email", "item_qq"};
HighlightOptions highlightOptions = new HighlightOptions().addField(fieldNames); //设置高亮域
highlightOptions.setSimplePrefix("<em style='color: red'>"); //设置高亮前缀
highlightOptions.setSimplePostfix("</em>"); //设置高亮后缀
query.setHighlightOptions(highlightOptions); //设置高亮选项
if ("".equals(keyword)) {
return new ResponseCode("请输入查询内容");
}
try {
/**
* 通过Criteria构建查询过滤条件
* 其中这里的`keyword`等价于solr core中schema.xml配置的域,且`keyword`是复制域名
* 因为查询的内容是不确定的,solr提供了复制域实现同时查询多个域中的数据,并返回匹配的结果
*/
Criteria criteria = new Criteria("keyword");
//按照关键字查询
if (keyword != null && !"".equals(keyword)) {
criteria.contains(keyword);
}
query.addCriteria(criteria);
if (current == null) {
current = 1; //默认第一页
}
if (rows == null) {
rows = 20; //默认每次查询20条记录
}
query.setOffset((long) ((current - 1) * rows)); //从第几条记录开始查询:= 当前页 * 每页的记录数
query.setRows(rows);
//
HighlightPage<Search> page = solrTemplate.queryForHighlightPage("", query, Search.class);
// 循环高亮入口集合
for (HighlightEntry<Search> h : page.getHighlighted()) {
Search search = h.getEntity(); //获取原实体类
if (h.getHighlights().size() > 0) {
h.getHighlights().forEach(light -> {
if (search.getUsername().contains(keyword)) {
search.setUsername(light.getSnipplets().get(0));
}
if (search.getEmail().contains(keyword)) {
search.setEmail(light.getSnipplets().get(0));
}
if (search.getQq().contains(keyword)) {
search.setQq(light.getSnipplets().get(0));
}
});
}
}
return new ResponseCode(page.getContent(), page.getTotalElements());
} catch (Exception e) {
e.printStackTrace();
return new ResponseCode("查询失败");
}
}
网友评论