最近在做毕业设计,一个电商APP,遇到搜索商品的问题,以往做的数据库模糊查询感觉不是那么的高大上,于是决定使用Solr搜索引擎,在此给同样想法的小伙伴一点借鉴,望共勉。

一、Solr部署

1.Solr下载

部署solr通常有2中方式,一个是部署在外部的web容器中例如tomcat,另一个是使用solr内置的jetty作为web容器。因为我做的是微服务项目,感觉独立部署方便一点,所以我们这里采用内置的jetty作为web容器的部署方式。

Solr官网下载适合的版本,windows下选择后缀为.zip的安装包,博主选择的是5.2.1,下载之后找到合适的位置解压

2.Sorl启动

在cmd窗口进入solr的解压目录下的bin文件夹点击20181227110049385.png

20181227110342420.png

注意窗口不要关闭,否则会断开服务器

在浏览器访问solr的管理界面 ,出现下面界面表示启动成功

20181227110406603.png

3. 创建core

方法一:命令行创建
bin目录下cmd窗口执行,如下命令:

20181227110553995.png

方法二:solr管理页面 创建

1.在下图目录中新建new_core

20181227112129371.png

2.上图中的configsets文件中存放的是基本的配置文件,把configsets中的basic_configs下的conf拷贝到new_core中,然后新建文件夹data,作为索引数据的存放文件

20181227112200775.png

3.在solr管理页面中点击core admin 下的 add core,修改name 和instanceDir为new_core,然后点击add core

4.创建完成

刷新界面,可以看到我们创建的core

20181227112442598.png

二、Solr使用

导入数据

solr中负责导入数据的模块叫做DataImportHandler,它有多种实现方式

数据库导入

这里做示范,我们选择一个比较简单的表结构进行数据导入

20181227132950726.png

solr支持多中形式的数据导入,其中最常用的就是从数据库导入数据
我们可以从solr自带的/example/example-DIH/solr/db/conf中找到从数据库导入数据的相关配置作为参考,然后修改coreTest1内的配置

1.修改solrconfig.xml

在最后其后添加如下配置

20181227131131752.png

<requestHandler name="/dataimport" class="solr.DataImportHandler">
    <lst name="defaults">
      <str name="config">db-data-config.xml</str>
    </lst>
  </requestHandler>

2.从example中拷贝db-data-config.xml到coreTest1,并根据数据库的使用情况进行修改,我这里使用的是mysql

20181227120112581.png

<dataConfig>
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/shopsystem" user="root" password="root" />
    <document>
        <entity name="item" query="select * from user">
            <field column="user_id" name="id" />
            <field column="user_sex" name="user_sex" />
            <field column="user_name" name="user_name" />
        </entity>
    </document>
</dataConfig>

这里有个坑,column对应数据库的列名,name为显示的列名,对应下面schema.xml文件中的name,这里必须要有一个name为id

3.将mysql的数据库连接jar拷贝到solr根目录的dist文件中,然后修改solrconfig.xml,加载这个jar包

<lib dir="${solr.install.dir:../../../..}/dist/" regex=".*\.jar" />

4.修改managed-schema为schema.xml,如果已经存在则忽略,根据db-data-config.xml中的配置的从数据库导入的字段进行修改.

<field name="user_sex" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="user_name" type="string" indexed="true" stored="true" required="true" multiValued="false" />

这里不需要再设置id列,因为这个文件中已经默认存在,这也是第2步中注意事项所说的 

5.在core admin选项中 选择刚刚修改的coreTest1,然后点击reload按钮,加载刚刚上面修改的配置

6.开始导入数据,选择刚刚修改的coreTest1下面的DataImport选项,然后点击execute按钮

20180116180737105.png

20181227134846635.png

7.如果还是没成功可以去左侧导航栏的Logging查看那个地方有问题,一步步总会成功的

20181227133247819.png

solr管理界面导入

20181227135052297.png

20181227135122645.png

服务器导入

数据库导入个人感觉适合查询数据集中的情况,我要查询的数据在多个表中, 而且数据会插入不同的core中,所以我选择了在服务端随着数据的改变通过代码对数据进行更新。

