欢迎投稿

今日深度:

Solr实战,

Solr实战,


solr版本5.5.3,

tomcat版本8.0,jdk1.7,操作系统centos7


转载自  https://segmentfault.com/a/1190000012754074


可访问网址
http://archive.apache.org/dis... 进行版本的下载,这里我下载的是5.5.3的版本,也可以访问http://pan.baidu.com/s/1pLzzM0j 进行下载,以下配置是solr基于tomcat8的整合。

至于为什么要用solr5.5,因为最新的6.10,没有中文的分词器支持,这里使用的是ik分词器,刚好支持到5.5

由于solr5.5.0之后的版本部署在tomcat7下的时候,会报

java.lang.NoSuchMethodError: javax.servlet.ServletInputStream.isFinished()Z

的错误, 这个是serverlet3.1才有的方法。所以本次使tomcat8。

1.下载

2.配置

解压压缩包并将solr-5.5.3/server/solr-webapp/webapp复制到/data/solr中,这是Tomcat8下需要跑的solr程序

tar -zxvf solr-5.5.3
cp -rf solr-5.5.3/server/solr-webapp/webapp/. /data/solr

复制solr-5.5.3/server/solr到/usr/local文件夹下(自定义)

cp -rf solr-5.5.3/server/solr /usr/local

修改/data/solr/WEB-INF/下的web.xml

<env-entry>
    <env-entry-name>solr/home</env-entry-name>
    <env-entry-value>/usr/local/solr</env-entry-value>
    <env-entry-type>java.lang.String</env-entry-type>
</env-entry>

将/solr-5.5.3/server/lib/ext/下的jar复制到/data/solr/WEB-INF/lib/中

cp -rf /solr-5.5.3/server/lib/ext/. /data/solr/WEB-INF/lib/

将/solr-5.5.3/server/resources/log4j.properties文件复制到/data/solr/WEB-INF/classes/

mkdir /data/solr/WEB-INF/classes
cp /solr-5.5.3/server/resources/log4j.properties /data/solr/WEB-INF/classes/

启动tomcat8

/usr/local/tomcat8/bin/startup.sh

然后访问IP/admin.html,出现以下界面则表示配置成功

3.solrcore配置

Solrhome是一个目录,它是solr运行的主目录,它包括多个SolrCore目录,SolrCore目录中就solr实例的运行配置文件和数据文件。

Solrhome中可以包括多个SolrCore,每个SolrCore互相独立,而且可以单独对外提供搜索和索引服务。

点击左侧菜单Core Admin

说明solrcore还未配置,将/solr-5.5.3/example/example-DIH/solr/solr下的文件全部复制到/usr/local/solr/solrcore1的文件夹中,并修改jar路径

cp -rf solr-5.5.3/example/example-DIH/solr/solr/. /usr/local/solr/solrcore1

修改conf下的solrconfig.xml

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

  <lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
  <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-\d.*\.jar" />

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

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

修改为

  <lib dir="/usr/local/solr/dist/" regex="solr-dataimporthandler-.*\.jar" />

  <lib dir="/usr/local/solr/contrib/extraction/lib" regex=".*\.jar" />
  <lib dir="/usr/local/solr/dist/" regex="solr-cell-\d.*\.jar" />

  <lib dir="/usr/local/solr/contrib/langid/lib/" regex=".*\.jar" />
  <lib dir="/usr/local/solr/dist/" regex="solr-langid-\d.*\.jar" />

  <lib dir="/usr/local/solr/contrib/velocity/lib" regex=".*\.jar" />
  <lib dir="/usr/local/solr/dist/" regex="solr-velocity-\d.*\.jar" />

再次点击,在name 和instanceDir下都输入solrcore1(在步骤一中取得名称) ,点击add core即可,也可重启tomcat8后看到

4.界面功能介绍

Analysis

Document

通过该界面操作,可以对索引库进行添加索引、删除索引、修改索引

