May 10, 2018

apache solr实践之部署,分片,集合

本章介绍一个很流行的搜索引擎---apache solr,现在最流行的搜索引擎非solr和ES必属,本文从应用入手介绍solr的部署和基本应用。

solr入门基本概念

Collections
SolrCloud集群中的一个完整的逻辑上的倒排索引(什么是倒排索引?),和一个独立的config set相关联,由一个或者多个shard组成,shard可以在不同的服务器上,shard对搜索接口的调用者来说是隐形的,搜索者不用考虑在搜索时如何指定shard,只需要传入Collection名即可。
Config Set
包含两个最根本的配置文件:solrconfig.xml和schema.xml,视这两个文件的内容而定是否需要包含其他文件。SolrCloud的config set目录会上传到zookeeper中,而传统单机Solr的config set是保存在本地文件夹中。
Core
一个Solr Core是一个包含索引和配置文件的运行实例,以前Solr Core是单例模式的,后来重构成了多实例的,(什么是SolrCores?)。一个Replica对应一个Core实例,同一个Shard对应的Replica的Core的配置和索引数据是一样的,但是是不同实例。
Replica
Shard的一个副本。一个Shard会在不同的服务器上保留Repicas(副本),通过选举机制(和zookeeper的leader选举机制类似)在Replicas(副本)中选出一个leader来对外提供服务。leader连不上了就重新选其他副本作为leader,这样能保证至多(副本数-1)台服务器挂掉后仍然能正常工作。
Shard
Collection的一个逻辑分片。每个Shard对应一个Core,并且包含一个索引(Collection)的文档(Documents)的不相交子集,一个Shard由至少一个Replica组成,当有多个Replicas时,选举机制选出作为leader的Replica。单机Solr中,Shard指的是Solr cores.
Zookeeper
分布式集群的基本组件,MapReduce、HDFS、Hive等分布式系统都基于它,Leader选举也要靠它。Solr有自己的内嵌Zookeeper,但是一般不会用内嵌的。部署Zookeeper至少需要3台主机(出于节约成本,可以和Solr实例部署在相同的服务器上,目前很多Solr users都是这么用的)。

配置

CentOS Linux release 7.4.1708 (Core)
jdk-7u80-linux-x64
zookeeper-3.4.11.tar.gz
solr-5.2.1.tgz

各个术语之间对应关系图:

创建上图collection对应的配置为:
numShards=2
replicationFactor=3
maxShardsPerNode=2
liveSolrNode=3

1.上传solr到linux并解压,solr目录如下(只需了解红线部分,其他忽略。):

2.sorl的server目录是重点:

3.复制server\lib\ext内log4j-1.2.17.jar包到server\solr-webapp\webapp\WEB-INF\lib,
复制contrib\analysis-extras\lucene-libs内lucene-analyzers-smartcn-5.2.1.jar包到server\solr-webapp\webapp\WEB-INF\lib

4.修改server\solr-webapp\webapp\WEB-INF\web.xml,配置solr home

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

5.新建solrHome文件夹server/qyswfx文件夹,并保证该文件夹有solr.xml和zoo.cfg配置文件:

6.从solr-5.2.1/server/solr/configsets/复制一份data_driven_schema_configs配置文件夹qyswfx,并修改solrconfig.xml和schema.xml文件:

6.1配置solrconfig.xml,这里只展示真正修改的代码片段,文件在这里: solrconfig.xml
设置索引插入时的提交方式为服务端提交。autoCommit为15000ms提交一次,autoSoftCommit为1000ms或doc数量>=1000时提交一次

                  
<updateHandler class="solr.DirectUpdateHandler2">
    <updateLog>
      <str name="dir">${solr.ulog.dir:}</str>
    </updateLog>
 
     <autoCommit> 
        <maxTime>${solr.autoCommit.maxTime:15000}</maxTime> 
        <openSearcher>false</openSearcher> 
     </autoCommit>

     <autoSoftCommit> 
        <maxDocs>1000</maxDocs>  
        <maxTime>${solr.autoSoftCommit.maxTime:1000}</maxTime> 
     </autoSoftCommit>

</updateHandler>
                  
                

