Solr

目录

  • solr
    • 什么是Solr
      • 直接使用sql搜索存在的问题
      • Apache Solr
      • 为什么选择Solr ?
      • Solr 关键特性
    • Solr安装
    • 中文分词器
      • IK Analyzer简介
      • IK Analyzer(配置)
      • 什么是域
      • 域的分类
      • 域的常用属性
      • 普通域
      • 复制域
    • solrj
      • 概述
      • 操作步骤
    • Spring Data Solr
      • 简介
      • 入门
    • 库存数据批量导入
      • 作用
      • 创建solr-util(jar) ,引入依赖dao项目
      • 在common工程当中引入pom依赖
      • 在solr-util项目src/main/resource/spring文件夹下创建
      • 把pojo/item添加@Field
      • 创建类SolrUtil ,实现商品数据的查询(已审核商品)

solr

什么是Solr

直接使用sql搜索存在的问题

  • 大多数搜索引擎应用都必须具有某种搜索功能
  • 搜索功能往往是巨大的资源消耗
  • 它们由于沉重的数据库加载而拖垮你的应用的性能
  • 所有我们一般在做搜索的时候 会把它单独转移到一个外部的搜索服务器当中进行
  • Apache Solr是一个流行的开源搜索服务器

Apache Solr

  • Solr是一个开源搜索平台,用于构建搜索应用程序。
  • 是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口
  • 它建立在Lucene(全文搜索引擎)之上。
  • Solr是企业级的,快速的和高度可扩展的。
  • 用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。

为什么选择Solr ?

  • 第一点原因:来自SQL数据库在性能上缺乏亮点。基本上,你需要在你的查询中使用JOIN操作。
  • 第二点原因是文档的天然数据特性松散的文本文件,这种查询都是需要使用LIKE。然而joins和likes都是性能杀手,在目前的数据库引擎中是不方便的。
  • solr底层采用的是倒排索引。这种数据结构类似与美化过的词典

Solr 关键特性

1.基于标准的开放接口:Solr搜索服务器支持通过XML、JSON和HTTP查询和获取结果。
2.易管理:Solr可以通过HTML页面管理,Solr配置通过XML完成。
3.可伸缩性:能够有效地复制到另外一个Solr搜索服务器。
4.灵活的插件体系:新功能能够以插件的形式方便的添加到Solr服务器上。
5.强大的数据导入功能:数据库和其他结构化数据源现在都可以导入、映射和转化。

Solr安装

解压tomcat
    mkdir /usr/local/solr
    cd /usr/local/solr
    tar -zxvf apache-tomcat-8.5.32.tar.gz 
    mv apache-tomcat-8.5.32 tomcat
    有可能会存在tomcat在centos7中启动缓慢的现象
        安装:yum -y install rng-tools
        开启 rng-tools服务:service rngd start
        
解压solr
    tar -zxvf solr-4.10.3.tar
    
解压IK
    unzip IKAnalyzer.zip
    
复制solr.war到tomcat/webapp下
    cd /usr/local/solr/solr-4.10.3/example/webapps/
    cp solr.war /usr/local/solr/tomcat/webapps/
    
启动tomcat让solr.war自动解压
    /usr/local/solr/tomcat/bin
    ./startup.sh
    
关闭tomcat后才能删除solr.war包,否则会连带solr应用一起删除
    /usr/local/solr/tomcat/bin
    ./shutdown.sh
    
进入到webapps删除solr.war包
    cd /usr/local/solr/tomcat/webapps/
    rm -rf solr.war
    
将solr-4.10.3/example/lib/ext/目录下的所有jar包拷贝到/usr/local/solr/tomcat/webapps/solr/WEB-INF/lib目录中
    cd /usr/local/solr/solr-4.10.3/example/lib/ext
    cp *  /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib
    