在solr中,添加或修改文档时,必须要传入一个唯一主键id

Query
::可以查询索引的数据

5.配置中文分词器

可见中文不能分词,需要配置IK分词器

ik分词器下载地址 :https://github.com/EugenePig/ik-analyzer-solr5 , 下载完之后使用maven命令, mvn package 即可生成jar文件,或者下载我编译好的 http://pan.baidu.com/s/1qYGsP20 (ps:我用的1.7版本的jdk,如果使用1.8版本的同学不要下载)

将jar复制到/data/solr/WEB-INF/lib里面,修改/usr/local/solr/solrcore1/conf下的managed-schema,在文件最后追加以下配置

<fieldType name="text_ik" class="solr.TextField">
    <analyzer type="index" useSmart="false"
        class="org.wltea.analyzer.lucene.IKAnalyzer" />
    <analyzer type="query" useSmart="true"
        class="org.wltea.analyzer.lucene.IKAnalyzer" />
</fieldType>
    

重启tomcat,再次分词

6.域

6.1 field

域,我个人也称它为字段,它在solr中有特定的含义,就类似数据库中表的列一样,规范着写入的数据,我们先来做个例子。

打开/usr/local/solr/solrcore1/conf下的managed-schema,先拿出一条配置来看一下

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

认识一下这些属性

  1. name:域名
  2. type:域的类型,必须匹配类型,不然会报错
  3. indexed:是否要作索引
  4. stored:是否要存储
  5. required:是否必填,一般只有id才会设置
  6. multiValued:是否有多个值,如果设置为多值,里面的值就采用数组的方式来存储,比如商品图片地址(大图,中图,小图等)

6.2配置动态域 dynamicField

同样的,也先拿出一条来看看

<dynamicField name="*_i" type="string" indexed="true" stored="true" multiValued="true" />

何谓动态域呢?就是这个域的名称,是由表达式组成的,只要名称满足了这个 表达式,就可以用这个域

同样的认识一下这些属性

  1. name:域的名称,该域的名称是通过一个表达式来指定的,只要符合这这个规则,就可以使用这个域。比如 aa_i,bb_i,13_i等等,只要满足这个表达式皆可
  2. type:对应的值类型,相应的值必须满足这个类型,不然就会报错
  3. indexed:是否要索引
  4. stored:是否要存储
  5. ...其它的属性与普通的域一致

6.3主键域 uniqueKey

给出一条配置

<uniqueKey>id</uniqueKey>

指定一个唯一的主键,每一个文档中,都应该有一个唯一的主键,这个值不要随便改

6.4复制域 copyField

同样的给出一段配置,这段稍微有点复杂

<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
  <analyzer type="index">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
    <!-- in this example, we will only use synonyms at query time
    <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
    -->
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
  <analyzer type="query">
    <tokenizer class="solr.StandardTokenizerFactory"/>
    <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
    <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
    <filter class="solr.LowerCaseFilterFactory"/>
  </analyzer>
</fieldType>

给出相应属性的说明

  1. name:域的名称
  2. class:指定solr的类型
  3. analyzer:分词器的配置
  4. type: index(索引分词器),query(查询分词器)
  5. tokenizer:配置分词器
  6. filter:过滤器

7.业务字段的实际配置

经过上面的学习,差不多了解了一些常用的配置,如今我们用field来配置实际的业务字段,有属性如下

当然,中文分词还是要用的,因为我们在前面的章节中,已经配置了一个fieldType的中文分词,所以我们现在一律用中文分词的域类型

主键的id就不需要配置了,默认已经把id配置为主键了,默认的配置如下

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

商品名称(需要分词,需要存储)

<field name="name" type="text_ik" indexed="true" stored="true" />

商品分类(不需要分词,需要存储)

<field name="catalog" type="int" indexed="false" stored="true" />

商品分类名称(需要分词,需要存储)

<field name="catalog_name" type="text_ik" indexed="true" stored="true" />

