java与solr连接,调用查询的方式,我知道的有两种:
solrj方式:这种方式写法较麻烦,倒不是因为难,就是简单的逻辑,有时候为了一个业务写一堆代码,所以solrj的这种方式还是比较灵活的,能实现你需要的变态业务需求。我发现它的一个小缺点,就是相对于solr-jpa那种方式,它的速度稍慢一点。
jpa方式:这种方式除了速度快点,基本没什么代码,都是自己搞好的,只要按照它的方式写就OK了,写法其实就是平时的jpa写法。缺点,其实我也不确定,对于一些稍微复杂的业务需求,我不知道它如何实现,本来我是用的这种方式,最后改成了solrj方式。
推荐solrj吧,虽然写法有点傻,但是至少它能满足你的不同变态的要求。
solrj搭建的连接方法:
1.我是自己建立的spring boot项目单独用来做solr查询的,结构如下:
首先,因为solr的查询结果我封装成了对象,facade项目是用于将来其他项目引用solr查询时与返回值匹配上。rest项目有具体的controller接口和具体的连接solr的实现逻辑。rest项目的pom同时引用了facade项目,保证外部引用和自己调用的接口以及对象的一致。
该项目仓促,还不知道以后怎么调用,打算改成dubbo发布出接口那种,现在还没改,主要写一下solrj的连接方式。其他都靠自己去设计了。
2.引入的jar包如下:
<!--parent标签是spring boot的统一引入的一种方式,如果你像我还有一个parent项目,那需要将下边的parent标签内容移到parent项目中,将其他的引入到rest项目-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<dependencies>
<!--spring boot项目必须引入的依赖web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring boot项目引入的solr的依赖-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-solr</artifactId>
</dependency>
<!--下边的这个依赖可以不用引用,我是让前端给我传的参数是以HttpServletRequest形式传入的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
3.这里不写我是如何在spring boot项目中放置的,源码在该文章最下边可以下载,只以一个main方法的形式,贴出solr的从连接到查询的部分。
package cloud.solr.domain;
//实体类
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.annotation.Id;
import org.springframework.data.solr.core.mapping.SolrDocument;
import java.io.Serializable;
@SolrDocument(solrCoreName="fbf") //solrj不需要加这个,加上也不报错,我主要是该项目jpa和solrj都可以,我就把实体类弄成了这样。
public class Fbf implements Serializable {
@Id
@Field
private String poid; //主键需要加两个注解
@Field
private String fbfbm; //普通的属性加Field注解即可
@Field
private String fbfmc;
//省略get和set方法
}
package cloud.solr.controller;
import cloud.solr.domain.Fbf;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.StringUtils;
import java.io.IOException;
import java.util.List;
import org.springframework.web.bind.annotation.*;
/**
* Created by lsf on 2017/10/17.
*/
@RestController
@RequestMapping("/testSolr")
public class TestController {
public static void main(String[] args){
/**
* http://192.168.1.170:8983/solr/fbf fbf是solr的一个core名称
*/
HttpSolrClient solrClient = new HttpSolrClient("http://192.168.1.170:8983/solr/fbf");
SolrQuery query = new SolrQuery();
query.setSort("createtime",SolrQuery.ORDER.asc); //设置排序参数及排序规则
String pageNo = "1"; //第几页
String pageSize = "10"; //每页多少数据
if(NumberUtils.isNumber(pageNo) && NumberUtils.isNumber(pageSize)){
int startPage = Integer.valueOf(pageNo);
int pageNum = Integer.valueOf(pageSize);
query.setStart((startPage-1)*pageNum);//起始页,这里一定要注意,不能直接把pageNo赋值给start,start表示从第一个数据开始,第一条从0开始。
query.setRows(pageNum);//每页显示数量
}
StringBuffer buffer = new StringBuffer();
String fbfmc = "何寨街道季家村高北组"; //查询条件
if(!StringUtils.isEmpty(fbfmc)){
buffer.append("fbfmc:"+fbfmc); //如果你的fbfmc字段在solrHome/fbf/conf/manage-schema文件中定义的类型是text_ik,即已经分词了,那么这里可以这么写,如果你定义的是string类型,即没有分词,那这句话的append中的内容需要写成这样buffer.append("fbfmc:*"+fbfmc+"*"),这是solr的查询规则,没有分词最好是加上模糊查询符号"*"
query.set("q",buffer.toString());
}else{
query.set("q","*:*"); //没有传入参数则全部查询
}
QueryResponse rsp = null;
try {
rsp = solrClient.query( query );
} catch (Exception e) {
e.printStackTrace();
}
SolrDocumentList results = rsp.getResults();
System.out.println(results.getNumFound());//查询总条数,该总条数是符合该条件下的总条数,并不是pageSize的数量。
List<Fbf> fbfList = rsp.getBeans(Fbf.class);//该方法将返回结果转换为对象,很方便。
System.out.println(fbfList.get(0).getFbfmc());
}
}
其他常用的方法:
添加方法---是调用solrClient.addBean(Fbf fbf);
根据id查询方法---是调用solrClient.getById(id); //注意它返回值是SolrDocument,可以直接返回给前端,就是key value那种形式。
删除方法---是调用solrClient.deleteById(id);
没有修改方法,只能结合删除和添加来完成修改操作。
说明:
(1)关于solrj的查询出错,主要是查询参数的传入格式,就像上边的地方,如果fbfmc设置成了分词类型,千万不要再加*
,如果是string类型就需要加上*
才可以。
(2)如果你不想再封装成对象,那么你可以直接给前端返回SolrDocumentList results = rsp.getResults();,也就是SolrDocumentList对象即可。
(3)solrj的连接地址,要具体到某一个core名称上,比如上边的http://192.168.1.170:8983/solr/fbf
连接到了fbf这个core上。
spring boot solr jpa搭建的连接方法:
1.首先引入的jar包与上边的一样,具体也可以看我的项目,下载位置在最下边。
2.找到spring boot项目的application.properties文件,添加如下代码:
这个是连接solr的客户端的地址
spring.data.solr.host=http://192.168.1.170:8983/solr
3.添加实体类、jpa查询逻辑类等(以下代码与我的项目源码稍有不同,具体参照项目的下边的写法,我稍微改动了下)
package cloud.solr.domain;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.annotation.Id;
import org.springframework.data.solr.core.mapping.SolrDocument;
import java.util.Date;
@SolrDocument(solrCoreName="product") //jpa是在这里与具体的core关联的,所以这个必须加
public class Product {
@Id
@Field
private String id; //主键必须加这两个注解
@Field
private String name; //其他属性加一个注解
@Field
private String pic;
@Field
private double price;
@Field
private long comment;
//省略get和set方法
}
controller类
package cloud.solr.controller;
import cloud.solr.controller.base.BaseController;
import cloud.solr.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* Created by Administrator on 2017/10/17.
*/
@RestController
public class ProductController extends BaseController{
@Autowired
ProductService productService;
//根据名称查询
@RequestMapping(value = "/selectByName",method = RequestMethod.GET)
@CrossOrigin
public Object SelectObjectByName(HttpServletRequest request){
return productService.findByName(request.getParameter("name"));
}
//根据名称查询,并且分页
@RequestMapping(value = "/select",method = RequestMethod.GET)
@CrossOrigin
public Object SelectObject(HttpServletRequest request){
try {
//getPageRequest方法在父类里写了,就是一个封装Pageable对象的方法,具体在下边贴出来。
return productService.query(request.getParameter("name"),getPageRequest(request));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
在父类中的getPageRequest方法
/**
* 获取分页请求
*/
protected PageRequest getPageRequest(HttpServletRequest request){
int page = 1;
int size = 10;
Sort sort = null;
try {
String sortName = request.getParameter("sortName");
String sortOrder = request.getParameter("sortOrder");
if(StringUtils.isNotBlank(sortName) ){
if("desc".equalsIgnoreCase(sortOrder)){
sort = new Sort(Sort.Direction.DESC, sortName);
}else{
sort = new Sort(Sort.Direction.ASC, sortName);
}
}
page = Integer.parseInt(request.getParameter("pageNo")) - 1;
size = Integer.parseInt(request.getParameter("pageSize"));
} catch (Exception e) {
e.printStackTrace();
}
if(sort == null){
sort = new Sort(Sort.Direction.ASC, "id");
}
PageRequest pageRequest = new PageRequest(page, size, sort);
return pageRequest;
}
Service类
package cloud.solr.service;
import cloud.solr.domain.Product;
import cloud.solr.repository.ProductRepository;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class ProductService {
@Autowired
ProductRepository productRepository;
public List<Product> findByName(String name){
if(StringUtils.isEmpty(name)){
return new ArrayList<>();
}
return productRepository.findByName(name);
}
public void save(Product product){
if(product != null) {
productRepository.save(product);
}
}
public Page<Product> query(String queryString, Pageable pageable) throws Exception {
return productRepository.findByNameContaining(queryString, pageable);
}
}
repository类(注意:重点来了)
package cloud.solr.repository;
import cloud.solr.domain.Product;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.solr.repository.Query;
import org.springframework.data.solr.repository.SolrCrudRepository;
import java.util.List;
public interface ProductRepository extends SolrCrudRepository<Product, String> {
//如果要与名字精确匹配,则如下写法,其中Name为具体的属性名称,如果包含查询,模糊查询则findByNameContaining即可。写法与jpa写法一致。也要注意下solrHome中的manage-schema文件对属性类型的配置是text_ik还是string类型。
List<Product> findByName(String name);
//可以把@Query注释掉findByNameContaining就变成了 name:*?0*,仅按名称匹配
//@Query(value = "name:*?0* or category:*?0*")
Page<Product> findByNameContaining(String name, Pageable pageable);
}
jpa的写法都是一样的,可以从网上看下具体的写法,最下边我可以下载的项目里jpa这种写法我给注释掉了,应该都很容易看懂的。
我的spring boot项目源码下载地址
下一篇写高亮查询