2018年05月22日 18:01:45 哈皮狗 阅读数:51

Solr

1、solr是什么呢?

一、Solr它是一种开放源码的、基于Lucene Java 的搜索服务器,易于加入到 Web 应用程序中。

 二、Solr提供了层面搜索(就是统计)、命中醒目显示并且支持多种输出格式(包括XML/XSLT 和JSON等格式)。它易于安装和配置,而且附带了一个基于 HTTP 的管理界面。Solr已经在众多大型的网站中使用,较为成熟和稳定。

三、Solr包装并扩展了 Lucene,所以Solr的基本上沿用了Lucene的相关术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。

四、通过对Solr进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。

五、此外,很多Lucene 工具(如Nutch、 Luke)也可以使用Solr 创建的索引。可以使用 Solr的表现优异的基本搜索功能,也可以对它进行扩展从而满足企业的需要。

2、solr的优点

solr的优点包括以下几个方面:

        1、高级的全文收索功能;

2、传为高通量的网络流量进行的优化;

3、基于开放接口(xml和http)的标准;

4、综合的html管理界面;

5、可伸缩-能够有效的复制到另外一个solr收索服务器;

6、使用xml配置达到灵活性和适配性;

7、可扩展的插件体系。

以下是solr的架构图:

 

 

绿色的就是lucene的模块,而蓝色的就是solr扩展了lucene。从图上可以看出以下几点:

a. 一个真正的拥有动态字段(DynamicField)和唯一键(Unique Key)的数据模式(Data Schema) 

b. 对Lucene查询语言的强大扩展! 

c. 支持对结果进行动态的分组和过滤 

d. 高级的,可配置的文本分析 

e. 高度可配置和可扩展的缓存机制 

f. 性能优化 

g. 支持通过XML进行外部配置 

h. 拥有一个管理界面 

i. 可监控的日志 

j. 支持高速增量式更新(Fast incrementalUpdates)和快照发布(Snapshot Distribution)

2、Solr的使用属性及配置文件

Solr拥有一个Document节点,一个Document包括一个或多个 Field。Field 包括名称、内容以及告诉 Solr 如何处理内容的元数据。

  2.1 schema.xml

schema.xml这个配置文件可以在你下载solr包的安装解压目录的\solr\example\solr\collection1\conf中找到,它就是solr模式关联的文件。

打开这个配置文件,你会发现有详细的注释。模式组织主要分为三个重要配置:

   

一、Fieldtype

Fieldtype:就是属性类型的意思,像int,String,Boolean种类型,而在此配置文件中,FieldType就有这种定义属性的功能,看下面的图片: 

图片上有我们熟悉的int,String,boolean,那么,后面的配置,是什么呢?那么我们就来介绍一下后面的参数:

 

 

二、Field

Field:是添加到索引文件中出现的属性名称,而声明类型就需要用到上面的type,如图所示:

ps:①field:固定的字段设置;②dynamicField: 动态的字段设置,用于后期自定义字段,*号通配符.例如: test_i就是int类型的动态字段。

三、copyField

 

<fieldname="item_keywords" type="text_ik"indexed="true" stored="false"multiValued="true"/>

<copyFieldsource="item_title" dest="item_keywords"/>

<copyFieldsource="item_sell_point" dest="item_keywords"/>

<copyFieldsource="item_category_name" dest="item_keywords"/>

 

它表达的意思是。假定item_title属性值为“标题1”;item_sell_point属性值为“卖点1”;item_category_name属性值为“属性1”。那么使用copyfield属性进行查询时,虽然会生成item_title属性值为“标题1”;item_sell_point属性值为“卖点1”;item_category_name属性值为“属性1”,还会生成item_keywords属性值“卖点1,属性1,标题1”。当使用前面三个属性值进行查询时,都只会通过item_keywords属性进行查询。

在Field里也有一些属性需要了解,看图: 

 

四加入中文分词器

中文分词在solr里面是没有默认开启的,需要我们自己配置一个中文分词器。目前可用的分词器有smartcn,IK,Jeasy等。