商品价格(不分词,需要存储)

<field name="price" type="double" indexed="false" stored="true" />

商品描述(需要分词,不需要存储)

<field name="description" type="text_ik" indexed="true" stored="false" />

商品图片(不需要分词,需要存储)

<field name="picture" type="string" indexed="false" stored="true" />

==复制域的应用==

前面我们了解了复制域,但是却不知道它的应用场景,现在我们结合实际情况来讲一下复制域

用户在搜索框搜索的时候,有可能输入的是商品名称,也有可能输入的是商品描述,也有可能输入的是一个商品类型,那么这些值的搜索,肯定在后台是对应一个域的,那么既然如此,我们就可以把这些域合并成一个,这样在后台只需要单独的对这一个域进行搜索就可以了

先定义一个目标域

<field name="myKeyword" type="text_ik" indexed="true" stored="false" multiValued="true"/>

复制域,把商品名称,商品描述,商品类型名称复制到上面的这个域中

<copyField source="name" dest="myKeyword"/>
<copyField source="catalog_name" dest="myKeyword"/>
<copyField source="description" dest="myKeyword"/>

8.dataimport 导入数据库数据

solr默认是没有开启dataimport这个功能的,所以我们要经过一点配置来开启它

  1. 首先找到solr5.5.3/dist/solr-dataimporthandler-5.5.3.jar,把这个文件复制到/data/solr/WEB-INF/lib/下,并且找到相应数据库的驱动包,也同样放到该目录。我这里用的是mysql的驱动包。
  2. 找到solr5.5.3/example/example-DIH/solr/db/conf/db-data-config.xml,把其复制到/usr/local/solr/solrcore1/conf/下,并改名为data-config.xml.
  3. 找到solrHome/solrcore1/conf/solrconfig.xml,并打开,在里面修改一段内容,如下
 <requestHandler name="/dataimport" class="solr.DataImportHandler">
      <lst name="defaults">
            <str name="config">data-config.xml</str>
      </lst>
  </requestHandler>
  1. 打开并编辑data-config.xml,完整的配置文件如下
 <dataConfig>
    <!-- 这是mysql的配置,学会jdbc的都应该看得懂 -->
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/solr" user="root" password="密码"/>
    <document>
        <!-- name属性,就代表着一个文档,可以随便命名 -->
        <!-- query是一条sql,代表在数据库查找出来的数据 -->
        <entity name="product" query="select * from products">
            <!-- 每一个field映射着数据库中列与文档中的域,column是数据库列,name是solr的域(必须是在managed-schema文件中配置过的域才行) -->
            <field column="pid" name="id"/>
            <field column="name" name="product_name"/>
            <field column="catalog" name="product_catalog"/>
            <field column="catalog_name" name="product_catalog_name"/>
            <field column="price" name="product_price"/>
            <field column="description" name="product_description"/>
            <field column="picture" name="product_picture"/>
        </entity>
    </document>
</dataConfig>

5.重启tomcat,然后会看到如下页面

9.solrj客户端的使用(虽然solr提供数据库导入的方案,但是不推荐这么做,最好使用客户端操作solr索引)

solr服务端已配好,现在说一下使用solrj来维护solr的索引及操作,solrj就是一个Java的客户端,是一个jar包的使用。
首先引入MAVEN的依赖,solrj的版本号要对应solr的版本号

<dependency>
    <groupId>org.apache.solr</groupId>
    <artifactId>solr-solrj</artifactId>
    <version>5.5.3</version>
</dependency>

9.1增加及修改

首先说明,在solr中,增加与修改都是一回事,当这个id不存在时,则是添加,当这个id存在时,则是修改

代码很好理解,直接给出

