Solr 4.10.3 客户端 SolrJ 进行 查询检索 操作

本文导读

基本检索

package com.wmx.utils;

import com.wmx.domain.News;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created by Administrator on 2018/9/7 0007.
 * Solr 检索工具类
 */
public class SolrSearchUtils {

  /**
     * 查询文档
     * 1)*:* 表示查询所有,但是如同 Solr 后台管理界面操作一样,它默认只会最多返回10条数据
     *
     * @param fieldName  :域名
     * @param fieldValue :检索的关键字
     */
    public static List<News> searchDocs(String fieldName, String fieldValue) {
        List<News> newses = new ArrayList<News>();
        SolrServer solrServer = null;
        try {
            if (fieldName == null || "".equals(fieldName) || fieldValue == null || "".equals(fieldValue)) {
                return newses;
            }
            /** 连接 solr 服务端
             * HttpSolrServer(String baseURL)
             * 1)baseURL:为 Solr 服务端地址,如 http://localhost:8983/solr/SolrCore
             * 2)末尾的 SolrCore 未指定时,默认为 collection1
             * 3)HttpSolrServer 继承于 org.apache.solr.client.solrj.impl.CloudSolrServer
             */
            solrServer = new HttpSolrServer("http://localhost:8080/solr/collection1");
            /**创建 query 查询对象
             * SolrQuery():先创建对象,后设置查询条件
             * SolrQuery(String q):创建对象的同时设置查询条件
             * SolrQuery 继承于 org.apache.solr.common.params.SolrParams*/
            SolrQuery query = new SolrQuery();

            /**设置查询条件
             * 格式:域名:关键字
             * */
            query.setQuery(fieldName + ":" + fieldValue);
            /**执行查询,返回查询结果*/
            QueryResponse queryResponse = solrServer.query(query);

            /**取查询结果
             * 当无结果时,SolrDocumentList 大小为0 ,不会为 null */
            SolrDocumentList solrDocumentList = queryResponse.getResults();

            System.out.println("Solr 查询文档总数:" + solrDocumentList.getNumFound());

            /** 遍历查询的结果*/
            for (SolrDocument solrDocument : solrDocumentList) {
                News news = new News();
                /**因为 Solr 的主键域 id 是 String 类型,而 POJO 中是 Integer 类型,所以要转换*/
                String id = (String) solrDocument.get("id");
                news.setId(Integer.parseInt(id));
                news.setReadNumber((Long) solrDocument.get("news_readNumber"));
                news.setPublishTime((Date) solrDocument.get("new_publishTime"));
                news.setOriginUrl((String) solrDocument.get("news_originUrl"));
                news.setContent((String) solrDocument.get("news_content"));
                news.setOriginName((String) solrDocument.get("news_originName"));
                news.setTitle((String) solrDocument.get("news_title"));
                newses.add(news);
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } finally {
            /**关闭连接,是否资源*/
            if (solrServer != null) {
                solrServer.shutdown();
            }
        }
        return newses;
    }

    public static void main(String[] args) {
        /**
         * "*:*":检索所有文档——默认是前10条数据
         * "news_text:中国":检索 文章 标题、正文内容、来源网站名称 中含有关键字 "中国" 的文档
         */
        List<News> newses = searchDocs("news_text", "中国");
        for (int i = 0; i < newses.size(); i++) {
            System.out.println("-------------" + (i + 1) + "--------------");
            System.out.println(newses.get(i));
        }
    }
}

控制台输出如下:

Solr 查询文档总数:2
-------------1--------------
News{content='新华社北京9月7日电(记者胡喆)记者从国家国防科技工业局、自然资源部获悉....', id=1004, title='中国成功发射海洋一号C卫星', publishTime=Fri Sep 07 17:10:52 CST 2018, originName='腾讯新闻', originUrl='https://new.qq.com/omn/20180907/20180907A0PQ83.html', readNumber=6765}
-------------2--------------
News{content='一场过境日本的台风,让国人再次体会到祖国“给力救援”同时,也“吹乱”了台湾绿媒的心思...', id=1005, title='觉得自己是中国人就能上车', publishTime=Fri Sep 07 17:11:28 CST 2018, originName='腾讯新闻', originUrl='https://new.qq.com/omn/20180907/20180907A0F82U.html', readNumber=6765}

Process finished with exit code 0

多条件检索