介绍IK分词器:

   路径:http://ik-analyzer.googlecode.com/files/IK%20Analyzer%202012FF_hf1.zip.

下载后解压出来文件中的三个复制到\solr\contrib\analysis-extras\lib目录中.

IKAnalyzer2012FF_u1.jar      分词器jar包

IKAnalyzer.cfg.xml           分词器配置文件

Stopword.dic                分词器停词字典,可自定义添加内容
 

<fieldTypename="text_ik" class="solr.TextField">

  <analyzerclass="org.wltea.analyzer.lucene.IKAnalyzer"/>

</fieldType>

 

五、其他配置

①uniqueKey:唯一键,这里配置的是上面出现的fileds,一般是id、url等不重复的。在更新、删除的时候可以用到。

②defaultSearchField:默认搜索属性,如q=solr就是默认的搜索那个字段

③solrQueryParser:查询转换模式,是并且还是或者(AND/OR必须大写)

 

   2.2solrconfig.xml

 

solrconfig.xml这个配置文件可以在你下载solr包的安装解压目录的E:\Work\solr-4.2.0-src-idea\solr\example\solr\collection1\conf中找到,这个配置文件内容有点多,主要内容有:使用的lib配置,包含依赖的jar和Solr的一些插件;组件信息配置;索引配置和查询配置,下面详细说一下索引配置和查询配置.

一、索引indexConfig

       Solr 性能因素,来了解与各种更改相关的性能权衡。 下表概括了可控制 Solr 索引处理的各种因素:

 

二、查询配置query

 

 2、DataImportHandler

将solr导入数据需要数据库相连接,然后使用colletion1的Dataimport进行数据连接。在solrconfig.xml目录下

引入配置:

  <admin>

   <defaultQuery>*:*</defaultQuery>

  </admin>

 

  <requestHandlername="/dataimport"class="org.apache.solr.handler.dataimport.DataImportHandler">

  <lst name="defaults">

    <strname="config">date-config.xml</str>

  </lst>

</requestHandler>

在solrconfig.xml同级目录下创建date-config.xml。其文件内容为:

<dataConfig>   

   <!-- 数据源--> 

  <dataSourcetype="JdbcDataSource"   

             driver="com.mysql.jdbc.Driver"   

             url="jdbc:mysql://localhost:3306/eshop-mail"   

              user="root "   

              password="root"/>   

  <document>   

<entityname="item"  query="selectid,name from tb_item_cat">   

      <!-- column:数据库的字段名;name:solr的字段名 --> 

       <field column="id"    name="id" /> 

       <field column="name"  name="item_sell_point" />     

</entity>   

  </document>   

</dataConfig>

column为数据库字段,name为solr的field域的名称。

 

配置完毕以后就能通过界面将数据导入数据库。

 

三、介绍solr软件

在这出现了一个软件就是Solr的软件,下面就和大家一起来看看这个软件怎么用 

上图为安装solr环境的软件的左面截图,首先来看看这幅图的讲解:

1、Dashboard:就是上面全图就是这个按钮的功能;

2、Logging:查看日志;

3、CoreAdmin:添加core用户,这个可重要也可不重要,默认是collection1,这个就是添加一个和collection1具有一样功能的用户,用来检索和查询。点击之

后会出现下面的截图: 

 

提示一下:

name:给core随便起个名字; 

instanceDir:core的安装目录,这里就是之前在tomcat/solrhome/目录下创建的core1文件夹; 

dataDir:指定用于存放lucene索引和log日志文件的目录路径,该路径是相对于core根目录(在单core模式下,就直接是相对于solr_home了),默认值是当前core目录下的data; 

config:用于指定solrconfig.xml配置文件的文件名,启动时会去core1/config目录下去查找; 

schema:即用来配置你的schema.xml配置文件的文件名的,schema.xml配置文件应该存放在当前core目录下的conf目录下。但是下载的solr里没有这个文件,所以我也不管了; 

属性都填上,然后点击Add Core,就创建完成了。

再看最下面的下拉框:点击之后会出现collection1,点击collection1出现如下截图: 