private String serverUrl = "http://192.168.1.4:8080/solr/core1";
    /**
     * 增加与修改<br>
     * 增加与修改其实是一回事,只要id不存在,则增加,如果id存在,则是修改
     * @throws IOException 
     * @throws SolrServerException 
     */
    @Test
    public void upadteIndex() throws SolrServerException, IOException{
        //已废弃的方法
        //HttpSolrServer server = new HttpSolrServer("http://192.168.1.4:8080/solr/core1");
        //创建
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        SolrInputDocument doc = new SolrInputDocument();
        
        doc.addField("id", "zxj1");
        doc.addField("product_name", "javaWEB技术");
        doc.addField("product_catalog", "1");
        doc.addField("product_catalog_name", "书籍");
        doc.addField("product_price", "11");
        doc.addField("product_description", "这是一本好书");
        doc.addField("product_picture", "图片地址");
        
        client.add(doc);
        client.commit();
        
        client.close();
    }

9.2删除索引

删除的代码也直接给出,看代码里面的注释就可以了

/**
     * 删除索引
     * @throws Exception
     */
    @Test
    public void deleteIndex()throws Exception{
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        
        //1.删除一个
        client.deleteById("zxj1");
        
        //2.删除多个
        List<String> ids = new ArrayList<>();
        ids.add("1");
        ids.add("2");
        client.deleteById(ids);
        
        //3.根据查询条件删除数据,这里的条件只能有一个,不能以逗号相隔
        client.deleteByQuery("id:zxj1");
        
        //4.删除全部,删除不可恢复
        client.deleteByQuery("*:*");
        
        //一定要记得提交,否则不起作用
        client.commit();
        client.close();
    }

9.3查询

查询稍微复杂一点,但是与solr管理界面的条件一致

  • q - 查询字符串,如果查询所有: (id:1)
  • fq - (filter query)过虑查询,过滤条件,基于查询出来的结果
  • fl - 指定返回那些字段内容,用逗号或空格分隔多个。
  • start - 分页开始
  • rows - 分页查询数据
  • sort - 排序,格式:sort=<field name>+<desc|asc>[,<field name>+<desc|asc>]… 。示例:(score desc, price asc)表示先 “score” 降序, 再 “price” 升序,默认是相关性降序。
  • wt - (writer type)指定输出格式,可以有 xml, json, php, phps。
  • fl表示索引显示那些field( *表示所有field,如果想查询指定字段用逗号或空格隔开(如:Name,SKU,ShortDescription或Name SKU ShortDescription【注:字段是严格区分大小写的】))
  • q.op 表示q 中 查询语句的 各条件的逻辑操作 AND(与) OR(或)
  • hl 是否高亮 ,如hl=true
  • hl.fl 高亮field ,hl.fl=Name,SKU
  • hl.snippets :默认是1,这里设置为3个片段
  • hl.simple.pre 高亮前面的格式
  • hl.simple.post 高亮后面的格式
  • facet 是否启动统计
  • facet.field 统计field
  1. “:” 指定字段查指定值,如返回所有值:
  2. “?” 表示单个任意字符的通配
  3. “*” 表示多个任意字符的通配(不能在检索的项开始使用*或者?符号)
  4. “~” 表示模糊检索,如检索拼写类似于”roam”的项这样写:roam~将找到形如foam和roams的单词;roam~0.8,检索返回相似度在0.8以上的记录。
  5. 邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
  6. “^” 控制相关度检索,如检索jakarta apache,同时希望去让”jakarta”的相关度更加好,那么在其后加上”^”符号和增量值,即jakarta^4 apache
  7. 布尔操作符AND、||
  8. 布尔操作符OR、&&
  9. 布尔操作符NOT、!、- (排除操作符不能单独与项使用构成查询)
  10. “+” 存在操作符,要求符号”+”后的项必须在文档相应的域中存在
  11. ( ) 用于构成子查询
  12. [] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO 200710]

给出基本的代码看一下,仅仅作为一个基本的查询,高级的查询,各位要自己结合文档

package zxj.solrj;

import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.junit.Test;

/**
 * 搜索
 * @author Administrator
 *
 */
