Springboot Solr 配置和使用
目录
Springboot Solr 配置和使用目录.png一、springboot+solr简单测试
1、创建springboot项目和测试代码
环境:springboot+solr+swagger2
说明:在项目此处连接的是solr中core库,方式二创建的
pom.xml依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
具体pom文件内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!--集成swagger-API-->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.5.21</version>
<!--<scope>compile</scope>-->
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.5.21</version>
<!--<scope>compile</scope>-->
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
</exclusion>
</exclusions>
</dependency>
.yml文件
server:
context-path: /
port: 8080
spring:
data:
solr:
#后面这个core就是文件夹的名称,这里也可以不用写这个,如果这里不指定core,那么在代码中使用的时候,就需要指定core。
#host: http://127.0.0.1:8983/solr/core
#代码中可以指定core的地方有注释可以看
host: http://127.0.0.1:8983/solr
添加swagger2配置
创建文件夹:config\Swagger2Config.java
package com.dist.config;
import com.google.common.base.Predicate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author yangmin
* @date 2018/8/15
* @desc
*/
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket adminApi(){
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Admin API")
.forCodeGeneration(true)
.pathMapping("/")
.select()
.paths(paths())
.build()
.apiInfo(apiInfo())
.useDefaultResponseMessages(false);
}
private Predicate<String> paths(){
return PathSelectors.regex("^/(?!error).*$");
}
private ApiInfo apiInfo(){
Contact contact = new Contact("BaiDu", "controller://baidu.com", " zhengja@dist.com.cn");
return new ApiInfoBuilder()
.title("个人SpringBoot测试系统")
.description("开发API文档")
.contact(contact)
.version("1.0")
.build();
}
}
在resources/static下创建index.html
把以下内容复制,需要更改端口和项目地址
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>进入首页</h1>
<!--更改成自己的端口号-->
<a href="http://localhost:8080/swagger-ui.html">进入swagger页面测试2</a>
</body>
</html>
controller下SolrController.java类
package com.dist.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
* @author zhengja@dist.com.cn
* @data 2019/8/15 15:43
*/
@RequestMapping(value = "rest/solr")
@RestController
@Api(tags = {"SolrController"},description = "Solr 全文检索")
public class SolrController {
@Autowired
private SolrClient client;
@ApiOperation(value = "添加文档内容",notes = "向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义",httpMethod = "GET")
@RequestMapping(value = "insert",method = RequestMethod.GET)
public Object validator(@ApiParam(value = "name") @RequestParam String name,
@ApiParam(value = "age") @RequestParam String age){
try {
String idStr = String.valueOf(System.currentTimeMillis());
SolrInputDocument document = new SolrInputDocument();
document.setField("id", idStr);
document.setField("name", name);
document.setField("age",age);
// 把文档对象写入索引库
client.add("core",document);//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称,比如client.add("core", doc);
client.commit("core");//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称client.commit("core");
return idStr;
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
@ApiOperation(value = "更新文档内容",notes = "更新文档内容,跟添加的区别是:id不能变,其他的可以变",httpMethod = "GET")
@RequestMapping(value = "updateDocument",method = RequestMethod.GET)
public Object updateDocument(@ApiParam(value = "idStr") @RequestParam String idStr,
@ApiParam(value = "name") @RequestParam String name,
@ApiParam(value = "age") @RequestParam String age) throws Exception{
// 创建一个文档对象, 向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义
SolrInputDocument document = new SolrInputDocument();
document.setField("id", idStr);
document.setField("name", name);
document.setField("age",age);
// 把文档对象写入索引库
client.add("core",document);
// 提交
client.commit("core");
return document;
}
@ApiOperation(value = "全量或增量更新-数据库",notes = "java操作Solr的全量或增量更新,可以结合定时任务做定时全量或增量更新",httpMethod = "PUT")
@RequestMapping(value = "updateSolrData",method = RequestMethod.PUT)
public void updateSolrData() throws SolrServerException, IOException {
//创建一个查询对象
SolrQuery solrQuery = new SolrQuery();
//增量更新全部完成;注意这里entity的值为solr-data-config.xml里entity标签里的name值
final String SOLR_DELTA_PARAM = "/dataimport?command=delta-import&entity=order_info&clean=false&commit=true";
//全量更新全部完成
final String SOLR_FULL_PARAM = "/dataimport?command=full-import&entity=order_info&clean=true&commit=true";
//设置更新方式
solrQuery.setRequestHandler(SOLR_DELTA_PARAM);
// 执行查询
QueryResponse query = client.query("core",solrQuery);
//提交
client.commit("core");
}
@ApiOperation(value = "查询文档内容",notes = "查询文档内容",httpMethod = "GET")
@RequestMapping(value = "queryDocument",method = RequestMethod.GET)
public Object queryDocument(@ApiParam(value = "条件",defaultValue = "*:*") @RequestParam String condition,
@ApiParam(value = "连接文件夹 默 core",defaultValue = "core") @RequestParam String collection,
@ApiParam(value = "分页起始 默 1",defaultValue = "1") @RequestParam Integer pageStart,
@ApiParam(value = "分页结束 默 10",defaultValue = "10") @RequestParam Integer pageEnd) throws Exception {
// 创建一个查询条件
SolrQuery solrQuery = new SolrQuery();
// 设置查询条件
solrQuery.setQuery(condition);
// 设置分页
solrQuery.setStart(pageStart);
solrQuery.setRows(pageEnd);
// 执行查询
QueryResponse query = client.query(collection,solrQuery);
// 取查询结果
SolrDocumentList solrDocumentList = query.getResults();
System.out.println("总记录数:" + solrDocumentList.getNumFound());
for (SolrDocument sd : solrDocumentList) {
System.out.println(sd.get("id"));
System.out.println(sd.get("name"));
System.out.println(sd.get("age"));
}
return solrDocumentList;
}
@ApiOperation(value = "删除文档",notes = "删除文档",httpMethod = "DELETE")
@RequestMapping(value = "deteleDocument",method = RequestMethod.DELETE)
public Object deteleDocument(@ApiParam(value = "连接文件夹 默 core" ,defaultValue = "core") @RequestParam String collection,
@ApiParam(value = "idStr") @RequestParam String idStr) throws Exception {
// 根据id删除
UpdateResponse response = client.deleteById(collection, idStr);
// 根据条件删除
// httpSolrServer.deleteByQuery("");
// 提交
client.commit(collection);
return response;
}
}
然后启动该项目之后,进入项目地址:
http://localhost:8080/swagger-ui.html 执行-即可测试插入索引操作。
插入成功之后,访问:
http://127.0.0.1:8983/solr/#/
在solr管理界面的左下方有一个下拉框,选择你创建的core之后,再选择Query,往下拖到最后,点击Execute Query即可看见你刚才插入的索引。
solr效果.png
其他问题:
刚才我们代码中插入了两个列(id、name),如果你想新增一个列,比如名称叫做age,然后启动项目,在插入索引,在solr管理平台中就看不见这个列名和列对应的值,原因是id、name这两列在solr中已经默认配置了。这种情况解决方式如下:
在你创建的core文件夹下面,打开conf文件夹,修改里面的managed-schema文件,修改地点如下:
# 132行后面增加(后面这几行随意位置增加就可以)
<field name="age" type="text_general" indexed="true" stored="true"/>
# 245行后面增加(后面这几行随意位置增加就可以)
<copyField source="age" dest="text"/>
修改完成之后重启solr,然后重新插入索引就可以成功操作了。
再测试:
SolrController.java
SolrInputDocument doc = new SolrInputDocument();
doc.setField("id", idStr); //id是默认配置,在你创建的core文件夹下面,打开conf文件夹,修改里面的managed-schema文件
doc.setField("name", content); // name是默认配置
doc.setField("age","23"); //自定义配置:在你创建的core文件夹下面,打开conf文件夹,修改里面的managed-schema文件,添加列 age
效果图:
solr效果.png
二、升级版测试
添加配置:
pom.xml
<!--solr 全文检索-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-solr</artifactId>
</dependency>
<!--自定义工具类:解决属性值null指针异常,将 null 转成 ""-->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
*.yml文件配置 solr
spring:
data:
solr:
#后面这个core就是文件夹的名称,这里也可以不用写这个,如果这里不指定core,那么在代码中使用的时候,就需要指定core。
#host: http://127.0.0.1:8983/solr/core
#代码中可以指定core的地方有注释可以看
host: http://127.0.0.1:8983/solr
PropertyNullToStrUtil.java
解决:对象属性值为 null的值转为 空字符串"" 的工具类
package com.dist.util;
import net.sf.json.JSONNull;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Iterator;
/** 对象属性值为 null的值转为 空字符串""
* @author zhengja@dist.com.cn
* @data 2019/8/20 13:59
*/
public class PropertyNullToStrUtil {
/**
* 将json对象中包含的null和JSONNull属性修改成""
*
* @param jsonObj
*/
public static JSONObject filterNull(JSONObject jsonObj) {
Iterator<String> it = jsonObj.keys();
Object obj = null;
String key = null;
while (it.hasNext()) {
key = it.next();
obj = jsonObj.get(key);
if (obj instanceof JSONObject) {
filterNull((JSONObject) obj);
}
if (obj instanceof JSONArray) {
JSONArray objArr = (JSONArray) obj;
for (int i = 0; i < objArr.length(); i++) {
filterNull(objArr.getJSONObject(i));
}
}
if (obj == null || obj instanceof JSONNull) {
jsonObj.put(key, "");
}
if (obj.equals(null)) {
jsonObj.put(key, "");
}
}
return jsonObj;
}
}
UserEntityDto.java @Field()对应core字段
package com.dist.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.apache.solr.client.solrj.beans.Field;
import java.io.Serializable;
import java.util.Date;
/** class 类中的字段上,solr的core中没有使用 @Field,那么该部分字段值,不会存储到solr数据库中
* @program: springbootdemo
* @Date: 2018/12/26 10:03
* @Author: Mr.Zheng
* @Description:
*/
@ApiModel(value = "测试dto")
@Data
public class UserEntityDto implements Serializable {
@ApiModelProperty(value = "id",required = true)
@Field("id")
private Long id;
@ApiModelProperty(value = "guid")
private String guid;
@ApiModelProperty(value = "name")
@Field("name")
private String name;
@ApiModelProperty(value = "age")
@Field("age")
private String age;
@ApiModelProperty(value = "createTime")
private Date createTime;
@ApiModelProperty(value = "lastUpdateTime")
private Date lastUpdateTime;
}
UserEntity.java @Field()对应corename字段
package com.dist.entity;
import lombok.Data;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.stereotype.Component;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
/**
* @program: springbootdemo
* @Date: 2018/12/26 10:03
* @Author: Mr.Zheng
* @Description:
*/
@Entity(name = "UserEntity")
@Component
@Table(name="t_user")
@Data
public class UserEntity implements Serializable {
@Id
@GeneratedValue
@Column(name = "ID",nullable = true)
@Field("id")
private Long id;
@Column(name="GUID")
private String guid;
@Column(name = "NAME",nullable = true,length = 50)
@Field("user_name")
private String name;
@Column(name = "AGE",nullable = true,length = 50)
@Field("user_age")
private String age;
@Column(name = "CREATETIME",nullable = true)
private Date createTime;
@Column(name = "LASTUPDATETIME",nullable = true)
@Field("user_lastUpdateTime")
private Date lastUpdateTime;
@Override
public String toString() {
return "UserEntity{" +
"id=" + id +
", guid='" + guid + '\'' +
", name='" + name + '\'' +
", age='" + age + '\'' +
", createTime=" + createTime +
", lastUpdateTime=" + lastUpdateTime +
'}';
}
}
1、SolrClient
说明:测试用到了两个库,分别是core和coername库,
创建来源:Solr 安装篇-创建core库:创建core库方式一(推荐)corename、创建core库方式二:cor 得到的。
SolrClientController.java
package com.dist.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.dist.entity.UserEntity;
import com.dist.service.UserService;
import com.dist.util.PropertyNullToStrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**全文检索 Solr SolrClient
* @author zhengja@dist.com.cn
* @data 2019/8/20 15:43
*/
//@EnableScheduling //开启定时任务,项目启动自动执行定时任务
@RequestMapping(value = "rest/solr/v1")
@RestController
@Api(tags = {"SolrClientController"},description = "Solr 全文检索 SolrClient")
public class SolrClientController {
//方式一
@Autowired
private SolrClient client;
//数据库获取数据接口-对应实体类:UserEntity
@Autowired
private UserService userService;
@ApiOperation(value = "core库-添加文档内容-方式一",notes = "向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义",httpMethod = "GET")
@RequestMapping(value = "core/insert",method = RequestMethod.GET)
public Object validator(@ApiParam(value = "name") @RequestParam String name,
@ApiParam(value = "age") @RequestParam String age,
@ApiParam(value = "默 core 库" ,defaultValue = "core") @RequestParam String collection){
try {
String idStr = String.valueOf(System.currentTimeMillis());
SolrInputDocument document = new SolrInputDocument();
document.setField("id", idStr);
document.setField("name", name);
document.setField("age",age);
//1.可以用addBean 添加对象写入索引库-(推荐使用)-不存在null指针异常
/*UserEntityDto userEntityDto = new UserEntityDto();
userEntityDto.setId(10L);
userEntityDto.setName("2"+name);
userEntityDto.setCreateTime(new Date());
client.addBean(collection,userEntityDto);*/
//2.也可以把文档对象写入索引库
client.add(collection,document);//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称,比如client.add("core", doc);
client.commit(collection);//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称client.commit("core");
return idStr;
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
/**怎么保证是修改还是新增呢?
* 这里主要是根据id来判断,这个id类似db中的唯一主键,当我们没有指定id时,会随机生成一个id
*如果存在相同的id,则修改文档;如果不存在,则新增文档
*/
@ApiOperation(value = "core库-更新文档-方式一",notes = "更新文档内容,跟添加的区别是:id不能变,其他的可以变",httpMethod = "GET")
@RequestMapping(value = "core/updateDocument",method = RequestMethod.GET)
public Object updateDocument(@ApiParam(value = "idStr") @RequestParam String idStr,
@ApiParam(value = "name") @RequestParam String name,
@ApiParam(value = "age") @RequestParam String age,
@ApiParam(value = "sex2") @RequestParam String sex2,
@ApiParam(value = "默 core 库" ,defaultValue = "core") @RequestParam String collection) throws Exception{
// 创建一个文档对象, 向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义
SolrInputDocument document = new SolrInputDocument();
document.setField("id", idStr);
document.setField("name", name);
document.setField("age",age);
document.setField("sex2",sex2);
// 把文档对象写入索引库
client.add(collection,document);
// 提交
client.commit(collection);
return document;
}
@ApiOperation(value = "查询文档内容-方式一",notes = "复杂查询",httpMethod = "GET")
@RequestMapping(value = "queryDocument",method = RequestMethod.GET)
public Object queryDocument(@ApiParam(value = "条件",defaultValue = "*:*") @RequestParam String condition,
@ApiParam(value = "core/默 corename 库",defaultValue = "corename") @RequestParam String collection,
@ApiParam(value = "分页起始 默 0",defaultValue = "0") @RequestParam Integer pageStart,
@ApiParam(value = "分页结束 默 10",defaultValue = "10") @RequestParam Integer pageEnd) throws Exception {
// 创建一个查询条件
SolrQuery solrQuery = new SolrQuery();
// 设置查询条件
solrQuery.setQuery(condition);
// 设置分页
solrQuery.setStart(pageStart);
solrQuery.setRows(pageEnd);
//排序
solrQuery.setSort("id",SolrQuery.ORDER.asc);
/*// df 代表默认的查询字段
solrQuery.set("name", "关键字");
// 指的是你查询完毕之后要返回的字段
solrQuery.set("name", "id,name");
//高亮
//打开开关
solrQuery.setHighlight(false);
solrQuery.addHighlightField("name"); // 高亮字段
//设置前缀
solrQuery.setHighlightSimplePre("<font color=\"red\">");
//设置后缀
solrQuery.setHighlightSimplePost("</font>");*/
// 执行查询
QueryResponse query = client.query(collection,solrQuery);
// 取查询结果
SolrDocumentList solrDocumentList = query.getResults();
System.out.println("总记录数:" + solrDocumentList.getNumFound());
client.commit(collection);
return solrDocumentList;
}
@ApiOperation(value = "根据id删除文档--方式一",notes = "根据id删除单个文档",httpMethod = "DELETE")
@RequestMapping(value = "deteleDocument",method = RequestMethod.DELETE)
public Object deteleDocument(@ApiParam(value = "core/默 corename 库" ,defaultValue = "corename") @RequestParam String collection,
@ApiParam(value = "idStr") @RequestParam String idStr) throws Exception {
// 根据条件删除
// httpSolrServer.deleteByQuery("");
// 根据id删除
UpdateResponse response = client.deleteById(collection, idStr);
// 提交
client.commit(collection);
return response;
}
@ApiOperation(value = "根据条件删除文档-方式一",notes = "默认删除所有文档",httpMethod = "DELETE")
@RequestMapping(value = "deteleAllDocument",method = RequestMethod.DELETE)
public Object deteleAllDocument(@ApiParam(value = "core/默 corename 库" ,defaultValue = "corename") @RequestParam String collection,
@ApiParam(value = "条件",defaultValue = "*:*") @RequestParam String condition) throws Exception {
// 根据条件删除
// httpSolrServer.deleteByQuery("");
// 删除所有文档
UpdateResponse response = client.deleteByQuery(collection,condition);
// 提交
client.commit(collection);
return "删除所有文档-成功!";
}
@ApiOperation(value = "corename库-添加文档内容-方式一",notes = "向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义",httpMethod = "GET")
@RequestMapping(value = "corename/insert",method = RequestMethod.GET)
public Object validator2(@ApiParam(value = "数据库数据id") @RequestParam Long id,
@ApiParam(value = "默 corename 库" ,defaultValue = "corename") @RequestParam String collection) throws IOException, SolrServerException {
Optional<UserEntity> userEntity = this.userService.getUserById(id);
UserEntity user = userEntity.get();
//方式一(推荐使用):把数据对象写入索引库 -不存在null指针异常
//client.addBean(collection,user);
System.out.println("user "+user);
//方式二:把文档对象写入索引库
SolrInputDocument document = new SolrInputDocument();
//原始添加方式:这种方式也可以,不过类属性字段,不能有null值存在,如 age=null,出错:null指针异常
/*document.addField("user_id",user.getId().toString());
document.addField("user_age",user.getAge().toString());
document.addField("user_lastUpdateTime",new SimpleDateFormat("yyyy-MM-dd HH:MM:SS").format(new Date()));
document.addField("user_name",user.getName().toString());*/
//解决属性值 null 指针异常
//把 类 中所有属性为 null 的转为 ""
String str = JSON.toJSONString(user,SerializerFeature.WriteMapNullValue);
//json对象转string
JSONObject object = new JSONObject(str);
JSONObject jsonObject = PropertyNullToStrUtil.filterNull(object);
System.out.println("jsonObject"+jsonObject);
document.addField("id",jsonObject.get("id"));
document.addField("user_age",jsonObject.get("age"));
document.addField("user_lastUpdateTime",new SimpleDateFormat("yyyy-MM-dd HH:MM:SS").format(new Date()));
document.addField("user_name",jsonObject.get("name"));
//方式二:把文档对象写入索引库
client.add(collection,document);//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称,比如client.add("corename", doc);
client.commit(collection);//如果配置文件中没有指定core,这个方法的第一个参数就需要指定core名称client.commit("core");
return document;
}
@ApiOperation(value = "corename库-更新文档内容-方式一",notes = "更新文档内容,跟添加的区别是:id不能变,其他的可以变",httpMethod = "GET")
@RequestMapping(value = "corename/updateDocument",method = RequestMethod.GET)
public Object updateDocument2(@ApiParam(value = "数据库数据id") @RequestParam Long id,
@ApiParam(value = "Solr数据库id") @RequestParam String solrid,
@ApiParam(value = "默 corename 库" ,defaultValue = "corename") @RequestParam String collection) throws Exception{
Optional<UserEntity> userEntity = this.userService.getUserById(id);
UserEntity user = userEntity.get();
// 创建一个文档对象, 向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义
SolrInputDocument document = new SolrInputDocument();
//把 类 中所有属性为 null 的转为 ""
String str = JSON.toJSONString(user,SerializerFeature.WriteMapNullValue);
//json对象转string
JSONObject object = new JSONObject(str);
JSONObject jsonObject = PropertyNullToStrUtil.filterNull(object);
//System.out.println("jsonObject"+jsonObject);
document.addField("id",jsonObject.get("id"));
document.addField("user_age",jsonObject.get("age"));
document.addField("user_lastUpdateTime",jsonObject.get("lastUpdateTime"));
document.addField("user_name",jsonObject.get("name"));
// 把文档对象写入索引库
client.add(collection,document);
// 提交
client.commit(collection);
return document;
}
@ApiOperation(value = "corename库-将数据库的数据导入solr索引库-方式一",notes = "将数据库的数据导入solr索引库",httpMethod = "GET")
@RequestMapping(value = "dataToSolr",method = RequestMethod.GET)
public void dataToSolr(@ApiParam(value = "默 corename 库" ,defaultValue = "corename") @RequestParam String collection) throws Exception {
//先去数据库查数据
List<UserEntity> userList = this.userService.getUserList();
//循环遍历查询
for (UserEntity user : userList){
SolrInputDocument document = new SolrInputDocument();
//创建文档对象
//添加域
//System.out.println("user= "+user);
//把 类 中所有属性为 null 的转为 ""
String str = JSON.toJSONString(user,SerializerFeature.WriteMapNullValue);
//json对象转string
JSONObject object = new JSONObject(str);
JSONObject jsonObject = PropertyNullToStrUtil.filterNull(object);
//System.out.println("jsonObject"+jsonObject);
document.addField("id",jsonObject.get("id"));
document.addField("user_age",jsonObject.get("age"));
document.addField("user_lastUpdateTime",jsonObject.get("lastUpdateTime"));
document.addField("user_name",jsonObject.get("name"));
//写入
System.out.println("document="+document);
client.add(collection,document);
}
//提交
client.commit(collection);
System.out.println("成功保存数据到corename库:"+userList);
}
/**需要在类上 加开启定时任务注解 @EnableScheduling
* 定时器 - 全量更新 -成功
* cron代表的是时间 如下代表(每隔2分钟执行一次)
* @throws Exception
*/
@Scheduled(cron = "0 */2 * * * ?")
public void timer() throws Exception {
//获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//输出当前时间
System.out.println("当前时间为:" +
localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.out.println("============测试一============");
//调用删除索引的方法
deteleAllDocument("corename","*:*");
Thread.sleep(5000);
//调用数据新增到索引库的方法
dataToSolr("corename");
}
}
2.SolrTemplate
说明:测试用到了两个库,分别是core和coername库,
创建来源:Solr 安装篇-创建core库:创建core库方式一(推荐)corename、创建core库方式二:cor 得到的。
package com.dist.config;
import org.apache.solr.client.solrj.SolrClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.solr.core.SolrTemplate;
/** solr 全文检索自动配置 ==自动装配
* @author zhengja@dist.com.cn
* @data 2019/8/20 15:36
*/
@Configuration
public class SearchAutoConfig {
@Bean
@ConditionalOnMissingBean(SolrTemplate.class)
public SolrTemplate solrTemplate(SolrClient solrClient) {
return new SolrTemplate(solrClient);
}
}
SolrTemplateController.java
package com.dist.controller;
import com.dist.entity.UserEntity;
import com.dist.entity.UserEntityDto;
import com.dist.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.solr.core.SolrTemplate;
import org.springframework.data.solr.core.query.Query;
import org.springframework.data.solr.core.query.SimpleQuery;
import org.springframework.data.solr.core.query.result.ScoredPage;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**全文检索 Solr
* @author zhengja@dist.com.cn
* @data 2019/8/20 15:43
*/
//@EnableScheduling //开启定时任务,项目启动自动执行定时任务
@RequestMapping(value = "rest/solr/v2")
@RestController
@Api(tags = {"SolrTemplateController"},description = "Solr 全文检索 SolrTemplate")
public class SolrTemplateController {
//方式二:自动装配
@Autowired
private SolrTemplate solrTemplate;
//数据库获取数据接口-对应实体类:UserEntity
@Autowired
private UserService userService;
@ApiOperation(value = "core库-添加文档内容-方式二",notes = "向文档中添加域,必须有id域,域的名称必须在scheme.xml中定义",httpMethod = "POST")
@RequestMapping(value = "v2/core/insert",method = RequestMethod.POST)
public Object validator2(@ApiParam(value = "具体参考:Model") @RequestBody UserEntityDto userEntityDto,
@ApiParam(value = "默 core 库" ,defaultValue = "core") @RequestParam String collection){
try {
UpdateResponse response = this.solrTemplate.saveBean(collection, userEntityDto);
solrTemplate.commit(collection);
return response;
} catch (Exception e) {
e.printStackTrace();
}
return "error";
}
@ApiOperation(value = "core库-更新文档-方式二",notes = "更新文档内容,跟添加的区别是:id不能变,其他的可以变",httpMethod = "PUT")
@RequestMapping(value = "v2/core/updateDocument",method = RequestMethod.PUT)
public Object updateDocument2(@ApiParam(value = "具体参考:Model") @RequestBody UserEntityDto userEntityDto,
@ApiParam(value = "默 core 库" ,defaultValue = "core") @RequestParam String collection) throws Exception{
UpdateResponse updateResponse = this.solrTemplate.saveBean(collection, userEntityDto);
this.solrTemplate.commit(collection);
return updateResponse;
}
@ApiOperation(value = "core库-批量更新文档-方式二",notes = "批量更新文档",httpMethod = "GET")
@RequestMapping(value = "v3/core/updateDocument",method = RequestMethod.GET)
public Object updateDocument3(@ApiParam(value = "默 core 库" ,defaultValue = "core") @RequestParam String collection){
UserEntityDto document = new UserEntityDto();
document.setId(1L);
document.setAge("20");
document.setGuid("123");
//少name字段
UserEntityDto document2 = new UserEntityDto();
document2.setId(2L);
document2.setAge("21");
document2.setName("List2");
document2.setGuid("1234"); //多guid字段
UserEntityDto document3 = new UserEntityDto();
document3.setId(3L);
document3.setAge("22");
document3.setName("List3");
//正常字段
UpdateResponse response = solrTemplate.saveBeans(collection, Arrays.asList(document, document2,document3));
solrTemplate.commit(collection);
return response;
}
@ApiOperation(value = "查询文档内容-方式二",notes = "复杂(高级)查询",httpMethod = "GET")
@RequestMapping(value = "v2/queryDocument",method = RequestMethod.GET)
public Object queryDocument2(@ApiParam(value = "条件",defaultValue = "*:*") @RequestParam String condition,
@ApiParam(value = "corename/默 core 库",defaultValue = "core") @RequestParam String collection,
@ApiParam(value = "分页起始 默 0",defaultValue = "0") @RequestParam Long pageStart,
@ApiParam(value = "分页结束 默 10",defaultValue = "10") @RequestParam Integer pageEnd) throws Exception {
Query query=new SimpleQuery(condition);
query.setOffset(pageStart); //开始索引(默认0)start:(page-1)*rows
query.setRows(pageEnd); //每页记录数(默认10)//rows:rows
if (collection.equals("core")){
ScoredPage<UserEntityDto> userEntityDtos = this.solrTemplate.queryForPage(collection, query, UserEntityDto.class);
this.solrTemplate.commit(collection);
return userEntityDtos.iterator();
}else {
ScoredPage<UserEntity> userEntities = this.solrTemplate.queryForPage(collection, query, UserEntity.class);
this.solrTemplate.commit(collection);
return userEntities.iterator();
}
}
@ApiOperation(value = "根据id查询文档内容-方式二",notes = "根据id查询文档内容",httpMethod = "GET")
@RequestMapping(value = "v3/queryDocument",method = RequestMethod.GET)
public Object queryDocument3(@ApiParam(value = "条件id") @RequestParam String id,
@ApiParam(value = "corename/默 core 库",defaultValue = "core") @RequestParam String collection){
if (collection.equals("core")){
Optional<UserEntityDto> userEntityDto = this.solrTemplate.getById(collection, id, UserEntityDto.class);
System.out.println("userEntityDto "+userEntityDto);
this.solrTemplate.commit(collection);
return userEntityDto.get();
}else {
Optional<UserEntity> userEntity = this.solrTemplate.getById(collection, id, UserEntity.class);
System.out.println("userEntity "+userEntity);
this.solrTemplate.commit(collection);
return userEntity.get();
}
}
@ApiOperation(value = "corename库-将数据库的数据导入solr索引库-方式二",notes = "将数据库的数据导入solr索引库",httpMethod = "GET")
@RequestMapping(value = "v2/dataToSolr",method = RequestMethod.GET)
public Object dataToSolr2(@ApiParam(value = "默 corename 库" ,defaultValue = "corename") @RequestParam String collection) throws Exception {
//先去数据库查数据
List<UserEntity> userList = this.userService.getUserList();
//同时,解决了属性值 null 报错的问题
UpdateResponse updateResponse = this.solrTemplate.saveBeans(collection, userList);
System.out.println("成功保存数据到corename库:"+userList);
this.solrTemplate.commit(collection);
return updateResponse;
}
@ApiOperation(value = "corename库-增量/默认全量更新-数据库-方式二",notes = "java操作Solr的全量或增量更新,可以结合定时任务做定时全量或增量更新",httpMethod = "GET")
@RequestMapping(value = "updateSolrData",method = RequestMethod.GET)
public Object updateSolrData(@ApiParam(value = "默 corename 库",defaultValue = "corename") @RequestParam String collection,
@ApiParam(value = "默 全量更新",defaultValue = "true") @RequestParam String is) throws Exception {
//获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//输出当前时间
System.out.println("当前时间为:" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
if (is.equals("true")){
//调用删除索引的方法,实现全量更新-不加的,多次调用就是增量更新
deteleAllDocument2(collection,"*:*");
System.out.println("============测试全量更新============");
}else {
System.out.println("============测试增量更新============");
}
//调用数据新增到索引库的方法二
Object toSolr2 = dataToSolr2(collection);
return toSolr2;
}
@ApiOperation(value = "根据条件删除文档",notes = "默认删除所有文档",httpMethod = "DELETE")
@RequestMapping(value = "v2/deteleAllDocument",method = RequestMethod.DELETE)
public Object deteleAllDocument2(@ApiParam(value = "core/默 corename 库" ,defaultValue = "corename") @RequestParam String collection,
@ApiParam(value = "条件",defaultValue = "*:*") @RequestParam String condition) throws Exception {
// 根据条件删除
// httpSolrServer.deleteByQuery("");
Query query=new SimpleQuery(condition);
// 删除所有文档
UpdateResponse response = this.solrTemplate.delete(collection,query);
// 提交
this.solrTemplate.commit(collection);
return "删除文档-成功!";
}
/**
* 需要在类上 加开启定时任务注解 @EnableScheduling
* 全量更新 -成功
* @throws Exception
*/
@Scheduled(cron = "0 */1 * * * ?")
public void timer2() throws Exception {
//获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//输出当前时间
System.out.println("当前时间为:" +
localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
System.out.println("============测试二============");
//调用删除索引的方法
deteleAllDocument2("corename","*:*");
Thread.sleep(5000);
//调用数据新增到索引库的方法二
dataToSolr2("corename");
}
}
3、Solr加用户后密码的配置
具体配置用户验证参考:[Solr 配置用户登录验证.md](Solr 配置用户登录验证.md)
springboot通过solr地址中加入用户名密码的方式连接,地址如下:
*.yml文件
spring:
data:
solr: # 全文检索
# solr加上了用户名密码访问条件,参数中并没有地方设置username和password,那应该怎么办?
host: http://user:pass@127.0.0.1:8983/solr