将solr-4.10.3/example/目录下的solr文件夹复制到/usr/local/solr/目录下,并且返回到/usr/local/solr目录下将solr重命名为solrhome
    cd /usr/local/solr/solr-4.10.3/example/
    cp -r solr /usr/local/solr/
    cd /usr/local/solr
    mv solr solrhome
    
配置tomcat/webapps/solr/WEB-INF/web.xml家的位置
    cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/
    vim web.xml
    添加solrhome(/usr/local/solr/solrhome)
    
        solr/home
        /usr/local/solr/solrhome
        java.lang.String
    
启动tomcat
    /usr/local/solr/tomcat/bin/
    ./startup.sh

tomcat在linux中启动慢解决方式

中文分词器

IK Analyzer简介

  • IK Analyzer 是一个开源的,基亍 java 语言开发的轻量级的中文分词工具包。
  • 它是以开源项目Luence 为应用主体的,结合词典分词和文法分析算法的中文分词组件
  • IK 实现了简单的分词歧义排除算法,标志着 IK 分词器从单纯的词典分词向模拟语义分词衍化。
  • 作用: 有中文语义分析的效果, 对中文分词效果好.

IK Analyzer(配置)

把IKAnalyzer2012FF_u1.jar 添加到 solr 工程的 lib 目录下
    cd /usr/local/solr/IKAnalyzer/
    cp IKAnalyzer2012FF_u1.jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/
    
创建WEB-INF/classes文件夹
    cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/
    mkdir classes
    
把扩展词典、停用词词典、配置文件放到 solr 工程的 WEB-INF/classes 目录下
    cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes
    cp /usr/local/solr/IKAnalyzer/IKAnalyzer.cfg.xml ./
    cp /usr/local/solr/IKAnalyzer/ext_stopword.dic ./ 

将ext_stopword.dic文件名修改为stopword.dic
    mv ext_stopword.dic stopword.dic

修改IKAnalyzer.cfg.xml配置文件
    stopword.dic已经有了,ext.dic还没有
    cd /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes
    vi IKAnalyzer.cfg.xml
    :wq
    
    
    
        IKAnalyzer扩展配置
        <--用户可以在这里配置自己的扩展字典-->
        ext.dic;
        <--用户可以在这里配置自己的扩展停止词字典-->
        stopword.dic
    

    创建ext.dic
        touch ext.dic

    stopword.dic-停止词典
        切分词的时候, 凡是出现在停止词典中的词都会被过滤掉.
    
    ext.dic-扩展词典
        凡是专有名词都会放到这里, 如果自然语义中不是一个词, 放到这里后solr
        切分词的时候就会切分成一个词.
    
配置分词器
    修改 Solrhome 的 schema.xml 文件
        cd /usr/local/solr/solrhome/collection1/conf
        vim schema.xml
            在最后添加
                
                    
                
    自定义域名使用自己创建的分词器
        
    
配置完毕后重启tomcat

什么是域

  • 域相当于数据库的表字段,用户存放数据
  • 用户根据业务需要去定义相关的Field(域)

域的分类

field普通域
    大多数情况都可以用这个域来完成, 主要定义了域名和域的类型.
    
copyField复制域
    复制域中有source叫做源域, dest代表目标域, 
    在维护数据的时候, 源域中的内容会复制到目标域中一份, 
    从目标域中搜索, 就相当于从多个源域中搜索一样
    
dynamicField动态域
    solr中域名要先定义后使用, 没有定义就使用会报错, 
    起到模糊匹配的效果,可以模糊匹配没有定义过的域名,相当于通配符的作用
    
uniqueKey主键域
    在添加数据的时候必须有主键域, 没有会报错, 这个不用添加也不用修改, 就使用这个默认的域名id就可以.

域的常用属性

  • name:指定域的名称
  • type:指定域的类型
  • indexed:是否索引
  • stored:是否存储
  • required:是否必须
  • multiValued:是否多值

普通域


     











复制域





动态域

solrj