  • 多条件指的就是 Solr 自己后台管理界面中的这些条件,Solr 自己同样使用的 SolrJ 客户端进行编码检索
  • 程序员自己只需要将这些操作转为代码即可,正式编码之前,先熟悉一下理论只是,同时也可以参考《Solr 4.10.3 后台管理页面查询详解

  • 如下所示:高亮的结果与 response 的查询结果是分开的,所以要分开取值
  • hl.fl 用于设置高亮显示域,可以同时设置多个,但是不要用复制域,多个时空格隔开
  • 即使高亮结果为空,也会与 response 的 主键域 id 进行一一对应,这样的好处是后台 SolrJ 根据 response 取值时顺便就能根据主键域 id 获取 高亮的结果,而且高亮的结果只是大小为0,并不会出现空指针异常!

  • 后台 SolrJ 获取高亮结果时使用的是 
  1. Map<String, Map<String, List<String>>>   highlighting =queryResponse.getHighlighting()
  • 上面返回的值就是 Solr 管理页面如下所示返回的值的结构。

 "highlighting": {
    "1001": {
      "news_title": [
        "“<em>一带</em><em>一路</em>”再出发,习近平的这些提法意味深远"
      ],
      "news_content": [
        "今年是“<em>一带</em><em>一路</em>”倡议提出五周年。五年前的今天(2013年9月7日),习近平主席出访哈萨克斯坦...."
      ]
    },
    "1004": {
      "news_title": [
        "中国成功发射海洋<em>一</em>号C卫星"
      ]
    },
    "1005": {
      "news_content": [
        "<em>一</em>场过境日本的台风,让国人再次体会到祖国“给力救援”同时,也“吹乱”了台湾绿媒的心思..."
      ]
    },
    "1007": {
      "news_content": [
        "日前,记者应聘到石家庄<em>一</em>家知名烤肉海鲜自助餐厅上班,第<em>一</em>天记者就被惊到了。..."
      ]
    }
  }

package com.wmx.utils;

import com.wmx.domain.News;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Created by Administrator on 2018/9/7 0007.
 * Solr 检索工具类
 */
public class SolrSearchUtils {
 /**
     * 多条件检索,包括:查询、过滤、分页、排序、高亮显示 等处理
     *
     * @param fieldName      :检索的域,为空或者为null时,默认为 复制域 news_text
     * @param keyword        :检索的关键字,必须存在
     * @param orderFieldName :排序字段,为空或者为 null 时,不排序
     * @param pageNumber     :检索的页数,如 1 表示第一页,3 表示第三页数据,默认每页20条数据
     * @param isHighlight    :是否进行高亮显示,true 为 是,false 则不进行高亮
     * @return
     */
    public static List<News> searchDocsByTerm(String fieldName, String keyword, String orderFieldName,
                                              Integer pageNumber, Boolean isHighlight) {
        List<News> newses = new ArrayList<News>();
        SolrServer solrServer = null;
        try {
            if (keyword == null || "".equals(keyword)) {
                return newses;
            }
            /** 连接 solr 服务端
             * HttpSolrServer(String baseURL)
             * 1)baseURL:为 Solr 服务端地址,如 http://localhost:8983/solr/SolrCore
             * 2)末尾的 SolrCore 未指定时,默认为 collection1
             * 3)HttpSolrServer 继承于 org.apache.solr.client.solrj.impl.CloudSolrServer
             * 4)实际项目中应该将 Solr 服务端地址配置在资源文件中,然后进行获取,不能写死在代码中
             */
            solrServer = new HttpSolrServer("http://localhost:8080/solr");
            /**创建 query 查询对象
             * SolrQuery():先创建对象,后设置查询条件
             * SolrQuery(String q):创建对象的同时设置查询条件
             * SolrQuery 继承于 org.apache.solr.common.params.SolrParams*/
            SolrQuery query = new SolrQuery();

            /**设置查询条件,格式:域名:关键字 */
            if (fieldName == null || "".equals(fieldName)) {
                /**
                 * 1)如果用户没有提供检索的域,则默认检索 news_text 域
                 * 2)news_text 是复制域,等同于同时检索 新闻标题、正文内容、来源网站名称
                 * 3)设置了默认检索域时,q 参数可以不用再设置 域名
                 * */
                query.set("df", "news_text");
                query.setQuery(keyword);
            } else {
                query.setQuery(fieldName + ":" + keyword);
            }

            /**
             * 设置过滤条件,类似求交集----------实际中根据应用需要动态进行设置,这里为了演示方便,直接写死在方法中了
             * 1)setFilterQueries(String ... fq):可以同时设置多个过滤条件
             * 2)addFilterQuery(String ... fq):可以同时设置多个过滤条件,两个方法效果一致
             * 3)如:query.setFilterQueries("id:[1000 TO 1500]") 、query.addFilterQuery("id:[1000 TO 1500]")
             *  都是表示 过滤 结果中 id 在 [1000,1500] 的文档
             */
            query.setFilterQueries("id:[1000 TO 1004]");

            /** 设置排序条件
             * setSort(String field, ORDER order)
             * field:排序的域
             * SolrQuery.ORDER.asc:表示从小到大的升序
             * SolrQuery.ORDER.desc:表示从大到小的降序
             */
            if (orderFieldName != null && !"".equals(orderFieldName)) {
                query.setSort(orderFieldName, SolrQuery.ORDER.asc);
            }

            /** 分页处理,假设每页显示 20 条 数据
             */
            pageNumber = pageNumber <= 0 ? 1 : pageNumber;
            query.setStart((pageNumber - 1) * 20);
            query.setRows(20);

            /** 设置结果集中显示的 域*/
            query.setFields("id", "news_content", "news_title", "new_publishTime", "news_originName", "news_originUrl");

            /**设置是否高亮显示
             * */
            if (isHighlight) {
                query.setHighlight(true);
                /**设置高亮显示的域,不能使用复制域,必须指定具体域
                 *可以指定多个域,这里以 文章标题 与 正文内容 为例
                 * */
                query.addHighlightField("news_title").addHighlightField("news_content");

                /**高亮显示的前缀 标签---根据应用需要自己设置标签与样式*/
                query.setHighlightSimplePre("<span style='color:red'>");
                /**高亮显示的后缀 标签*/
                query.setHighlightSimplePost("</span>");
            }

            /**执行查询,返回查询结果*/
            QueryResponse queryResponse = solrServer.query(query);

            /**获取查询结果
             * 当无结果时,SolrDocumentList 大小为0 ,不会为 null */
            SolrDocumentList solrDocumentList = queryResponse.getResults();

            /**获取高亮的结果,正常结果 与 高亮结果 是分开的,而且其中的规则也不一样,所以需要分开获取
             * Map<String, Map<String, List<String>>>
             * 1)外围 Map 的 Key 是 文档的主键域 id 的值
             * 2)外围 Map 的 value 子 Map 存放的是多个 域及其对应的内容
             * 3)子 Map 的 Key 是域名,当对多个域需要高亮显示时,此时子Map 可能就有多个值
             * 4)子 Map 的 Value 是 域 对应的加了 前后缀 的内容
             *
             * 5)外层 Map 的 key 主键域 id 永远存在,它的 value 即 子 Map 大小可能为0,但不会为 null
             * 6)即 外围 Map 与 子 Map 都不会为 null,不用担心 空指针异常
             * */
            Map<String, Map<String, List<String>>> highlighting = null;
            if (isHighlight) {
                highlighting = queryResponse.getHighlighting();
            }

            System.out.println("Solr 检索文档总数 >>> " + solrDocumentList.getNumFound());

            /**遍历查询结果*/
            for (SolrDocument solrDocument : solrDocumentList) {

                /**1)当需要高亮显示时,则 获取 文章标题 与 正文内容的高亮显示内容
                 * 有高亮结果时,则取高亮结果,否则就取正常的结果
                 * 注意从 Solr 后台管理页面也知道,高亮的结果与正常返回的结果是分开的
                 * */
                String news_title;
                String news_content;
                if (isHighlight) {
                    List<String> news_titleList = highlighting.get(solrDocument.get("id")).get("news_title");
                    if (news_titleList != null && news_titleList.size() > 0) {
                        news_title = news_titleList.get(0);
                    } else {
                        news_title = (String) solrDocument.get("news_title");
                    }

                    List<String> news_contentList = highlighting.get(solrDocument.get("id")).get("news_content");
                    if (news_contentList != null && news_contentList.size() > 0) {
                        news_content = news_contentList.get(0);
                    } else {
                        news_content = (String) solrDocument.get("news_content");
                    }
                    /**当本次遍历处理完成之后,删除 highlighting 中的此元素,这样下次就更快了
                     * */
                    highlighting.remove(solrDocument.get("id"));
                } else {
                    news_title = (String) solrDocument.get("news_title");
                    news_content = (String) solrDocument.get("news_content");
                }

                News news = new News();
                /**因为 Solr 的主键域 id 是 String 类型,而 POJO 中是 Integer 类型,所以要转换*/
                String id = (String) solrDocument.get("id");
                news.setId(Integer.parseInt(id));
                news.setReadNumber((Long) solrDocument.get("news_readNumber"));
                news.setPublishTime((Date) solrDocument.get("new_publishTime"));
                news.setOriginUrl((String) solrDocument.get("news_originUrl"));
                news.setContent(news_content);
                news.setOriginName((String) solrDocument.get("news_originName"));
                news.setTitle(news_title);
                newses.add(news);
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } finally {
            /**关闭连接,释放资源*/
            if (solrServer != null) {
                solrServer.shutdown();
            }
        }
        return newses;
    }

    public static void main(String[] args) {
        /** null:使用默认检索域 news_text
         * "一带一路":检索 "一带一路" 关键字
         * null:使用默认排序
         * 1:检索第一页
         * true:使结果高亮*/
        List<News> newses = searchDocsByTerm(null, "一带一路", null, 1, true);
        for (int i = 0; i < newses.size(); i++) {
            System.out.println("-------------" + (i + 1) + "--------------");
            System.out.println(newses.get(i));
        }
    }
}

控制台输出结果如下:

Solr 检索文档总数 >>> 4
-------------1--------------
News{content='今年是“<span style='color:red'>一带</span><span style='color:red'>一路</span>”倡议提出五周年。五年前的今天(2013年9月7日),习近平主席出访哈萨克斯坦....', id=1001, title='“<span style='color:red'>一带</span><span style='color:red'>一路</span>”再出发,习近平的这些提法意味深远', publishTime=Fri Sep 07 17:07:17 CST 2018, originName='凤凰新闻', originUrl='http://news.ifeng.com/a/20180907/60034084_0.shtml', readNumber=null}
-------------2--------------
News{content='日前,记者应聘到石家庄<span style='color:red'>一</span>家知名烤肉海鲜自助餐厅上班,第<span style='color:red'>一</span>天记者就被惊到了。...', id=1007, title='记者卧底自助餐厅1月曝光如此内幕', publishTime=Fri Sep 07 17:20:10 CST 2018, originName='新浪新闻', originUrl='http://news.sina.com.cn/s/2018-09-07/doc-ihitesuz5705441.shtml', readNumber=null}
-------------3--------------
News{content='新华社北京9月7日电(记者胡喆)记者从国家国防科技工业局、自然资源部获悉....', id=1004, title='中国成功发射海洋<span style='color:red'>一</span>号C卫星', publishTime=Fri Sep 07 17:10:52 CST 2018, originName='腾讯新闻', originUrl='https://new.qq.com/omn/20180907/20180907A0PQ83.html', readNumber=null}
-------------4--------------
News{content='<span style='color:red'>一</span>场过境日本的台风,让国人再次体会到祖国“给力救援”同时,也“吹乱”了台湾绿媒的心思...', id=1005, title='觉得自己是中国人就能上车', publishTime=Fri Sep 07 17:11:28 CST 2018, originName='腾讯新闻', originUrl='https://new.qq.com/omn/20180907/20180907A0F82U.html', readNumber=null}

Process finished with exit code 0

检索拓展

时间检索