因为我在这之前添加了一个索引文档,所以我的显示的NumDocs和Max Doc 是有值的,没有安装就是为0;

就来介绍一下选中core角色后生成的一些按钮功能。

1、Overview:是浏览你的索引文档。其中包括最后开启时间、文档内存数量、文档最大数量等等一些信息; 

2、Analysis:解析浏览。如下图:

看左上方的FieldValue(Index):这个是定义你要索引的属性值; 

右上方的FieldValue(Query):这个是根据输入的值,来进行查找; 

底下的Analyse Fieldname /FieldType :就是你要往哪个属性里添加索引的值。

3、dataImport:就是数据的引进。 

4、FIles、Ping、Pligins/Stats这些不怎么常用,这里就不多详细介绍了。 

5、Query:是根据索引属性查询,效果如下: 

看到这,相信有的同学就要问了,拿这些是干嘛的呢?下面就介绍一下他们是干嘛的: 

q:查询字符串,必须写,格式为:“索引属性:属性值”,必须遵守这种格式,否则查不出来。

fq:filter query。使用FilterQuery可以充分利用Filter Query Cache,提高检索性能。作用:在q查询符合结果中同时是fq查询符合的,例如:

   q=mm&fq=date_time:[20081001 TO 20091031],找关键字mm,并且date_time是20081001到20091031之间的。

fl:field list。指定返回结果字段。以空格“”或逗号“,”分隔。

start:用于分页定义结果起始记录数,默认为0。

rows:用于分页定义结果每页返回记录数,默认为10。

sort:排序,格式:sort=fieldname+desc|asc 。示例:(inStock desc, price asc)表示先 “inStock” 降序, 再 “price”升序,默认是相关性降序。

df:默认的查询字段,一般默认指定。

q.op:覆盖schema.xml的defaultOperator(有空格时用”AND”还是用”OR”操作逻辑),一般默认指定。必须大写

wt:writertype。指定查询输出结构格式,默认为“xml”。在solrconfig.xml中定义了查询输出格式:xml、json、python、ruby、php、phps、custom。

qt:query type,指定查询使用的QueryHandler,默认为“standard”。

explainOther:设置当debugQuery=true时,显示其他的查询说明。

defType:设置查询解析器名称。

timeAllowed:设置查询超时时间。

omitHeader:设置是否忽略查询结果返回头信息,默认为“false”。

indent:返回的结果是否缩进,默认关闭,用indent=true|on 开启,一般调试json,php,phps,ruby输出才有必要用这个参数。

version:查询语法的版本,建议不使用它,由服务器指定默认值。

debugQuery:设置返回结果是否显示Debug信息。

以上这些就是solr的一些参数,下面就来介绍一下,查询的语法有哪些?

语法:

1.匹配所有文档::

2.强制、阻止和可选查询:

1) Mandatory:查询结果中必须包括的(forexample, only entry name containing the word make)

Solr/Lucene Statement:+make,+make +up ,+make +up +kiss

2) prohibited:(for example,all documents except those with word believe)

Solr/Lucene Statement:+make+up -kiss

3) optional:

Solr/Lucene Statement:+make+up kiss

3.布尔操作:AND、OR和NOT布尔操作(必须大写)与Mandatory、optional和prohibited相似。

1) make AND up = +make +up:AND左右两边的操作都是mandatory

2) make || up = make ORup=make up :OR左右两边的操作都是optional

3) +make +up NOT kiss = +make+up –kiss

4) make AND up OR french ANDKiss不可以达到期望的结果,因为AND两边的操作都是mandatory的。

  1. 子表达式查询(子查询):可以使用“()”构造子查询。

示例:(make AND up) OR (frenchAND Kiss)

5.子表达式查询中阻止查询的限制:

示例:make(-up):只能取得make的查询结果;要使用make (-up :)查询make或者不包括up的结果。

6.多字段fields查询:通过字段名加上分号的方式(fieldName:query)来进行查询

示例:entryNm:make ANDentryId:3cdc86e8e0fb4da8ab17caed42f6760c

