spring bootElasticsearch Solr 全文搜索

Springboot Solr 配置和使用

2019-08-23  本文已影响0人  宇宙小神特别萌

目录

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
上一篇下一篇

猜你喜欢

热点阅读