6.2配置schema.xml,这里只展示真正修改的代码片段,文件在这里: schema.xml
schema.xml作用:Solr stores details about the field types and fields it is expected to understand in a schema file. The name and location of this file may vary depending on how you initially configured Solr or if you modified it later.
根据业务需求定制schema.xml:给一个数据库表并指定表里的若干字段,将表里的数据导入索引集合。因为字段名是动态的,所以要使用dynamicField

                  
  <fields>
    <field name="_version_" type="long" indexed="true" stored="true"/>
    <field name="text" type="text_smartcn" indexed="true" stored="false" multiValued="true"/>
    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
  </fields>
  
  <!-- 动态字段,用于后台维护索引字段,不可索引部分 -->  
  <dynamicField name="*_i"  type="int"    indexed="false"  stored="true"/>
  <dynamicField name="*_s"  type="string"  indexed="false"  stored="true"/>
  <dynamicField name="*_l"  type="long"   indexed="false"  stored="true"/>
  <dynamicField name="*_d" type="double" indexed="false"  stored="true"/>
  <dynamicField name="*_f"  type="float"  indexed="false"  stored="true"/>
  <dynamicField name="*_b"  type="boolean" indexed="false" stored="true"/>
  <dynamicField name="*_text" type="text_general"   indexed="false"  stored="true"/>
  <dynamicField name="*_textcn"  type="text_smartcn"    indexed="false"  stored="true"/>
  
  <!-- 动态字段,用于后台维护索引字段,可索引部分 -->  
  <dynamicField name="*_i_i"  type="int"    indexed="true"  stored="true"/>
  <dynamicField name="*_i_s"  type="string"  indexed="true"  stored="true"/>
  <dynamicField name="*_i_l"  type="long"   indexed="true"  stored="true"/>
  <dynamicField name="*_i_d" type="double" indexed="true"  stored="true"/>
  <dynamicField name="*_i_f"  type="float"  indexed="true"  stored="true"/>
  <dynamicField name="*_i_b"  type="boolean" indexed="true" stored="true"/>
  <dynamicField name="*_i_text" type="text_general"   indexed="true"  stored="true"/>
  <dynamicField name="*_i_textcn"  type="text_smartcn"    indexed="true"  stored="true"/>
  
  <!-- 文档的唯一标识,可理解为主键,除非标识为required="false", 否则值不能为空-->  
  <uniqueKey>id</uniqueKey>
                  
                

6.3配置schema.xml的中文分词器

                  
    <fieldType name="text_smartcn" class="solr.TextField" positionIncrementGap="100">
    <!--  solr自带中文分词器 -->
    <analyzer type="index" isMaxWordLength="true">
      <tokenizer class="solr.SmartChineseSentenceTokenizerFactory" />
      <filter class="solr.SmartChineseWordTokenFilterFactory" />
    </analyzer>
    <analyzer type="query" isMaxWordLength="true">
      <tokenizer class="solr.SmartChineseSentenceTokenizerFactory" />
      <filter class="solr.SmartChineseWordTokenFilterFactory" />
    </analyzer>
    </fieldType>
                  
                

////////////////////////////上面solr基本配置完成,下面介绍SolrCloud的配置////////////////////////////

7.配置solrhome目录下的solr.xml
只有当solr实例以集群的方式启动的时候,也就是启动带有参数-DzkRun 或 -DzkHost的时候,</solrcloud>才会起效。

                  
<?xml version="1.0" encoding="UTF-8" ?>

<solr>

  <solrcloud>

    <str name="host">${host:}</str>
    <int name="hostPort">${jetty.port:8983}</int>
    <str name="hostContext">${hostContext:solr}</str>

    <!--zk地址列表-->
    <str name="zkHost">111.230.211.90:2181,111.230.223.233:2181</str> 
    <int name="zkClientTimeout">${zkClientTimeout:30000}</int>

    <bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
    <int name="distribUpdateSoTimeout">${distribUpdateSoTimeout:600000}</int>
    <int name="distribUpdateConnTimeout">${distribUpdateConnTimeout:60000}</int>

  </solrcloud>

  <shardHandlerFactory name="shardHandlerFactory"
    class="HttpShardHandlerFactory">
    <int name="socketTimeout">${socketTimeout:600000}</int>
    <int name="connTimeout">${connTimeout:60000}</int>
  </shardHandlerFactory>

</solr>

                  
                