7.通配符查询(wildCard Query):

1) 通配符?和:“”表示匹配任意字符;“?”表示匹配出现的位置。

示例:ma?(ma后面的一个位置匹配),ma??(ma后面两个位置都匹配)

2) 查询字符必须要小写:+Ma+be**可以搜索到结果;+Ma +Be**没有搜索结果.

3)查询速度较慢,尤其是通配符在首位:主要原因一是需要迭代查询字段中的每个term,判断是否匹配;二是匹配上的term被加到内部的查询,当terms数量达到1024的时候,查询会失败。

4)Solr中默认通配符不能出现在首位(可以修改QueryParser,设置

setAllowLeadingWildcard为true)

5) set setAllowLeadingWildcardto true.

8.模糊查询、相似查询:不是精确的查询,通过对查询的字段进行重新插入、删除和转换来取得得分较高的查询解决(由LevensteinDistance Algorithm算法支持)。

1) 一般模糊查询:示例:make-believ~

2)门槛模糊查询:对模糊查询可以设置查询门槛,门槛是0~1之间的数值,门槛越高表面相似度越高。示例:make-believ~0.5、make-believ~0.8、make-believ~0.9

9.范围查询(RangeQuery):Lucene支持对数字、日期甚至文本的范围查询。结束的范围可以使用“*”通配符。

示例:

1) 日期范围(ISO-8601时间GMT):sa_type:2 AND a_begin_date:[1990-01-01T00:00:00.000Z TO1999-12-31T24:59:99.999Z]

2) 数字:salary:[2000 TO *]

3) 文本:entryNm:[a TO a]

10.日期匹配:YEAR, MONTH, DAY, DATE(synonymous with DAY) HOUR, MINUTE, SECOND, MILLISECOND, and MILLI (synonymouswith MILLISECOND)可以被标志成日期。

示例:

1) r_event_date:[* TONOW-2YEAR]:2年前的现在这个时间

2) r_event_date:[* TONOW/DAY-2YEAR]:2年前前一天的这个时间

在solr里,也有函数,接下来就看看solr是怎样通过函数查询的:

函数查询 可以利用 numeric字段的值 或者与字段相关的的某个特定的值的函数,来对文档进行评分。

  1. 使用函数查询的方法

这里主要有三种方法可以使用函数查询,这三种s方法都是通过solrhttp接口的。

1) 使用FunctionQParserPlugin。ie:q={!func}log(foo)

2) 使用“val”内嵌方法

内嵌在正常的solr查询表达式中。即,将函数查询写在q这个参数中,这时候,我们使用“val”将函数与其他的查询加以区别。

ie:entryNm:make&& val:ord(entryNm)

3) 使用dismax中的bf参数

使用明确为函数查询的参数,比如说dismax中的bf(boostfunction)这个参数。注意:bf这个参数是可以接受多个函数查询的,它们之间用空格隔开,它们还可以带上权重。所以,当我们使用bf这个参数的时候,我们必须保证单个函数中是没有空格出现的,不然程序有可能会以为是两个函数。

示例:

q=dismax&bf=”ord(popularity)^0.5recip(rord(price),1,1000,1000)^0.3

  1. 函数的格式(Function Query Syntax)

目前,function query 并不支持 a+b这样的形式,我们得把它写成一个方法形式,这就是 sum(a,b).

  1. 使用函数查询注意事项

1) 用于函数查询的field必须是被索引的;

2) 字段不可以是多值的(multi-value)

  1. 可以利用的函数 (available function)

1) constant:支持有小数点的常量; 例如:1.5;SolrQuerySyntax:val:1.5

2) fieldvalue:这个函数将会返回numericfield的值,这个字段必须是indexd的,非multiValued的。格式很简单,就是该字段的名字。如果这个字段中没有这样的值,那么将会返回0。