概述

  • solrJ是solr官方推出的客户端工具包, 将solrj的jar包放到我们项目中
  • 我们就可以调用solrj中的api来远程给solr服务器发送命令, solr服务器就可以完成对索引库的操作(添加修改删除查询)

操作步骤

创建一个普通的Java工程

添加soloJ相关Jar包



    org.apache.solr
    solr-solrj
    ${solrj.version}

操作

添加或者修改

//修改时, 会把以前的内容删除, 然后再添加
@Test
public void testIndexCreateAndUpdate() throws Exception {
    /**
    * 创建和solr服务器连接
    * http://192.168.1.88:8080/solr是连接的默认实例也就是collection1实例
     * http://192.168.1.88:8080/solr/collection2实例
    */
    SolrServer solrServer = new HttpSolrServer("http://192.168.1.88:8080/solr");
    //创建文档对象
    SolrInputDocument doc = new SolrInputDocument();
    doc.addField("id", "002");
    doc.addField("title", "后裔");
    doc.addField("price", "250");
    //添加或者修改
    solrServer.add(doc);
    //提交
    solrServer.commit();
    }
}
查询所有

@Test
public void testIndexSearch() throws Exception {
    SolrServer solrServer = new HttpSolrServer("http://192.168.1.88:8080/solr");
    //创建查询对象
    SolrQuery query = new SolrQuery();
    //设置查询条件
    query.setQuery("*:*");
    //查询并返回响应
    QueryResponse queryResponse = solrServer.query(query);
    //从响应中获取结果集
    SolrDocumentList results = queryResponse.getResults();
    System.out.println("count=" + results.getNumFound());
    for (SolrDocument result : results) {
        System.out.println("id=" + result.get("id"));
        System.out.println("title=" + result.get("title"));
    }
}
删除
@Test
public void testIndexDelete() throws Exception {
    SolrServer solrServer = new HttpSolrServer("http://192.168.1.88:8080/solr");
    //单个删除
    //solrServer.deleteById("001");
    //删除所有
    solrServer.deleteByQuery("*:*");
    //提交
    solrServer.commit();
}

Spring Data Solr

简介

  • Spring Data Solr就是为了方便Solr的开发所研制的一个框架
  • 其底层是对SolrJ(官方API)的封装

入门

(1)创建maven工程SpringSolrProject jar项目

(2)pom.xml中引入依赖


    5.1.7.RELEASE



    
        org.springframework
        spring-context
        ${spring.version}
    
    
        org.springframework
        spring-beans
        ${spring.version}
    
    
        org.springframework
        spring-webmvc
        ${spring.version}
    
    
        org.springframework
        spring-jdbc
        ${spring.version}
    
    
        org.springframework
        spring-aspects
        ${spring.version}
    
    
        org.springframework
        spring-jms
        ${spring.version}
    
    
        org.springframework
        spring-context-support
        ${spring.version}
    
    
        org.springframework
        spring-test
        ${spring.version}
    


    
        org.springframework.data
        spring-data-solr
        1.5.5.RELEASE
    
    
        org.springframework
        spring-test
        5.1.7.RELEASE
    
    
        junit
        junit
        4.12
    
    
        javax.servlet
        servlet-api
        2.5
    

(3)在src/main/resources下创建applicationContext-solr.xml



    
    

    
    
        
    

(4)创建 cn.fmjava.pojo 包 引入 Item实体类

