Solr应用

  Solr是apache的顶级开源项目,它是使用java开发 ,基于lucene的全文检索服务器。Solr比lucene提供了更多的查询语句,而且它可扩展、可配置,同时它对lucene的性能进行了优化。Solr和lucene有什么区别呢? 

  Lucene是一个全文检索引擎工具包,它只是一个jar包,不能独立运行与对外提供服务。 

   Solr是一个全文检索服务器,它可以单独运行在servlet容器上,可以单独对外提供搜索和索引功能。Solr比lucene在开发全文检索功能方面更快捷、更方便。

  那么,Solr是如何实现全文检索的呢? 

  索引流程:solr客户端(浏览器、java程序)可以向solr服务端发送POST请求,请求内容是包含Field等信息的一个xml文档,通过该文档,solr实现对索引的维护(增删改)。 

  搜索流程:solr客户端(浏览器、java程序)可以向solr服务端发送GET请求,solr服务器返回一个xml文档。

  在使用solr时,先要下载与安装solr(本文使用4.10.3版本),下载地址:http://archive.apache.org/dist/lucene/solr/。其中,Solr和lucene的版本是同步更新的。

  Linux下需要下载lucene-4.10.3.tgz,windows下需要下载lucene-4.10.3.zip。

  solr运行环境是:  

  Jdk:1.7及以上

 Solr:4.10.3

 Mysql:5X

 Web服务器:tomcat 7  

  将solr-4.10.3/dist下的solr-4.10.3.war包(为使用方便,将其更名为solr.war)拷贝到tomcat的webapps下,启动tomcat时,该war包会自动解压缩为名称为solr的文件夹,此时,将solr.war包删除。接下来,添加solr的扩展服务包,截图如下(jar包数量较多,部分显示):

  接下来,将log4j.properties等配置文件拷贝到如下路径:

  接下来,在web.xml中指定solrhome的目录:

 

<env-entry>
		<env-entry-name>solr/home</env-entry-name>
		<env-entry-value>E:\tomcat\apache-tomcat-7.0.53-8090\solrhome</env-entry-value>
		<env-entry-type>java.lang.String</env-entry-type>
</env-entry> 

  其中,Solrhome是solr服务运行的主目录,一个solrhome目录里面包含多个solrcore目录,一个solrcore目录里面包含了一个solr实例运行时所需要的配置文件和数据文件。每一个solrcore都可以单独对外提供搜索和索引服务。多个solrcore之间没有关系。solrhome的文件结构:

  solrcore的文件结构如下:

  在solrcore的conf文件下,找到solrconfig.xml文件,通过里面的lib标签来指定依赖包的地址: 

<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/clustering/lib/" regex=".*\.jar" />
  <lib dir="${solr.install.dir:..}/dist/" regex="solr-clustering-\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="${solr.install.dir:..}/contrib/dataimporthandler/lib" regex=".*\.jar" />   
  <lib dir="${solr.install.dir:..}/contrib/db/lib" regex=".*\.jar" /> 

  里面的“solr.install.dir”表示solrcore的安装目录。 

  再在solrcore的conf文件下找到schema.xml文件,加入如下配置信息: 

<!-- Chinese -->
	<fieldType name="text_zh" class="solr.TextField">
      <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"> </analyzer>
    </fieldType>
	<field name="content_zh" type="text_zh" indexed="true" stored="true"></field>	
	
	<field name="product_name" type="text_zh" indexed="true" stored="true"></field>
    <field name="product_catalog_name" type="text_zh" indexed="true" stored="true"></field>
	<field name="product_price" type="float" indexed="true" stored="true"></field>
	<field name="product_description" type="text_zh" indexed="true" stored="true"></field>	
	
    <field name="product" type="text_zh" indexed="true" stored="true" multiValued="true"></field>

	<copyField source="id" dest="product"/>
	<copyField source="product_name" dest="product"/>	
	<copyField source="product_catalog_name" dest="product"/>	
	<copyField source="product_price" dest="product"/>	
	<copyField source="product_description" dest="product"/>	 

  其中,product是测试搜索的数据。

  每个SolrCore都有自己的索引文件目录 ,默认在SolrCore目录下的data中。data数据目录下包括了index索引目录 和tlog日志文件目录。如果不想使用默认的目录也可以通过solrConfig.xml更改索引目录 ,如下: 