8.因为上传配置文件到要求solr必须以cloud的方式启动,所以以solr cloud的方式在solrHome启动solr
我们暂时只有2个节点:111.230.211.90; 111.230.223.233,端口都是2181。

                  
.bin/solr start -c -s /usr/solr-5.2.1/server/qyswfx -p 8983 -z 111.230.211.90:2181,111.230.223.233:2181
//如果需要停止solr服务,使用下面命令
.bin/solr stop -all
                  
                

启动成功后信息如下:

                  
[root@VM_0_12_centos bin]# ./solr start -c -s /usr/solr-5.2.1/server/qyswfx -p 8983 -z 111.230.211.90:2181,111.230.223.233:2181
Waiting to see Solr listening on port 8983 [/]  
Started Solr server on port 8983 (pid=11211). Happy searching!
                  
                

9.利用zkcli上传配置文件夹到zk集群,供后面创建collection使用。
-zkhost指定ZooKeeper地址,逗号分割,-confdir为配置文件目录。-confname指定该配置的名称。

                  
server/scripts/cloud-scripts/zkcli.sh -zkhost 111.230.211.90:2181,111.230.223.233:2181 -cmd upconfig -confname qyswfx_conf -confdir server/qyswfx/qyswfx_configs/conf

//查看命令  
server/scripts/cloud-scripts/zkcli help 
//查看zk配置文件信息
server/scripts/cloud-scripts/zkcli -zkhost 111.230.211.90:2181,111.230.223.233:2181 -cmd list
                  
                

上传成功后部分信息如下:

                  
 /configs/qyswfx_conf/mapping-FoldToASCII.txt
INFO  - 2018-03-22 12:57:12.382; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/protwords.txt
INFO  - 2018-03-22 12:57:12.395; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/spellings.txt
INFO  - 2018-03-22 12:57:12.402; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/elevate.xml
INFO  - 2018-03-22 12:57:12.409; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/stopwords.txt
INFO  - 2018-03-22 12:57:12.421; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/solrconfig.xml
INFO  - 2018-03-22 12:57:13.750; org.apache.solr.common.cloud.SolrZkClient; makePath /configs/qyswfx_conf/update-script.js
INFO  - 2018-03-22 12:57:13.761; org.apache.zookeeper.ZooKeeper; Session: 0x2001ceb33a0000 closed
INFO  - 2018-03-22 12:57:13.761; org.apache.zookeeper.ClientCnxn$EventThread; EventTread shut down
                  
                

10.通过http协议与solr交互(可以在浏览器栏测试,生产中我们使用代码自动化执行。),使用上传的配置文件qyswfx_conf,创建一个collection集合,分片数量numShards=2,复制因子replicationFactor=2

                  
//如果你在1台机器:111.230.211.90:8983部署了solr
http://111.230.211.90:8983/solr/admin/collections?action=CREATE&name=collection_hmdcx&numShards=2&replicationFactor=1&maxShardsPerNode=2&collection.configName=qyswfx_conf

//如果你在2台机器:111.230.211.90:8983,111.230.223.233:8983都部署了solr
http://111.230.211.90:8983/solr/admin/collections?action=CREATE&name=collection_hmdcx&numShards=2&replicationFactor=2&maxShardsPerNode=2&collection.configName=qyswfx_conf
                  
                

numShards: collection分成多少片shard
replicationFactor:每片shard由多少个复制组成,(replicationFactor=1表示每份shard只有1份,replicationFactor=2表示每份shard有2份,1份数据节点,1份备份节点)
maxShardsPerNode: 对于某个collection,每个节点允许的最大分片数
liveSolrNode:当前存活的solr节点
注意:一个正常的solrCloud集群不容许一个liveSolrNode上部署同一个shard的多个replic,因此正确时因满足以下条件:numShards*replicationFactor<liveSolrNode*maxShardsPerNode

11.删除collection集合collection_hmdcx

                  
http://111.230.211.90:8983/solr/admin/collections?action=DELETE&name=collection_hmdcx
                  
                

12.在webapp控制台查看我们创建的collection集合:

12.关于solr控制台webapp由solr内置jetty启动还是放到tomcat里面的问题,个人认为还是由jetty启动该webapp,原因如下:
(1)在业务上,tomcat用来运行我们项目的webapp,版本发行的时候需要重启,我们的搜索服务在业务场景上应该跟它剥离。
(2)在技术上,使用jetty来运行solr控制台webapp,一样可以做访问控制/二次定制。