import lombok.Data;
import org.apache.solr.client.solrj.beans.Field;
import org.springframework.data.solr.core.mapping.Dynamic;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Data
public class Item implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 商品id,同时也是商品编号
     */
    @Field
    private Long id;

    /**
     * 商品标题
     */
    @Field("item_title")
    private String title;

    /**
     * 商品卖点
     */
    private String sellPoint;

    /**
     * 商品价格,单位为:元
     */
    @Field("item_price")
    private BigDecimal price;

    private Integer stockCount;

    /**
     * 库存数量
     */
    private Integer num;

    /**
     * 商品条形码
     */
    private String barcode;

    /**
     * 商品图片
     */
    @Field("item_image")
    private String image;

    /**
     * 所属类目,叶子类目
     */
    private Long categoryid;

    /**
     * 商品状态,1-正常,2-下架,3-删除
     */
    private String status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    @Field("item_updatetime")
    private Date updateTime;

    private String itemSn;

    private BigDecimal costPirce;

    private BigDecimal marketPrice;

    private String isDefault;

    @Field("item_goodsid")
    private Long goodsId;

    private String sellerId;

    private String cartThumbnail;

    @Field("item_category")
    private String category;

    @Field("item_brand")
    private String brand;

    private String spec;

    @Field("item_seller")
    private String seller;

    @Dynamic
    @Field("item_spec_*")
    private Map specMap;

    public Map getSpecMap() {
        return specMap;
    }

    public void setSpecMap(Map specMap) {
        this.specMap = specMap;
    }

}

(5)配置业务域

修改solrhome的schema.xml 文件 设置业务系统 Field







复制域的作用在于将某一个Field中的数据复制到另一个域中




动态扩充字段时,我们需要使用动态域
  

配置
cd /usr/local/solr/solrhome/collection1/conf
vim schema.xml

    
    
    
    
    
    








  

重启tomcat
/usr/local/solr/tomcat/bin/shutdown.sh
/usr/local/solr/tomcat/bin/startup.sh

(6)在实体类字段上添加@Field注解

public class Item implements Serializable {
    /**
     * 商品id,同时也是商品编号
     */
    @Field
    private Long id;

    /**
     * 商品标题
     */
    @Field("item_title")
    private String title;

    /**
     * 商品卖点
     */
    private String sellPoint;

    /**
     * 商品价格,单位为:元
     */
    @Field("item_price")
    private BigDecimal price;

    private Integer stockCount;

    /**
     * 库存数量
     */
    private Integer num;

    /**
     * 商品条形码
     */
    private String barcode;

    /**
     * 商品图片
     */
    @Field("item_image")
    private String image;

    /**
     * 所属类目,叶子类目
     */
    private Long categoryid;

    /**
     * 商品状态,1-正常,2-下架,3-删除
     */
    private String status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    private String itemSn;

    private BigDecimal costPirce;

    private BigDecimal marketPrice;

    private String isDefault;

    @Field("item_goodsid")
    private Long goodsId;

    private String sellerId;

    private String cartThumbnail;

    @Field("item_category")
    private String category;

    @Field("item_brand")
    private String brand;

    private String spec;

    @Field("item_seller")
    private String seller;

    private static final long serialVersionUID = 1L;
}

(7)创建测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-solr.xml")
public class TestIndexManager {
    @Autowired
    private SolrTemplate solrTemplate;
    //添加更新
    @Test
    public void testIndexCreatAndUpdate() {
        List itemList = new ArrayList();
        for(long i= 1; i < 100; i++) {
            Item item = new Item();
            item.setId(i);
            item.setTitle("鲁班" + i);
            item.setCategory("射手");
            item.setPrice(new BigDecimal("100"+i));
            item.setBrand("王者");
            itemList.add(item);
        }
        //保存
        //solrTemplate.saveBean(itemList);
        solrTemplate.saveBeans(itemList);
        //提交
        solrTemplate.commit();
    }

    //删除
    @Test
    public void testIndexDelte() {
        //根据主键域id删除
        //solrTemplate.deleteById("1");

        //创建查询对象
        Query query = new SimpleQuery("*:*");
        //根据查询条件删除
        solrTemplate.delete(query);
        //提交
        solrTemplate.commit();
    }

