在上篇文章中我已经讲了solr的安装与配置、DIH全量导入、ik分词器的配置,今天给小伙伴们分享一下springboot如何整合solr实现增删改查。先赞后看,已成习惯,点赞!!!
目录
一、导包
日常导包,不必多言
<!-- solr-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
版本的话你们自己根据自己情况而定。
二、配置solrHost
配置solrhost分两种情况,一种是只有一个core的,一种是有多个core的。只有一个core的同学配置就很简单了,在springboot的主配置文件application.properties中添加配置即可。
至于有多个core的同学,就不需要在主配置文件 配置host了,你需要在每次调用solr操作的时候指明用哪个core的solrClient去操作。通过HttpSolrClient solrClient = new HttpSolrClient(url);构造出对应core的solrClient进行相关操作。
三、实体类映射
在我们要查询的表的对应实体类上添加注解,没有的的可以新建一个,目的主要是为了我们后面查询的时候可以直接getBeans,不用再一个属性一个属性的封装,这里以我的为例,我的core为product_core,查询的信息为Product信息
这里有三点需要注意一下
1.如果你有多个Core,这里就不要添加@SolrDocument注解了,就像我前面说的,直接通过HttpSolrClient solrClient = new HttpSolrClient(url);构造出对应core的solrClient进行相关操作,只添加@Field注解即可
2.我这里的@Field注解没有配置映射参数是因为我的实体类的属性名称与我在core中配置的name一样,所以不用添加映射参数,如果你的实体类属性名称与你的Core中配置的字段name不一样,这里的@field注解需要添加映射参数,如:@Filed(“id”)
3.solr的字段类型中是没有BigDecimal类型的!我的解决方案为solr中配置价格为pdouble类型,查询的时候先转为json字符串,再转为实体类。如果你的字段类型中有BigDecimal类型,可以参考一下。也欢迎补充更好的方案。
另外,据说solr配置的id只能为String类型,我没有验证,因为我一开始id就为String类型,有为自增类型的小伙伴可以试一下。如果确实是真的,希望留言回复补充,我好给大家出解决方案。
四、增删改
solr的增删改都是通过solrClient进行操作的,方法也都很简单,需要注意的是,solr的增删改查都是针对索引的,并不作用于数据库
@Service
public class SolrServiceImpl implements SolrService {
@Autowired
private SolrClient solrClient;
private Logger logger = Logger.getLogger(SolrServiceImpl.class);
@Override
public void add(ProductInfo productInfo){
SolrInputDocument document = new SolrInputDocument();
document.addField("productId",productInfo.getProductId());
try {
solrClient.add(document);
solrClient.commit();
} catch (IOException io) {
io.printStackTrace();
logger.error("solr添加索引失败!");
} catch (SolrServerException solre) {
solre.printStackTrace();
logger.error("solr添加索引失败!");
}
}
@Override
public void delete(String productId) {
try {
solrClient.deleteById(productId);
solrClient.commit();
}catch (IOException io) {
io.printStackTrace();
logger.error("solr删除索引失败!");
} catch (SolrServerException solre) {
solre.printStackTrace();
logger.error("solr删除索引失败!");
}
}
@Override
public void update(ProductInfo productInfo) {
try {
solrClient.addBean(productInfo);
solrClient.commit();
}catch (IOException io) {
io.printStackTrace();
logger.error("solr更新索引失败!");
} catch (SolrServerException solre) {
solre.printStackTrace();
logger.error("solr更新索引失败!");
}
}
}
以上就是solr增删改索引的方法
五、solr查询
solr的查询分为两种,一种是普通查询,一种是高亮查询。两者的区别就是高亮查询可以高亮显示查询结果中的关键字。下面先给大家看一下普通查询,其实操作也很简单。
public List<ProductInfo> simpleQuery(String query) {
List<ProductInfo> productInfoList = new ArrayList<>();
SolrQuery solrQuery = new SolrQuery();
solrQuery.setQuery(query);
try {
QueryResponse response = solrClient.query(solrQuery);
if (response != null) {
// productInfoList = response.getBeans(ProductInfo.class);
SolrDocumentList results = response.getResults();
for (SolrDocument document: results
) {
ProductInfo productInfo;
String jsonString = JSON.toJSONString(document);
productInfo = JSONObject.parseObject(jsonString,ProductInfo.class);
productInfoList.add(productInfo);
}
} else {
logger.info("solr查询为空");
}
}catch (IOException io) {
io.printStackTrace();
logger.error("solr查询失败!");
} catch (SolrServerException solre) {
solre.printStackTrace();
logger.error("solr查询失败!");
}
return productInfoList;
}
在上面的代码中,由于我的实体类中有BigDecimal类型,所以不得已做了一下转换,没有此类型的小伙伴可以直接使用我注释的方法也就是QueryResponse.getBeans(),下面给大家看一下solr高亮查询如何实现
public List<ProductInfo> queryWithHighLighting(String query) {
List<ProductInfo> productInfoList = new ArrayList<>();
SolrQuery solrQuery = new SolrQuery();
// 设置默认查询域
solrQuery.set("df","productName");
// 设置查询条件
solrQuery.setQuery(query);
// 开启高亮显示
solrQuery.setHighlight(true);
// 添加高亮显示的域
solrQuery.addHighlightField("productName");
// 设置高亮显示1前缀
solrQuery.setHighlightSimplePre("<font color='red'>");
// 设置高亮显示后缀
solrQuery.setHighlightSimplePost("</font>");
try {
// 执行查询
QueryResponse response = solrClient.query(solrQuery);
if (response == null) {
logger.info("solr查询为空!");
return null;
}
// 获取查询结果
SolrDocumentList results = response.getResults();
if (results.isEmpty()) {
logger.info("solr查询为空!");
return null;
}
// 获取高亮显示的结果集
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
// 遍历高亮显示的结果集封装到返回结果中
for (SolrDocument document: results
) {
ProductInfo productInfo;
List<String> productNames = highlighting.get(document.get("productId")).get("productName");
if (!CollectionUtils.isEmpty(productNames)) {
document.setField("productName",productNames.get(0));
}
String jsonString = JSON.toJSONString(document);
productInfo = JSONObject.parseObject(jsonString,ProductInfo.class);
productInfoList.add(productInfo);
}
} catch (IOException io) {
io.printStackTrace();
logger.error("solr查询失败!");
} catch (SolrServerException solre) {
solre.printStackTrace();
logger.error("solr查询失败!");
}
return productInfoList;
}
从上面的代码中不难看出来高亮显示的结果集和其他字段的结果集并不在一个集合中,高亮显示的结果集在总结果集的HighLighting中,具体的数据结构如下
"response":{"numFound":21,"start":0,"docs":[
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"},
{
"productName":"商品名称",
"productProfile":"这里是商品简介"}]
},
"highlighting":{
"1":{
"productName":["<font color='red'>商品名称</font>"]},
"10":{
"productName":["<font color='red'>商品名称</font>"]},
"11":{
"productName":["<font color='red'>商品名称</font>"]},
"12":{
"productName":["<font color='red'>商品名称</font>"]},
"2":{
"productName":["<font color='red'>商品名称</font>"]},
"3":{
"productName":["<font color='red'>商品名称</font>"]},
"4":{
"productName":["<font color='red'>商品名称</font>"]},
"9":{
"productName":["<font color='red'>商品名称</font>"]},
"product1":{
"productName":["<font color='red'>商品名称</font>"]},
"product10":{
"productName":["<font color='red'>商品名称</font>"]},
"product11":{
"productName":["<font color='red'>商品名称</font>"]},
"product12":{
"productName":["<font color='red'>商品名称</font>"]},
"product13":{
"productName":["<font color='red'>商品名称</font>"]},
"product2":{
"productName":["<font color='red'>商品名称</font>"]},
"product3":{
"productName":["<font color='red'>商品名称</font>"]},
"product4":{
"productName":["<font color='red'>商品名称</font>"]},
"product5":{
"productName":["<font color='red'>商品名称</font>"]},
"product6":{
"productName":["<font color='red'>商品名称</font>"]},
"product7":{
"productName":["<font color='red'>商品名称</font>"]},
"product8":{
"productName":["<font color='red'>商品名称</font>"]}}}
此处highlighting的key为商品Id。相信看过solr的这个返回结果再回头看处理返回结果的代码就很清楚了。需要注意的是,普通查询,也就是如果不开启高亮显示,返回结果中是没highlighting这个属性的。
六、实际应用
solr对索引的增删改查操作一般体现在商品搜索,如:模糊搜索一个商品名称,这个时候一般会先到solr中查询,如果solr中没有查到,再去数据库查询,如果数据库查到了,这时候就需要将该商品的索引添加到solr中,那么下次查询就能直接从solr中查询了。同样,数据库增删改的时候也要记得同步到solr。这里展示一下我的商品搜索是如何运用solr的
public RequestResult queryProductNameByKey(String key,String businessId) {
logger.info("*********************进入根据关键字查询产品名称接口*******************");
String solrKey = "productName:"+"*"+key+"* "+"AND businessId:"+businessId;
String likeKey = "%"+key+"%";
List<ProductInfo> products = new ArrayList<>();
try {
List<ProductInfo> infos = solrService.simpleQuery(solrKey);
if (CollectionUtils.isEmpty(infos)) {
logger.info("solr查询为空,开始调用数据库查询");
ProductInfoPoExample example = new ProductInfoPoExample();
example.createCriteria().andProductNameLike(likeKey).andBusinessIdEqualTo(businessId);
List<ProductInfoPo> productInfoPos = infoPOMapper.selectByExample(example);
if (CollectionUtils.isEmpty(productInfoPos)) {
logger.info("数据库查询关键字为空");
} else {
logger.info("数据库查询出带有'"+key+"'关键字的数量为"+productInfoPos.size());
for (ProductInfoPo productInfoPo: productInfoPos
) {
ProductInfo productInfo = new ProductInfo();
BeanUtils.copyProperties(productInfoPo,productInfo);
products.add(productInfo);
solrService.add(productInfo);
logger.info("添加索引库成功");
}
}
} else {
logger.info("solr查询出带有'"+key+"'关键字的数量为"+infos.size());
products.addAll(infos);
}
return ResultUtils.success(products);
} catch (Exception e) {
e.printStackTrace();
logger.error("查询关键字失败");
return ResultUtils.fail(ErrorCode.SERVER_SERVICE_ERROR);
}
}
下面是查询结果
我这里本来只是查询名称集合,后需求更改,查询产品集合,所以日志还没来得及改,希望这篇文章对小伙伴们能有所帮助,也欢迎大家留言补充,共同进步。走之前几点的点赞哦*_*
来源:CSDN
作者:莫离瑜
链接:https://blog.csdn.net/ding_ran/article/details/103919816