<dataDir>${solr.data.dir:E:/develop/solr/solrhome/solrcore/data}</dataDir> 

  在solrconfig.xml文件中,有个requestHandler标签,它是一个请求处理器,定义了索引和搜索的访问方式。通过/update维护索引,可以完成索引的添加、修改、删除操作;通过/select搜索索引;通过/dataimport可以导入数据库中的数据。如下: 

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

  在配置完solr后,启动tomcat,访问solr,界面如下:

   一个solr服务器可以配置多个solrcore,这样做的好处有:

  (1)在进行solrcloud的时候,必须配置多solrcore。

  (2) 每个solrcore之间是独立的,都可以单独对外提供服务;不同的业务模块可以使用不同的solrcore来提供搜索和索引服务。

  在使用solr时,要先在schema.xml文件中配置solrcore的一些数据信息,包括Field和FieldType的定义等信息,在solr中,Field和FieldType都需要先定义后使用。  

定义Field域
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> 
    Name:指定域的名称
    Type:指定域的类型
    Indexed:是否索引
    Stored:是否存储
    Required:是否必须
    multiValued:是否多值,比如商品信息中,一个商品有多张图片,一个Field像存储多个值的话,必须将multiValued设置为true。
----------------------------------------------
动态域
<dynamicField name="*_i"  type="int"    indexed="true"  stored="true"/>
    Name:指定动态域的命名规则
------------------------------------------------
指定唯一键
<uniqueKey>id</uniqueKey>
    其中的id是在Field标签中已经定义好的域名,而且该域要设置为required为true。
    一个schema.xml文件中必须有且仅有一个唯一键
-----------------------------------------------
复制域
<copyField source="cat" dest="text"/>
    Source:要复制的源域的域名
    Dest:目标域的域名
    由dest指的的目标域,必须设置multiValued为true。
-------------------------------------------------
定义域的类型
<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>
    Name:指定域类型的名称
    Class:指定该域类型对应的solr的类型
    Analyzer:指定分析器
    Type:index、query,分别指定搜索和索引时的分析器
    Tokenizer:指定分词器
    Filter:指定过滤器
-------------------------------------------------
使用ikanalyzer进行中文分词
<!-- Chinese -->
	<fieldType name="text_zh" class="solr.TextField">
      <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"> </analyzer>
    </fieldType>
	<field name="content_zh" type="text_zh" indexed="true" stored="true"></field> 

  我们在java程序中使用solr时,需要使用solrj,这是solr服务器的java客户端。其操作逻辑如下:

  接下来通过代码演示操作solr:  

package com.itszt.solr;

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

import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 测试solr
 */
public class TestUpdate {
    //products中,product_price的type为text_zh
    // //products2中,product_price的type为float
    //更换另一个solr-core

    //测试插入数据
    @Test
    public void testInsertData() throws IOException, SolrServerException {
        HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8090/solr/products2");
        SolrInputDocument solrInputDocument = new SolrInputDocument();
        solrInputDocument.addField("id","10086");
        solrInputDocument.addField("product_name","大红花");
        solrInputDocument.addField("product_price","28.89");
        solrInputDocument.addField("product_description","这朵大红花就是好好看");
        solrServer.add(solrInputDocument);
        solrServer.commit();
    }

    //测试更新数据
    @Test
    public void testUpdateData() throws IOException, SolrServerException {
        HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8090/solr/products2");
        SolrInputDocument solrInputDocument = new SolrInputDocument();
        solrInputDocument.addField("id","10086");
        solrInputDocument.addField("product_name","大红花");
        solrInputDocument.addField("product_price","28.79");
        solrInputDocument.addField("product_description","这朵大红花在加工后就是好好看");
        solrServer.add(solrInputDocument);
        solrServer.commit();
    }

    //测试删除数据
    @Test
    public void testDelteData() throws IOException, SolrServerException {
        HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8090/solr/products2");
        //solrServer.deleteById("10086");
        solrServer.deleteByQuery("product:10086");
        solrServer.commit();
    }

    //测试查询数据
    @Test
    public void testQueryDatas() throws SolrServerException {
        HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8090/solr/products2");
        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery("product_name:花儿");
        QueryResponse queryResponse = solrServer.query(solrQuery);
        SolrDocumentList results = queryResponse.getResults();
        for(SolrDocument result:results){
//            System.out.println("result = " + result);
            Collection<String> fieldNames = result.getFieldNames();
            for(String fieldName:fieldNames){
                System.out.println(fieldName+" ---> " + result.get(fieldName));
            }
        }
    }