下面是一个导入数据的工具类,直接调用即可,读者可根据注解自行修改

@Service
public class SolrService<T> {
 
    // 指定solr服务器的地址
    private final static String SOLR_URL = "http://localhost:8983/solr/";
 
    private String solrCore = "shopstem";// 指定的存储数据的collection
 
    /**
     * 创建SolrServer对象
     * 
     * 该对象有两个可以使用,都是线程安全的 1、CommonsHttpSolrServer:启动web服务器使用的,通过http请求的 2、
     * EmbeddedSolrServer:内嵌式的,导入solr的jar包就可以使用了 3、solr
     * 4.0之后好像添加了不少东西,其中CommonsHttpSolrServer这个类改名为HttpSolrClient
     * 
     * @return
     */
    public HttpSolrClient createSolrServer() {
        HttpSolrClient solr = null;
        solr = new HttpSolrClient(SOLR_URL);
        solr.setConnectionTimeout(100);
        solr.setDefaultMaxConnectionsPerHost(100);
        solr.setMaxTotalConnections(100);
        return solr;
    }
 
    public void addBeansBatch(List<T> list) throws IOException, SolrServerException {
        HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
        solr.addBeans(list);
        solr.commit();
        solr.close();
    }
 
    public void addBean(T t) throws IOException, SolrServerException {
        HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
        solr.addBean(t);
        solr.commit();
        solr.close();
    }
 
    /**
     * 往索引库添加文档
     * 
     * @throws IOException
     * @throws SolrServerException
     */
    public void addDoc() throws SolrServerException, IOException {
        // 构造一篇文档
        SolrInputDocument document = new SolrInputDocument();
        // 往doc中添加字段,在客户端这边添加的字段必须在服务端中有过定义
        document.addField("id", "4");
        document.addField("goods_name", "LG 55LG63CJ-CA 4K液晶");
        document.addField("goods_price", "1000");
        document.addField("attr_name", "黄色,自由组合");
        document.addField("type_name", "超薄电视");
        // 获得一个solr服务端的请求,去提交 ,选择具体的某一个solr core
        HttpSolrClient solr = new HttpSolrClient(SOLR_URL + solrCore);
        solr.add(document);
        solr.commit();
        solr.close();
    }
 
    /**
     * 根据id从索引库删除文档
     */
    public void deleteDocumentById(String id) throws Exception {
        // 选择具体的某一个solr core
        HttpSolrClient server = new HttpSolrClient(SOLR_URL + solrCore);
        // 删除文档
        server.deleteById(id);
        // 删除所有的索引
        //server.deleteByQuery("*:*");
        // 提交修改
        server.commit();
        server.close();
    }
 