    //查询
    @Test
    public void testSearch() {
        //创建查询对象
        //Query query = new SimpleQuery("*:*");
        //创建查询对象
        Query query = new SimpleQuery();
        //创建查询条件对象, 注意这里的Criteria对象和mybatis中的那个不是同一个, 只是同名而已
        Criteria criteria = new Criteria("item_title").contains("鲁班");
        //查询对象中放入查询条件
        query.addCriteria(criteria);
        //从第几条开始查询
        query.setOffset(11);
        //设置每页查询多少条数据
        query.setRows(20);
        //查询并返回结果
        ScoredPage items = solrTemplate.queryForPage(query, Item.class);
        //总页数
        int totalPages = items.getTotalPages();
        //查询到的总记录数
        long totalElements = items.getTotalElements();
        //查询到的数据集合
        List content = items.getContent();
        //每页有多少条数据
        int numberOfElements = items.getNumberOfElements();
        System.out.println("==========");
        System.out.println(content);
    }
}

库存数据批量导入

作用

  • 查询库存数据库中所有的数据
  • 把数据导入到索引库当中
  • 只需要要用一次, 当索引库当中的数据出现损坏或文件丢失时, 再次调用

创建solr-util(jar) ,引入依赖dao项目


    
        com.itxk
        dao
        1.0-SNAPSHOT
    

在common工程当中引入pom依赖



    org.springframework.data
    spring-data-solr
    1.5.5.RELEASE

在solr-util项目src/main/resource/spring文件夹下创建

spring/applicationContext-solr.xml文件




    
    

    
    
        
    

spring/applicationContext.xml




    

把pojo/item添加@Field

@Data
public class Item implements Serializable {
    private static final long serialVersionUID = 1L;
    
    /**
     * 商品id,同时也是商品编号
     */
    @Field
    private Long id;

    /**
     * 商品标题
     */
    @Field("item_title")
    private String title;

    /**
     * 商品卖点
     */
    private String sellPoint;

    /**
     * 商品价格,单位为:元
     */
    @Field("item_price")
    private BigDecimal price;

    private Integer stockCount;

    /**
     * 库存数量
     */
    private Integer num;

    /**
     * 商品条形码
     */
    private String barcode;

    /**
     * 商品图片
     */
    @Field("item_image")
    private String image;

    /**
     * 所属类目,叶子类目
     */
    private Long categoryid;

    /**
     * 商品状态,1-正常,2-下架,3-删除
     */
    private String status;

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    @Field("item_updatetime")
    private Date updateTime;

    private String itemSn;

    private BigDecimal costPirce;

    private BigDecimal marketPrice;

    private String isDefault;

    @Field("item_goodsid")
    private Long goodsId;

    private String sellerId;

    private String cartThumbnail;

    @Field("item_category")
    private String category;

    @Field("item_brand")
    private String brand;

    private String spec;

    @Field("item_seller")
    private String seller;

    @Dynamic
    @Field("item_spec_*")
    private Map specMap;

    public Map getSpecMap() {
        return specMap;
    }

    public void setSpecMap(Map specMap) {
        this.specMap = specMap;
    }
}

创建类SolrUtil ,实现商品数据的查询(已审核商品)

@Component
public class DataImportToSolr {

    @Autowired
    private SolrTemplate solrTemplate;
    @Autowired
    private ItemDao itemDao;
    public void importItemDataToSolr() {
        ItemQuery query = new ItemQuery();
        ItemQuery.Criteria criteria = query.createCriteria();
        criteria.andStatusEqualTo("1");
        List items = itemDao.selectByExample(query);
        if (items != null) {
            for (Item item : items) {
                //获取规格json格式字符串
                String specJsonStr = item.getSpec();
                Map map = JSON.parseObject(specJsonStr, Map.class);
                item.setSpecMap(map);
            }
            //保存
            solrTemplate.saveBeans(items);
            //提交
            solrTemplate.commit();
        }
    }

    public static void main(String[] args) {
        ApplicationContext contexnt =
                new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml");
        DataImportToSolr bean = (DataImportToSolr)contexnt.getBean("dataImportToSolr");
        bean.importItemDataToSolr();
    }
}

你可能感兴趣的:(Solr)