3)ord:对于一个字段,它所有的值都将会按照字典顺序排列,这个函数返回你要查询的那个特定的值在这个顺序中的排名。这个字段,必须是非multiValued的,当没有值存在的时候,将返回0。例如:某个特定的字段只能去三个值,“apple”、“banana”、“pear”,那么ord(“apple”)=1,ord(“banana”)=2,ord(“pear”)=3.需要注意的是,ord()这个函数,依赖于值在索引中的位置,所以当有文档被删除、或者添加的时候,ord()的值就会发生变化。当你使用MultiSearcher的时候,这个值也就是不定的了。

4)rord:这个函数将会返回与ord相对应的倒排序的排名。

格式: rord(myIndexedField)。

5)sum:这个函数的意思就显而易见啦,它就是表示“和”啦。

格式:sum(x,1) 、sum(x,y)、sum(sqrt(x),log(y),z,0.5)

6)product:product(x,y,…)将会返回多个函数的乘积。格式:product(x,2)、product(x,y)

7)div:div(x,y)表示x除以y的值,格式:div(1,x)、div(sum(x,100),max(y,1))

8) pow:pow表示幂值。pow(x,y)=x^y。例如:pow(x,0.5) 表示开方pow(x,log(y))

9)abs:abs(x)将返回表达式的绝对值。格式:abs(-5)、 abs(x)

10)log:log(x)将会返回基数为10,x的对数。格式: log(x)、 log(sum(x,100))

11) Sqrt:sqrt(x) 返回一个数的平方根。格式:sqrt(2)、sqrt(sum(x,100))

12) Map:如果x>=min,且x<=max,那么map(x,min,max,target)=target.如果x不在[min,max]这个区间内,那么map(x,min,max,target)=x.

格式:map(x,0,0,1)

13)Scale:scale(x,minTarget,maxTarget) 这个函数将会把x的值限制在[minTarget,maxTarget]范围内。

14) query:query(subquery,default)将会返回给定subquery的分数,如果subquery与文档不匹配,那么将会返回默认值。任何的查询类型都是受支持的。可以通过引用的方式,也可以直接指定查询串。

例子:q=product(popularity,query({!dismax v=’solr rocks’}) 将会返回popularity和通过dismax 查询得到的分数的乘积。

q=product(popularity,query($qq)&qq={!dismax}solr rocks 跟上一个例子的效果是一样的。不过这里使用的是引用的方式

q=product(popularity,query($qq,0.1)&qq={!dismax}solr rocks 在前一个例子的基础上又加了一个默认值。

15) linear: inear(x,m,c)表示m*x+c ,其中m和c都是常量,x是一个变量也可以是一个函数。例如: linear(x,2,4)=2*x+4.

16)Recip:recip(x,m,a,b)=a/(m*x+b)其中,m、a、b是常量,x是变量或者一个函数。当a=b,并且x>=0的时候,这个函数的最大值是1,值的大小随着x的增大而减小。例如:recip(rord(creationDate),1,1000,1000)

17) Max:max(x,c)将会返回一个函数和一个常量之间的最大值。

例如:max(myfield,0)

 

4、Solr与spring框架整合开发。

SolrJ是操作Solr的JAVA客户端,它提供了增加、修改、删除、查询Solr索引的JAVA接口。SolrJ针对Solr提供了Rest 的HTTP接口进行了封装, SolrJ底层是通过使用httpClient中的方法来完成Solr的操作。

1、使用solrj进行开发的基本思路:

1、创建一个SolrServer对象,创建一个连接。参数solr服务的url

2、创建一个文档对象SolrInputDocument

3、向文档对象中添加域。文档中必须包含一个id域,所有的域的名称必须在schema.xml中定义。

4、/把文档写入索引库

5、/提交

具体代码实现:

publicclass TestSolrJ {

 

@Test

publicvoid addDocument() throws Exception {

//创建一个SolrServer对象,创建一个连接。参数solr服务的url

SolrServersolrServer = newHttpSolrServer("http://192.168.25.163:8080/solr/collection1");

//创建一个文档对象SolrInputDocument

SolrInputDocumentdocument = new SolrInputDocument();

//向文档对象中添加域。文档中必须包含一个id域,所有的域的名称必须在schema.xml中定义。

document.addField("id","doc01");

document.addField("item_title", "测试商品01");

document.addField("item_price",1000);

//把文档写入索引库

solrServer.add(document);

//提交

solrServer.commit();

}

}

 

