zoukankan      html  css  js  c++  java
  • solr

    一. solr的启动方式

    1. start.jar启动

      cd  solr-4.10.4example
      java -jar start.jar
      java -Djetty.port=8980  -jar start.jar  #指定端口  --daemon 后台运行
      #####  java -jar --help 执行帮助命令  #####
      
    2. bin/solr执行

      不加参数有提示
      bin/solr   start   -p  8983     # 开启指定端口的solr
      bin/solr   stop   -p  8983      # 关闭指定端口的solr
      
    3. tomcat启动solr
      (1)建立一个solr的运行目录
      例如:D:solr-tomcat
      将下载的solr-4.10.4中的solr-4.10.4example目录下的solr文件夹拷贝到D:solr-tomcat目录下
      (2)建立JNDI文件
      在tomcat的confCatalinalocalhost目录下建立文件solr.xml

      <Context path="/solr" docBase="D:apache-tomcat-8.0.15solr.war"> 
          <Environment name="solr/home" type="java.lang.String" value="D:solr-tomcatsolr" override="true"/> 
      </Context>
      

      (3)部署solr.war包
      把solr-4.10.4中dist目录中的solr-4.10.4.war包拷贝到tomcat的根目录下,名字改为solr.war

      (4)配置日志
      如果不配置的话,启动会报错,无法访问solr平台,查看localhost.2015-01-01.log日志。
      把solr-4.10.4examplelibext目录下的jar包都拷贝到tomcat的lib目录下即可。
      访问http://localhost:8080/solr/

    二. solr的目录配置

    1. example目录是solr项目的根目录
      若根目录改名, 启动方式如下:
      a) bin/solr -s 没目录名
      b) cd 指定目录 & java -jar start.jar

    2. example/solr目录 : (start.jar同级目录下的solr目录 )
      若改变索引库目录, 启动方式如下:
      a) java -Dsolr.solr.home=(对于start.jar的相对路径) -jar start.jar
      b) solr start -s (对于start.jar的相对路径)

    3. example/solr-webapp 目录
      solr项目的部署位置 , solr启动后把 examplewebappssolr.war拷贝到 examplesolr-webappwebapp下面

    三. scchemal文件

    1. field : 静态字段
      (1)name:字段名
      (2)type:之前定义过的各种FieldType
      (3)indexed:是否被索引
      (4)stored:是否被存储(如果不需要存储相应字段值,尽量设为false)
      (5)multiValued:是否有多个值(对可能存在多值的字段尽量设置为true,避免建索引时抛出错误)

      <field name="_version_" type="long" indexed="true" stored="true"/>
      
    2. Dynamic Fields : 动态字段
      动态字段建立的索引存储规则 , 所有匹配到的字段名都会按照这种方式建立索引

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

    匹配规则 :
    (1)如果一个field的名字没有匹配到,那么就会用动态field试图匹配定义的各种模式。
    (2)""只能出现在模式的最前和最后
    (3)较长的模式会被先去做匹配 :
    (4)<dynamicField name="
    _ss>比<dynamicField name="*_s>先匹配
    (5)如果2个模式同时匹配上,最先定义的优先
    3. copyField : 拷贝字段
    (1)将多个field的数据放在一起同时搜索,提供速度
    (2)将一个field的数据拷贝到另一个,可以用2种不同的方式来建立索引。

    ```xml
    <field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>  <!--组合字段要声明成multiValued="true"-->
    <copyField source="cat" dest="text"/>   <!--cat name text是上文建立好的静态字段-->
    <copyField source="name" dest="text"/>
    ```
    

    应用场景 :
    比如现在要查询包涵"Java"的博客, 那么你肯定要查内容,标题是否包含Java,但是solr不能像SQL那样,
    where tittle like '%Java%' or content like '%Java%'. 这个时候copyField就派上用场了,
    定义一个新字段,将title和content 复制到这个新字段,索引的时候,直接从这个新字段查询,这样就达到目地了。

    1. fieldType : 字段类型
      <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true" />
      <!--声明字段类型 , 供<field>引用-->
      

    【注】: solr中1个core是一个数据库 , 称作为collection。每一个collection包含一个schemal.xml , 用于描述索引结构

    五. 查询语法

    1. id:aaa [AND][OR] name:lj : 交集并集
    2. price:[0 TO 93] : 范围查询 []闭区间,{}开区间
    3. filterquery : 把第一次查询结果进行缓存
    4. sort : 类似于mysql的order by price desc
    5. start,rows : 相当于limit关键字
    6. fl : 指定查询的字段
    7. df : default field 默认查询字段
    8. facet.query : 相当于group by price:[0 TO 100]
      ROW.QUERY.PARAMETER : facet.query = price:[0 TO 100] && price:{100 TO 100]
    9. facet.field : 分组字段 // name
    10. facet.prefix : 字段值前缀 // a
    11. Request-Handler : 配置的解析引擎
      /select :
      /spell : 实现拼写检查

    六. 分词器

    1. 分词器 : 把一段文本按照一定规则进行切分

       <fieldType name="text_nl" class="solr.TextField" positionIncrementGap="100">
          <analyzer> 
              <tokenizer class="solr.StandardTokenizerFactory"/>
              <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_nl.txt" format="snowball" />
          </analyzer>
      </fieldType>
      
    2. 分词器的一般工作流程:
      (1)切分关键词
      (2)去除停用词
      (3)对于英文单词,把所有字母转为小写(搜索时不区分大小写)

    七. IKAnalyzer整合solr

    1. 整合 : 通过页面上的Analyse测试效果
      (1)下载IK工具包
      (2)上传服务器,并解压,使用unzip命令
      (3)IKAnalyzer2012FF_u1.jar 拷贝到solr-web项目的lib目录下面

      cp IKAnalyzer2012FF_u1.jar solr-4.10.4/example/solr-webapp/webapp/WEB-INF/lib/
      

    (4)IKAnalyzer.cfg.xml和stopword.dic 拷贝到solr-web项目的类路径下
    注意:项目的类路径是指WEB-INF下面的classes目录,但是这个目录现在是不存在的,所以需要手工创建。
    shell cp IKAnalyzer.cfg.xml solr-4.10.4/example/solr-webapp/webapp/WEB-INF/classes/ cp stopword.dic solr-4.10.4/example/solr-webapp/webapp/WEB-INF/classes/
    (5)修改schem.xml文件(solr-4.10.4/example/solr/collection1/conf/schema.xml)
    xml <!--配置IK分词器--> <fieldType name="text_ik" class="solr.TextField"> <!--索引时候的分词器--> <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/> <!--查询时候的分词器--> <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
    (6)重启solr即可

    1. 自定义词库
      (1)首先要有一个自定义字典,my.dic
      自定义字典中的一行代表一个词语
      注意:这个文件的编码必须是utf-8 without bom
      (2)把这个dic文件上传到solrweb项目的类路径下
      (3)修改ik的配置文件(IKAnalyzer.cfg.xml)
      <properties>
          <comment>IK Analyzer 扩展配置</comment>
          <!--用户可以在这里配置自己的扩展字典 -->
          <entry key="ext_dict">my.dic;</entry>
          <!--用户可以在这里配置自己的扩展停止词字典-->
          <entry key="ext_stopwords">stopword.dic;</entry>
      </properties>
      

    (4)重启solr
    (5)(可选)添加多个自定义字典

    ```xml
    <entry key="ext_dict">my.dic;my1.dic;</entry>
    ```
    

    八. solr多core

    1. 界面操作
      core admin --> add core 界面上的unload可以让一个core下线,下线就是重命名core.properties为core.properties.unload
    2. 直接操作
      (1)cp example/solr/collection1 crxy
      (2)修改core.properties文件 : name=crxy

    九. SolrJ

    1. 实体类注解
      public class Article {  
            
          @Field     // 进行添加索引的属性加@Field注解  
          private String id;  
          @Field  
          private String title;  
            
          @Field  
          private String describe;  
            
          private String content;  
          @Field  
          private String author;  
          public String getId() {  
              return id;  
          }  
          public void setId(String id) {  
              this.id = id;  
          }  
          public String getTitle() {  
              return title;  
          }  
          public void setTitle(String title) {  
              this.title = title;  
          }  
          public String getContent() {  
              return content;  
          }  
          public void setContent(String content) {  
              this.content = content;  
          }  
          public String getAuthor() {  
              return author;  
          }  
          public void setAuthor(String author) {  
              this.author = author;  
          }  
          public String getDescribe() {  
              return describe;  
          }  
          public void setDescribe(String describe) {  
              this.describe = describe;  
          }  
            
      }  
      
    2. SolrUtil工具类
      public class SolrUtil {  
          static final Logger logger = LoggerFactory.getLogger(SolrUtil.class);  
          // shard分片下,无论连哪个地址都会查询所有shard  
          private static final String SOLR_URL = "http://192.168.182.130:7574/solr/collection1"; 
          private static HttpSolrServer server = null;  
          static{  
              try {  
                  server = new HttpSolrServer(SOLR_URL);  
                  server.setAllowCompression(true);  
                  server.setConnectionTimeout(10000);  
                  server.setDefaultMaxConnectionsPerHost(100);  
                  server.setMaxTotalConnections(100);  
              } catch (Exception e) {  
                  logger.error("请检查tomcat服务器或端口是否开启!{}",e);  
                  e.printStackTrace();  
              }  
          }  
          /** 
           * 建立索引 
           * @throws Exception 
           */  
          public static void addIndex(Article article) {  
              try {  
                  server.addBean(article);  
                  server.commit(true,true,true);  // 第三个true代表软提交  
              } catch (IOException e) {  
                  e.printStackTrace();  
              } catch (SolrServerException e) {  
                  e.printStackTrace();  
              }  
          }  
            
          /** 
           * 查询 
           */  
          @SuppressWarnings("unchecked")  
          public static Map<String,Object> search(String skey, Long start, Long row) throws Exception {  
              // schema.xmml中设置了id为uniquekey,增加索引时,如果id相同则更新索引,id不同则新增索引  
              SolrQuery param = new SolrQuery();  
              param.set("q","text:"+skey);  
              //param.set("fq","title:"title1"");   // fq与q的查询内容取交集,并把fq的内容缓存  
              param.addFacetField("title");  //按照title字段分组  
              param.setStart(start.intValue());  
              param.setRows(row.intValue());  
        
              param.setHighlight(true);  
              param.addHighlightField("title");  //给查询出title字段家高亮  
              param.addHighlightField("describe");  
              param.setHighlightSimplePre("<font color='red'>");  
              param.setHighlightSimplePost("</font>");  
        
              QueryResponse reponse = server.query(param);  
              List<Article> articleLi = reponse.getBeans(Article.class);  //  
              long numFound = reponse.getResults().getNumFound();  
        
              Map<String, Map<String, List<String>>> highlighting = reponse.getHighlighting(); // <id,{"title":"{list}","describe":{list}}>>  
              for (Article article : articleLi) {  
                  String id = article.getId();  
                  Map<String, List<String>> map = highlighting.get(id);  
        
                  List<String> titles = map.get("title");  
                  if(CollectionUtils.isNotEmpty(titles)){  
                      article.setTitle(titles.get(0));  
                  }  
        
                  List<String> describes = map.get("describe");  
                  if(CollectionUtils.isNotEmpty(describes)){  
                      article.setDescribe(describes.get(0));  
                  }  
              }  
        
              HashedMap hashedMap = new HashedMap();  
              hashedMap.put("dataList",articleLi);  
              hashedMap.put("nummFound",numFound);  
              System.out.println(hashedMap);  
              return hashedMap;  
          }  
            
          /** 拼写检查 */  
          public static void checkSpell(){  
              SolrQuery param = new SolrQuery();  
              param.set("q","title:title1");  
              param.set("qt","/spell");  
              try {  
                  QueryResponse response = server.query(param);  
                  SolrDocumentList results = response.getResults();  
                  long numFound = results.getNumFound();  
                  if(numFound==0){  
                      List<SpellCheckResponse.Suggestion> suggestions = response.getSpellCheckResponse().getSuggestions();  
                      for (SpellCheckResponse.Suggestion suggestion : suggestions) {  
                          int suggestNum = suggestion.getNumFound();  
                          System.out.printf("推荐词个数:"+suggestNum);  
                          List<String> list = suggestion.getAlternatives();  
                          for (String s : list) {  
                              System.out.println(s);  
                          }  
                      }  
                  }else{  
                      for (SolrDocument result : results) {  
                          Collection<String> fieldNames = result.getFieldNames();  
                          for (String fieldName : fieldNames) {  
                              Object value = result.get(fieldName);  
                              System.out.println("字段名:"+fieldName+",字段值:"+value);  
                          }  
                          System.out.println("===================================================");  
                      }  
                  }  
              } catch (SolrServerException e) {  
                  e.printStackTrace();  
              }  
          }  
        
          public static void main(String[] args) {  
              checkSpell();  
          }  
      }  
      

    十. solr时间问题

    solr的时间 , 页面上显示时间比真实事件少8小时, java代码操作的话没问题

    十一. solr的主从结构 (解决高并发响应速度慢的问题)

    1. master节点

      <lst name="master">            <!-- 主从结构时主节点应该打开此处配置-->
           <str name="replicateAfter">commit</str> <!--solrserver.commit()后从节点开始同步索引-->
           <str name="replicateAfter">startup</str> <!--从节点重启后开始同步索引-->
           <str name="confFiles">schema.xml,stopwords.txt</str>
      </lst>
      
    2. slave节点

      <lst name="slave">  <!--主从结构时,从节点修改的配置-->
           <str name="masterUrl">http://your-master-hostname:8983/solr/collection1</str><!--配置主节点url,-->
           <str name="pollInterval">00:00:60</str><!--每隔60--秒同步一次-->
      </lst>
      
    3. 动态切换主从角色 : 只需要把所有节点上面的配置都统一修改为下面配置即可

      <lst name="${master:master}">
           <str name="replicateAfter">commit</str>
           <str name="replicateAfter">startup</str>
           <str name="confFiles">schema.xml,stopwords.txt</str>
      </lst>
      <lst name="${slave:slave}">
           <str name="masterUrl">http://${masterurl}:8983/solr</str>
           <str name="pollInterval">00:00:60</str>
      </lst>
      
    4. 这样在启动的时候

      启动主节点:java -Dslave=disabled -Dmasterurl  -jar start.jar 
      启动从节点:java -Dmaster=disabled -Dmasterurl=192.168.1.170  -jar start.jar
      

    十二. solrcloud操作solr集群

    String zkHost = "192.168.1.170:2181,192.168.1.171:2181";
    CloudSolrServer server = new CloudSolrServer(zkHost );
    server.setDefaultCollection("collection1");
    SolrQuery query = new SolrQuery();
    query.set("q", "*:*");
    QueryResponse response = server.query(query);
    SolrDocumentList results = response.getResults();
    

    十三. solr的提交方式

    1. 代码手动提交 :
      (1)硬提交 : 把索引到硬盘中 (写index文件)

      httpSolrServer.commit();
      

    (2)软提交 :
    索引库中没有 , 但是能查询到 (软提交把数据提交到内存) , 但是会产生提交的log日志 , 在下次启动solr时,solr根据提交日志, 把数据恢复到index目录中 , 所以数据不会丢失. 这是一种兼顾实时性与性能的这种选择 (写log文件)
    java httpSolrServer.commit(true,true,true);
    2. 自动硬提交触发时,软提交的数据从内存刷到文件中
    (1)自动硬提交 :
    代码中不执行commit() , 每隔15秒提交一次索引到硬盘 , 或记录达到10000条自动提交 . 这种自动提交 , 如果false , 相当于没有重新刷新索引 , 所以自动提交后还是查不到. openSearch消耗性能,所以应该配置maxDoc与maxTime尽量大(solr中必须设置自动硬提交, 否则代码的软提交没法写成index索引文件 , 只是log文件+内存中的数据, 可能造成内存溢出 )

    ```xml
    <autoCommit> 
      <maxTime>${solr.autoCommit.maxTime:15000}</maxTime> 
     <!--  <maxDocs>10000</maxDocs>  -->
      <openSearcher>false</openSearcher> 
    </autoCommit>
    ```
    

    (2)自动软提交 (每隔多长时间吧内存中的数据写一次log日志)

    ```xml
    <autoSoftCommit> 
      <maxTime>${solr.autoSoftCommit.maxTime:1000}</maxTime> 
    </autoSoftCommit>
    ```
    
    
    
    【注】: 通常配置1-10分钟自动硬提交 , 每秒软提交
    关于存储字段和索引字段 : 例如sql: select id , auth from tableA where content='aa'  此时content作为索引字段进行查询(index=true),id.auth作为存储字段显示(stored=true)
    将多个索引文件合并成1个索引文件,避免发生too many files一场(linux系统抛出) httpSolrServer.optimize()代码 (消耗性能,应在夜晚执行)
    精确查询 : 不对查询字段的值进行分词 , params.set("q",content:"刘德华")
    

    十四. Solr与Hbase (hbase通过行健查询很快)

    1. 配置solrschema.xml : 修改field字段

      field name index store
      id index:true store:true
      title index:true store:true
      author index:false store:true
      describe index:true store:true
      content 该字段内容很多,index:false store:false
    2. 配置ik分词器
      (1)复制IkAnalyzer.jar到 solr-webapp/webapp/web-inf/lib
      (2)拷贝IKAnalyzer.cfg.xml和stopword.dic到solr-webapp/webapp/web-inf/目录下
      (3)修改schema.xml配置中文分词器

      <!--配置IK分词器-->  
      <fieldType name="text_ik" class="solr.TextField">  
          <!--索引时候的分词器-->  
          <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>  
          <!--查询时候的分词器-->  
          <analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>  
      </fieldType>  
      
      
  • 相关阅读:
    关于用户体验的几张图片
    上下翻滚JS特效代码
    关注程序员健康之——缺失营养时的六种信号
    C#基础知识系列之——for循环
    关于程序中的需求的变化,责任的分配
    Silverlight学习之——Canvas对象
    还是觉得应该动手写点东西....
    怎样理解“道不同,不相为谋”这句话呢。。。
    UML图中最基本的是类图
    .NET中各种数据库连接大全
  • 原文地址:https://www.cnblogs.com/72808ljup/p/5564205.html
Copyright © 2011-2022 走看看