  • schema.xml 文件中日期的域类型为 Date ,如下所示。
  • Java 也有 java.util.Date 类型,对于添加 与取值时并没有影响,但是查询时却要特殊处理:
  1. 日期必须符合格式:1990-01-01T00:00:00.000Z
  2. Solr 会自动将在原来的时间上加上 8 小时,所以自己要提前减去。
 <field name="new_publishTime" type="date" indexed="true" stored="true"/>
  • 如 new_publishTime:[2018-09-07T09:00:00.000Z TO 2018-09-07T9:15:00.000Z],表示查询 2018年9月15点0分0秒  到 2018年9月15点15分0秒的数据,闭区间。
  • 下面代码中用到了 Apache 格式化日期的工具类,它们都来自 Apache 的 commons-lang3 包,没有的可以从 Apache 官网下载::
  1. org.apache.commons.lang3.time.DateUtils
  2. org.apache.commons.lang3.time.DateFormatUtils

  /**
     * 根据时间范围进行查询,闭区间,以时间倒序排列
     *
     * @param startDate 开始时间
     * @param endDate   结束时间
     * @return
     */
    public static List<News> searchDocsByTime(Date startDate, Date endDate) {
        List<News> newsList = new ArrayList<News>();
        SolrServer solrServer = null;
        try {
            String startDateStr;
            String endDateStr;

            if (startDate == null && endDate == null) {
                return newsList;
            } else {
                /**如果 Solr 的域类型用的是 date,则查询时,日期必须符合格式:1990-01-01T00:00:00.000Z
                 * 1)"日"与"时"中间用 "T"字符,结尾加上 ".000Z"
                 * 2)Solr 会自动将 时间加上 8小时,不过对于 date 类型的域,添加与取值不用特殊处理,查询的时候,必须自己减去8小时
                 * 3)new_publishTime:[2018-09-07T9:07:18.000Z TO 2018-09-07T9:09:00.000Z]
                 * 表示查询 2018年9月15点07分18秒  到 2018年9月15点09分0秒的数据,闭区间
                 * */
                startDate = DateUtils.addHours(startDate, -8);
                endDate = DateUtils.addHours(endDate, -8);
                startDateStr = DateFormatUtils.format(startDate, "yyyy-MM-dd HH:mm:ss");
                endDateStr = DateFormatUtils.format(endDate, "yyyy-MM-dd HH:mm:ss");

                startDateStr = startDateStr.replace(" ", "T") + ".000Z";
                endDateStr = endDateStr.replace(" ", "T") + ".000Z";
            }

            /** 连接 solr 服务端
             * HttpSolrServer(String baseURL)
             * 1)baseURL:为 Solr 服务端地址,如 http://localhost:8983/solr/SolrCore
             * 2)末尾的 SolrCore 未指定时,默认为 collection1
             * 3)HttpSolrServer 继承于 org.apache.solr.client.solrj.impl.CloudSolrServer
             * 4)实际项目中应该将 Solr 服务端地址配置在资源文件中,然后进行获取,不能写死在代码中
             */
            solrServer = new HttpSolrServer("http://localhost:8080/solr");

            /**创建 query 查询对象
             * SolrQuery():先创建对象,后设置查询条件
             * SolrQuery(String q):创建对象的同时设置查询条件
             * SolrQuery 继承于 org.apache.solr.common.params.SolrParams*/
            SolrQuery query = new SolrQuery();

            /**日期查询的格式:new_publishTime:
             * [2018-09-07T9:07:18.000Z TO 2018-09-07T9:09:00.000Z]
             * [2018-09-07T07:00:00.000Z TO 2018-09-07T07:25:00.000Z]
             * solr 会自动加上8小时,自己要提前减去8小时
             */
            String timeQueryStr = "[" + startDateStr + " TO " + endDateStr + "]";
            System.out.println("时间查询字符串 >>> " + timeQueryStr);
            query.setQuery("new_publishTime:" + timeQueryStr);
            query.setSort("new_publishTime", SolrQuery.ORDER.desc);

            /**执行查询,返回查询结果*/
            QueryResponse queryResponse = solrServer.query(query);

            /**取查询结果
             * 当无结果时,SolrDocumentList 大小为0 ,不会为 null */
            SolrDocumentList solrDocumentList = queryResponse.getResults();

            System.out.println("Solr 查询文档总数:" + solrDocumentList.getNumFound());

            /** 遍历查询的结果*/
            for (SolrDocument solrDocument : solrDocumentList) {
                News news = new News();
                /**因为 Solr 的主键域 id 是 String 类型,而 POJO 中是 Integer 类型,所以要转换*/
                String id = (String) solrDocument.get("id");
                news.setId(Integer.parseInt(id));
                news.setReadNumber((Long) solrDocument.get("news_readNumber"));
                news.setPublishTime((Date) solrDocument.get("new_publishTime"));
                news.setOriginUrl((String) solrDocument.get("news_originUrl"));
                news.setContent((String) solrDocument.get("news_content"));
                news.setOriginName((String) solrDocument.get("news_originName"));
                news.setTitle((String) solrDocument.get("news_title"));
                newsList.add(news);
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } finally {
            /**关闭连接,释放资源*/
            if (solrServer != null) {
                solrServer.shutdown();
            }
        }
        return newsList;
    }
    public static void main(String[] args) throws ParseException {
        /** 查询 [2018-09-07 17:00:00,2018-09-07 17:09:00]的数据
         * searchDocsByTime方法中会先减去8小时,所以 solr 再加上8小时后,查询的就是这个时间区域
         */
        Date startDate = DateUtils.parseDate("2018-09-07 17:00:00", "yyyy-MM-dd HH:mm:ss");
        Date endDate = DateUtils.parseDate("2018-09-07 17:09:00", "yyyy-MM-dd HH:mm:ss");
        List<News> newses = searchDocsByTime(startDate, endDate);
        for (int i = 0; i < newses.size(); i++) {
            System.out.println("-------------" + (i + 1) + "--------------");
            System.out.println(newses.get(i));
        }
    }

控制台输出:

时间查询字符串 >>> [2018-09-07T09:00:00.000Z TO 2018-09-07T09:09:00.000Z]
Solr 查询文档总数:2
-------------1--------------
News{content='党的十八大以来,以习近平同志为核心的党中央从关系党和国家前途命运的战略全局出发,从前所未有的....', id=1002, title='中共十八大以来全面依法治国新成就述评', publishTime=Fri Sep 07 17:08:11 CST 2018, originName='凤凰新闻', originUrl='http://news.ifeng.com/a/20180907/60033433_0.shtml', readNumber=8855}
-------------2--------------
News{content='今年是“一带一路”倡议提出五周年。五年前的今天(2013年9月7日),习近平主席出访哈萨克斯坦....', id=1001, title='“一带一路”再出发,习近平的这些提法意味深远', publishTime=Fri Sep 07 17:07:17 CST 2018, originName='凤凰新闻', originUrl='http://news.ifeng.com/a/20180907/60034084_0.shtml', readNumber=8888}

Process finished with exit code 0

  • 提示:对于日期,也可以在 Solr 中使用 Long 类型,而不使用 Date 类型,ava.util.Data 的 getTime() 方法返回的就是毫秒数。

特殊字符转义

  • Solr 查询时对于 +、-、&、|、(、)、{、}、[、]、^、"、~、*、?、:、/、\、以及 “空格” 等字符需要进行转义,否则查询会因为语法错误而报错
  • 如查询来源地址时:query.setQuery("news_originUrl:http\\://news.ifeng.com/a/20180907/60033433_0.shtml"); 地址中的冒号":"必须转义,否则显然语法是错误的
  • Solr 提供了一个专门转义的工具类方法:ClientUtils.escapeQueryChars(String s),如果检索的内容比较复杂,含有上述这些特殊符号,则必须进行转义
 /**
     * 根据新闻来源地址进行查询,显然地址必须要进行转义
     *
     * @param news_originUrl :新闻来源地址,如:http://news.ifeng.com/a/20180907/60033433_0.shtml
     * @return
     */
    public static List<News> searchSpecialCharacter(String news_originUrl) {
        List<News> newsList = new ArrayList<News>();
        SolrServer solrServer = null;
        try {
            if (StringUtils.isBlank(news_originUrl)) {
                return newsList;
            } else {
                /**对检索的地址进行转义*/
                news_originUrl = ClientUtils.escapeQueryChars(news_originUrl);
            }
            System.out.println("news_originUrl 转义后>>> " + news_originUrl);
            /** 连接 solr 服务端
             * HttpSolrServer(String baseURL)
             * 1)baseURL:为 Solr 服务端地址,如 http://localhost:8983/solr/SolrCore
             * 2)末尾的 SolrCore 未指定时,默认为 collection1
             * 3)HttpSolrServer 继承于 org.apache.solr.client.solrj.impl.CloudSolrServer
             * 4)实际项目中应该将 Solr 服务端地址配置在资源文件中,然后进行获取,不能写死在代码中
             */
            solrServer = new HttpSolrServer("http://localhost:8080/solr");

            /**创建 query 查询对象
             * SolrQuery():先创建对象,后设置查询条件
             * SolrQuery(String q):创建对象的同时设置查询条件
             * SolrQuery 继承于 org.apache.solr.common.params.SolrParams*/
            SolrQuery query = new SolrQuery();

            query.setQuery("news_originUrl:" + news_originUrl);
            query.setSort("new_publishTime", SolrQuery.ORDER.desc);

            /**执行查询,返回查询结果*/
            QueryResponse queryResponse = solrServer.query(query);

            /**取查询结果
             * 当无结果时,SolrDocumentList 大小为0 ,不会为 null */
            SolrDocumentList solrDocumentList = queryResponse.getResults();

            System.out.println("Solr 查询文档总数:" + solrDocumentList.getNumFound());

            /** 遍历查询的结果*/
            for (SolrDocument solrDocument : solrDocumentList) {
                News news = new News();
                /**因为 Solr 的主键域 id 是 String 类型,而 POJO 中是 Integer 类型,所以要转换*/
                String id = (String) solrDocument.get("id");
                news.setId(Integer.parseInt(id));
                news.setReadNumber((Long) solrDocument.get("news_readNumber"));
                news.setPublishTime((Date) solrDocument.get("new_publishTime"));
                news.setOriginUrl((String) solrDocument.get("news_originUrl"));
                news.setContent((String) solrDocument.get("news_content"));
                news.setOriginName((String) solrDocument.get("news_originName"));
                news.setTitle((String) solrDocument.get("news_title"));
                newsList.add(news);
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } finally {
            /**关闭连接,释放资源*/
            if (solrServer != null) {
                solrServer.shutdown();
            }
        }
        return newsList;
    }
    public static void main(String[] args) throws ParseException {
        List<News> newses = searchSpecialCharacter("http://news.ifeng.com/a/20180907/60033433_0.shtml");
        for (int i = 0; i < newses.size(); i++) {
            System.out.println("-------------" + (i + 1) + "--------------");
            System.out.println(newses.get(i));
        }
    }

控制台输出:

news_originUrl 转义后>>> http\:\/\/news.ifeng.com\/a\/20180907\/60033433_0.shtml
Solr 查询文档总数:1
-------------1--------------
News{content='党的十八大以来,以习近平同志为核心的党中央从关系党和国家前途命运的战略全局出发,从前所未有的....', id=1002, title='中共十八大以来全面依法治国新成就述评', publishTime=Fri Sep 07 17:08:11 CST 2018, originName='凤凰新闻', originUrl='http://news.ifeng.com/a/20180907/60033433_0.shtml', readNumber=8855}

Process finished with exit code 0

查询时间

  • 如果需要指定检索花费的时间,在可以用 org.apache.solr.client.solrj.response.SolrResponseBase.getQTime 方法
         /**执行查询,返回查询结果*/
            QueryResponse queryResponse = solrServer.query(query);

            int time = queryResponse.getQTime();
            System.out.println(time);

优化索引

  1. 优化Lucene 的索引文件以改进搜索性能
  2. 一个索引无需优化也可以正常地运行,优化是一个耗时较多的过程。
  3. 尽量在无人使用或使用频率低时进行优化,server.optimize ();//不要频繁的调用
 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
 solrServer.optimize();

批量操作

  • 无论是 添加、修改、删除 都需要手动提交 commit,所以如果操作的数据量比较大时,可以分批次进行 commit 即可
/**
     * 批量添加新闻——文档
     *
     * @param newsList :被添加的新闻列表
     */
    public static void addDocuments(List<News> newsList) {
        SolrServer solrServer = null;
        try {
            /** 连接 solr 服务端
             * HttpSolrServer(String baseURL)
             * 1)baseURL:为 Solr 服务端地址,如 http://localhost:8983/solr/SolrCore
             * 2)末尾的 SolrCore 未指定时,默认为 collection1
             * 3)HttpSolrServer 继承于 org.apache.solr.client.solrj.impl.CloudSolrServer
             */
            solrServer = new HttpSolrServer("http://localhost:8080/solr/collection1");
            /** 创建 Solr 文档
             * 然后向文档中添加 域及其值
             * addField(String name, Object value)
             * 1)name:域名,必须在 schema.xml 事先定义好,不存在时会报错
             * 2)value:域的值
             * 3)主键 id 域 是必须存在的,不存在时报错
             * 4)如果 id 已经存在,则删除原来的就文档,再添加此新文档(即修改)
             * 5)如果 id 不存在,则直接添加
             */
            for (int i = 0; i < newsList.size(); i++) {
                SolrInputDocument document = new SolrInputDocument();
                News news = newsList.get(i);
                document.addField("id", news.getId());
                document.addField("news_title", news.getTitle());
                document.addField("new_publishTime", news.getPublishTime());
                document.addField("news_originName", news.getOriginName());
                document.addField("news_originUrl", news.getOriginUrl());
                document.addField("news_content", news.getContent());
                document.addField("news_readNumber", news.getReadNumber());
                /** add 方法 添加到索引库中
                 * 每次 100 个时 提交一次,提交之后,Solr 中就有了
                 */
                solrServer.add(document);
                if (i % 100 == 0) {
                    solrServer.commit();
                }
            }
            /** 最后再要提交一次*/
            solrServer.commit();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            /**最后关闭连接,释放资源*/
            if (solrServer != null) {
                solrServer.shutdown();
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/wangmx1993328/article/details/82499574
今日推荐