2、solrj与spring整合

由于在solr架构中,服务层和显示层是不同的项目。为了让sorl被显示层都能使用,所有将solrj在服务层与spring进行整合。

在service模块中目录为resource/spring/applicationContext-solr.xml创建该目录。在webapp中对spring进行扫描。

applicationContext-solr.xml内容为:

<?xmlversion="1.0" encoding="UTF-8"?>

<beansxmlns="http://www.springframework.org/schema/beans"

xmlns:context="http://www.springframework.org/schema/context"xmlns:p="http://www.springframework.org/schema/p"

xmlns:aop="http://www.springframework.org/schema/aop"xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsd

http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsd

http://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.2.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx-4.2.xsd

http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-4.2.xsd">

<!-- sorl服务 -->

<beanid="httpSolrServer"class="org.apache.solr.client.solrj.impl.HttpSolrServer">

<constructor-argindex="0"value="http://192.168.1.110:8086/solr/collection1"/>

</bean>

</beans>

2、在dao层调用solr服务:SearchDao

@Repository

publicclass SearchDao {

@Autowired

private SolrServer solrServer;//引用solr服务

 

/**

 *根据查询条件查询索引库

 * <p>Title: search</p>

 * <p>Description: </p>

 * @param query

 * @return

 */

publicSearchResult search(SolrQuery query) throws Exception {

//根据query查询索引库

QueryResponsequeryResponse = solrServer.query(query);

//取查询结果。

SolrDocumentListsolrDocumentList = queryResponse.getResults();

//取查询结果总记录数

longnumFound = solrDocumentList.getNumFound();

SearchResultresult = new SearchResult();

result.setRecordCount(numFound);

//取商品列表,需要取高亮显示

Map<String,Map<String, List<String>>> highlighting =queryResponse.getHighlighting();

List<SearchItem>itemList = new ArrayList<>();

for(SolrDocument solrDocument : solrDocumentList) {

SearchItemitem = new SearchItem();

item.setId((String)solrDocument.get("id"));

item.setCategory_name((String)solrDocument.get("item_category_name"));

item.setImage((String)solrDocument.get("item_image"));

item.setPrice((long)solrDocument.get("item_price"));

item.setSell_point((String)solrDocument.get("item_sell_point"));

//取高亮显示

List<String>list =highlighting.get(solrDocument.get("id")).get("item_title");

Stringtitle = "";

if(list != null && list.size() > 0) {

title= list.get(0);

}else {

title= (String) solrDocument.get("item_title");

}

item.setTitle(title);

//添加到商品列表

itemList.add(item);

}

result.setItemList(itemList);

//返回结果

returnresult;

}

}

3、服务层调用dao:

@Service

public class SearchServiceImpl implements SearchService {

 

@ajutowired

private SearchDao searchDao;

@Override

public SearchResult search(String keyword, int page, int rows)throws Exception {

//创建一个SolrQuery对象

SolrQuery query = new SolrQuery();

//设置查询条件

query.setQuery(keyword);

//设置分页条件

if (page <=0 ) page =1;

query.setStart((page - 1) * rows);

query.setRows(rows);

//设置默认搜索域

query.set("df", "item_title");

//开启高亮显示

query.setHighlight(true);

query.addHighlightField("item_title");

query.setHighlightSimplePre("<emstyle=\"color:red\">");

query.setHighlightSimplePost("</em>");

//调用dao执行查询

SearchResult searchResult = searchDao.search(query);

//计算总页数

long recordCount = searchResult.getRecordCount();

int totalPage = (int) (recordCount / rows);

if (recordCount % rows > 0)

totalPage ++;

//添加到返回结果

searchResult.setTotalPages(totalPage);

//返回结果

return searchResult;

}

}

需要特别说明的是生成的高亮数据结构是Map<String, Map<String,List<String>>>,而且高亮Highlighting与Filed是两份不同的数据。

10-06 19:56