    //测试查询高亮度显示的数据
    @Test
    public void testQueryDatasHl() throws SolrServerException {
        HttpSolrServer solrServer = new HttpSolrServer("http://localhost:8090/solr/products2");

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.setQuery("product_name:家居");
        solrQuery.setFields("product_name,product_price");
        solrQuery.setFilterQueries("product_price:[10 TO 100]");
        solrQuery.setSort("product_price",SolrQuery.ORDER.asc);
        solrQuery.setHighlight(true);
        solrQuery.set("hl.fl","product_name");

        QueryResponse queryResponse = solrServer.query(solrQuery);

        SolrDocumentList results = queryResponse.getResults();
        System.out.println("查询回来的数据量:" + results.size());

        for(SolrDocument result:results){
            Collection<String> fieldNames = result.getFieldNames();
            for(String fieldName:fieldNames){
                System.out.println(fieldName+"--->"+result.get(fieldName));
                System.out.println("----------------------");
            }
        }

        System.out.println("获取高亮数据:");
        Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
        Set<String> keySet1 = highlighting.keySet();
        for(String key1:keySet1){
            System.out.println("key1 = " + key1);
            Map<String, List<String>> map2 = highlighting.get(key1);
            System.out.println("map2 = " + map2);
            Set<String> keySet2 = map2.keySet();
            for(String key2:keySet2){
                System.out.println("key2 = " + key2);
            }
        }
    }
} 
1 概述 4 1.1 企业搜索引擎方案选型 4 1.2 Solr的特性 4 1.2.1 Solr使用Lucene并且进行了扩展 4 1.2.2 Schema(模式) 5 1.2.3 查询 5 1.2.4 核心 5 1.2.5 缓存 5 1.2.6 复制 6 1.2.7 管理接口 6 1.3 Solr服务原理 6 1.3.1 索引 6 1.3.2 搜索 7 1.4 源码结构 8 1.4.1 目录结构说明 8 1.4.2 Solr home说明 9 1.4.3 solr的各包的说明 10 1.5 版本说明 11 1.5.1 1.3版本 11 1.5.2 1.4版本 12 1.6 分布式和复制 Solr 架构 13 2 Solr的安装与配置 13 2.1 在Tomcat下Solr安装 13 2.1.1 安装准备 13 2.1.2 安装过程 14 2.1.3 验证安装 15 2.2 中文分词配置 15 2.2.1 mmseg4j 15 2.2.2 paoding 19 2.3 多核(MultiCore)配置 22 2.3.1 MultiCore的配置方法 22 2.3.2 为何使用多core ? 23 2.4 配置文件说明 23 2.4.1 schema.xml 24 2.4.2 solrconfig.xml 25 3 Solr应用 29 3.1 SOLR应用概述 29 3.1.1 Solr应用模式 29 3.1.2 SOLR的使用过程说明 30 3.2 一个简单的例子 30 3.2.1 Solr Schema 设计 30 3.2.2 构建索引 30 3.2.3 搜索测试 31 3.3 搜索引擎的规划设计 32 3.3.1 定义业务模型 32 3.3.2 定制索引服务 34 3.3.3 定制搜索服务 34 3.4 搜索引擎配置 34 3.4.1 Solr Schema 设计(如何定制索引的结构?) 34 3.5 如何进行索引操作? 36 3.5.1 基本索引操作 36 3.5.2 批量索引操作 37 3.6 如何进行搜索 39 3.6.1 搜索语法 39 3.6.2 排序 42 3.6.3 字段增加权重 42 3.6.4 Solr分词器、过滤器、分析器 42 3.6.5 Solr高亮使用 46 4 SolrJ的用法 46 4.1 搜索接口的调用实例 46 4.2 Solrj的使用说明 47 4.2.1 Adding Data to Solr 47 4.2.2 Directly adding POJOs to Solr 49 4.2.3 Reading Data from Solr 51 4.3 创建查询 51 4.4 使用 SolrJ 创建索引 52 4.5 Solrj包的结构说明 53 4.5.1 CommonsHttpSolrServer 53 4.5.2 Setting XMLResponseParser 53 4.5.3 Changing other Connection Settings 53 4.5.4 EmbeddedSolrServer 54 5 Solr的实际应用测试报告 54 5.1 线下压力测试报告 54 5.2 线上环境运行报告 54 6 solr性能调优 55 6.1 Schema Design Considerations 55 6.1.1 indexed fields 55 6.1.2 stored fields 55 6.2 Configuration Considerations 55 6.2.1 mergeFactor 55 6.2.2 mergeFactor Tradeoffs 56 6.3 Cache autoWarm Count Considerations 56 6.4 Cache hit rate(缓存命中率) 56 6.5 Explicit Warming of Sort Fields 56 6.6 Optimization Considerations 56 6.7 Updates and Commit Frequency Tradeoffs 56 6.8 Query Response Compression 57 6.9 Embedded vs HTTP Post 57 6.10 RAM Usage Considerations(内存方面的考虑) 57 6.10.1 OutOfMemoryErrors 57 6.10.2 Memory allocated to the Java VM 57 7 FAQ 58 7.1 出现乱码或者查不到结果的排查方法: 58
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值