public class IndexSearch {

    private String serverUrl = "http://192.168.1.4:8080/solr/core1";
    @Test
    public void search()throws Exception{
        HttpSolrClient client = new  HttpSolrClient(serverUrl);
        
        //创建查询对象
        SolrQuery query = new SolrQuery();
        //q 查询字符串,如果查询所有*:*
        query.set("q", "product_name:小黄人");
        //fq 过滤条件,过滤是基于查询结果中的过滤
        query.set("fq", "product_catalog_name:幽默杂货");
        //sort 排序,请注意,如果一个字段没有被索引,那么它是无法排序的
//        query.set("sort", "product_price desc");
        //start row 分页信息,与mysql的limit的两个参数一致效果
        query.setStart(0);
        query.setRows(10);
        //fl 查询哪些结果出来,不写的话,就查询全部,所以我这里就不写了
//        query.set("fl", "");
        //df 默认搜索的域
        query.set("df", "product_keywords");
        
        //======高亮设置===
        //开启高亮
        query.setHighlight(true);
        //高亮域
        query.addHighlightField("product_name");
        //前缀
        query.setHighlightSimplePre("<span style='color:red'>");
        //后缀
        query.setHighlightSimplePost("</span>");
        
        
        //执行搜索
        QueryResponse queryResponse = client.query(query);
        //搜索结果
        SolrDocumentList results = queryResponse.getResults();
        //查询出来的数量
        long numFound = results.getNumFound();
        System.out.println("总查询出:" + numFound + "条记录");
        
        //遍历搜索记录
        //获取高亮信息
        Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
        for (SolrDocument solrDocument : results) {
            System.out.println("商品id:" + solrDocument.get("id"));
            System.out.println("商品名称 :" + solrDocument.get("product_name"));
            System.out.println("商品分类:" + solrDocument.get("product_catalog"));
            System.out.println("商品分类名称:" + solrDocument.get("product_catalog_name"));
            System.out.println("商品价格:" + solrDocument.get("product_price"));
            System.out.println("商品描述:" + solrDocument.get("product_description"));
            System.out.println("商品图片:" + solrDocument.get("product_picture"));

            //输出高亮 
            Map<String, List<String>> map = highlighting.get(solrDocument.get("id"));
            List<String> list = map.get("product_name");
            if(list != null && list.size() > 0){
                System.out.println(list.get(0));
            }
        }
        
        client.close();
    }
}
  • 注意:没有索引的域,是不能用作排序的
  • 安全:因为此界面涉及到位solr增减核心等管理操作,在实际产品上运行时,尽量设置禁用在公网上(通过ip或者域名)的访问,需要使用时再临时打开。

10.使用技巧

10.1模糊条件查询

在solr的分词配置后成功后,在solr后台管理界面进行模糊查询的时候会存在分词匹配个数的问题。打个简单的比方:搜索兰州XXXX酒店。 往往这个时候就有一大批数据出来,只要包含了分词后的词的数据都会搜索出来,给客户的体验不怎么好,本来客户是想只展示兰州的XXXX酒店的,结果北京的、广州的,还有其他名称的酒店都给搜索出来。这个时候就是分词的匹配个数设置的问题了。

在solr 的schema.xml中把 solrQueryParser 的defaultOperator 变成AND (默认这个参数是被注释掉的,找到后改一下就可以了)

<solrQueryParser defaultOperator="AND"/>

10.2模糊关键字查询

使用ik分词器分词中英文,分词“javaWEB”,想要查询“java”关键字

solrj

www.htsjk.Com true http://www.htsjk.com/solr/37912.html NewsArticle Solr实战, solr版本5.5.3, tomcat版本8.0,jdk1.7,操作系统centos7 转载自  https://segmentfault.com/a/1190000012754074 可访问网址 http://archive.apache.org/dis... 进行版本的下载,这里我下载的是5.5.3的版...
相关文章
    暂无相关文章
评论暂时关闭