    /**
     * 查询
     * 
     * @throws Exception
     */
    public List<Goods> querySolr(String search) throws Exception {
        HttpSolrClient solrServer = new HttpSolrClient(SOLR_URL + solrCore);
        SolrQuery query = new SolrQuery();
        // 下面设置solr查询参数
        query.set("q", search);// 参数q 查询所有
        //query.set("q","*长虹*");//相关查询,比如某条数据某个字段含有周、星、驰三个字 将会查询出来
        // ,这个作用适用于联想查询
 
        // 参数fq, 给query增加过滤查询条件
        // query.addFilterQuery("id:[0 TO 9]");//id为0-9
 
        // 给query增加布尔过滤条件
        // query.addFilterQuery("description:演员"); //description字段中含有“演员”两字的数据
 
        // 参数df,给query设置默认搜索域
        // query.set("df", "name");
 
        //query.setQuery("name:*");
        //query.setQuery("goods_name:"+search+" OR goods_price:"+search+"  OR type_name:"+search+"" );//name
        // 包含zhangsan或者123
        // query.setQuery("name:*zhangsan* AND description:*zhangsan*" );//
        // name包含且
 
        // 分组查询
        //query.setFacet(true);
        //query.addFacetField("name", "description");// 两个域有各自独立的结果
        /*
         * FacetComponet有两种排序选择,分别是count和index,
         * count是按每个词出现的次数,index是按词的字典顺序。如果查询参数不指定facet.sort,solr默认是按count排序。
         */
        query.setFacetSort(FacetParams.FACET_SORT_COUNT);
        /* query.setFacetLimit(101); */// 设置返回结果条数 ,-1表示返回所有,默认值为100
        /* query.setParam(FacetParams.FACET_OFFSET, "100"); */// 开始条数,偏移量,它与facet.limit配合使用可以达到分页的效果
        query.setFacetMinCount(1);// 设置 限制 count的最小返回值,默认为0
        query.setFacetMissing(false);// 不统计null的值
        /* query.setFacetPrefix("test");//设置前缀 */
 
        // 参数sort,设置返回结果的排序规则
        // query.addSort("id",SolrQuery.ORDER.asc);
        // query.addSort("name", SolrQuery.ORDER.desc);
 
        // 设置分页参数
        // query.setStart(0);
        // query.setRows(10);//每一页多少值
 
        // 参数hl,设置高亮
        query.setHighlight(true);
        // 设置高亮的字段
        query.addHighlightField("goods_name");
        // 设置高亮的样式
        query.setHighlightSimplePre("<font color='red'>");
        query.setHighlightSimplePost("</font>");
 
        // 获取查询结果
        QueryResponse response = solrServer.query(query);
        // 两种结果获取:得到文档集合或者实体对象
 
        // 获取高亮数据结果
        // Map<String, Map<String, List<String>>> map =
        // response.getHighlighting();
 
        // 得到FacetField结果
        System.out.println(response.getFacetFields());
 
        // 获取高亮数据结果
        System.out.println("高亮数据结果" + response.getHighlighting());
 
        // 查询得到文档的集合
        SolrDocumentList solrDocumentList = response.getResults();
        System.out.println("通过文档集合获取查询文档数量:" + solrDocumentList.getNumFound());
        // 遍历列表
        List<Goods> list = new ArrayList<Goods>();
        for (SolrDocument doc : solrDocumentList) {
            Goods goods = new Goods();
            goods.setGoods_id(Integer.parseInt(doc.get("goods_id").toString().substring(doc.get("goods_id").toString().indexOf("[")+1,doc.get("goods_id").toString().length()-1)));
            //goodsdetail.setGoods_name( doc.get("goods_name").toString().substring(doc.get("goods_name").toString().indexOf("[")+1,doc.get("goods_name").toString().length()-1));
            //goodsdetail.setType_name( doc.get("type_name").toString().substring(doc.get("type_name").toString().indexOf("[")+1,doc.get("type_name").toString().length()-1));
            //goodsdetail.setAttr_name(doc.get("attr_name").toString().substring(doc.get("attr_name").toString().indexOf("[")+1,doc.get("attr_name").toString().length()-1));
            System.out.println(goods.toString());
            list.add(goods);
        }
 
        // 得到实体对象
//        List<GoodsDetail> tmpLists = response.getBeans(GoodsDetail.class);
//        if (tmpLists != null && tmpLists.size() > 0) {
//            System.out.println("实体对象赋值内容:");
//            for (Person per : tmpLists) {
//                System.out.println(per.toString());
//            }
//        }
//        System.out.println(tmpLists);
        return list;
    }
 
    public static void main(String[] args) throws Exception {
        SolrService solr = new SolrService();
        // solr.createSolrServer();
        solr.addDoc();
        //solr.addPersonIndex();
        //solr.addPersonBatch();
        //solr.deleteDocumentById("149d9e7b-064f-4977-bc21-a9c0c61fbf32");
        //solr.querySolr("超薄电视");
    }
 
}

下面是我放一下我所实现的web端及APP端的搜索功能图

20181227144830517.gif

20181227144830612.gif


版权声明:文章转载请注明来源,如有侵权请联系博主删除!
最后修改:2019 年 12 月 27 日 01 : 27 PM
如果觉得我的文章对你有用,请随意赞赏
评论打卡也可以哦,您的鼓励是我最大的动力!