Springboot Solr 配置和使用

作者: 宇宙小神特别萌 | 来源:发表于2019-08-23 14:26 被阅读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
    

    相关文章

      网友评论

        本文标题:Springboot Solr 配置和使用

        本文链接:https://www.haomeiwen.com/subject/bnttectx.html