[开篇语]按照惯例应该写一篇技术文章了,此次结合Lucene/Solr来分享一下开发经验。 java
Lucene是一个使用Java语言写的全文检索开发包(API),利用它能够实现强大的检索功能,它的详细介绍你们能够去Google上搜索一下,本文重点放在Solr相关的讨论上。 linux
[概述]目前国内研究Solr的人很少,并且大可能是由于项目开发须要。Solr师承Lucene,为Apache基金会下的一个项目,具体的说它仍是Lucene下的一个子项目。Solr出身豪门,并且具备本身的技术特色,填补了以往Lucene仅仅做为开发工具包的遗憾,它是一个完完整整地应用。换句话说,它是一个全文检索服务器,它开箱即用,让咱们能立马体会到Lucene的强大功能,为Lucene产品化走出了一大步。
Solr分词原理演示界面 web
[渊源]最初,CNET Networks使用Lucene
API来开发了一些应用,并在这个基础上产生了Solr的雏形,后来Apache Software
Foundation在Lucene顶级项目的支持下获得了Solr,这已是2006年1月份的事了。2006年1月17日,Solr正是加入Apache基金会的孵化项目,在整个项目孵化期间,Solr
稳步地积累各类特性并吸引了一个稳定的user群体、developer群体和Committer群体,并于1年以后的17日正式酝酿成熟,在这以前已经成功发布了1.1.0版。目前的稳定版本是1.2,Solr在9月份的2007Apache年会上大放异彩,在今年11月底未来到香港参加2007亚洲开源软件峰会,遗憾的是为何不来北京:-( 数据库
[初识Solr]Solr服务器不一样于普通的关系型数据库,不只仅在于它核心本质的不一样(面向结构化和非结构化数据的不一样),很大的不一样还在于它的体系架构上。Solr服务器通常状况下须要部署于应用服务器/Java容器上(若是是本机通讯不涉及RPC能够不使用Java容器,如采用嵌入方式使用Solr),没法独立工做于JVM上。
Solr架构图
Solr服务器能够存储数据并经过索引对其进行快速高效检索。对外提供HTTP/XML和Json
API接口,这使得它可以在多语言环境下集成,好比针对它的客户端的开发。Solr目前的客户端面向的有Java、PHP、Python、C#、Json和Ruby等,遗憾的是没有面向C/C++(这也是本人目前在研究的),研究音乐搜索分类的Brian
Whitman曾在苹果平台上使用JNI技术在C代码中嵌入Solr实现检索,不过是一个Cocoa工程。有了这些客户端,使用者能很方便地将Solr集成到具体运用中。目前最完善的当属Java客户端Solrj,以及加入到Solr
trunk,并将在1.3版本中正式发布。 apache
若是不研究开发Solr,只是使用Solr,只须要关注Solr的如下几个方面:
一、Solr服务器的配置在solrconfig.xml中完成,包括对缓存,servlet的个性化配置等等,即系统全局的配置;
二、索引方法、索引域(字段)等等在schema.xml中完成,这个配置是针对Solr实例的;
三、索引数据文件默认放在Solr文档根目录下的data/index目录下,这个路径能够经过第1点配置,同时能够将这个目录下的文件进行复制粘贴,便可完成索引的复用;
四、创建索引的时间至关长,我采用按词无字典索引方式对2G110万条中文记录进行索引,花了将近2个半小时的时间(固然这个时间和不少因素有关,有兴趣的话你们能够留言和我讨论),相对而言,在linux下建索引时间要比windows下快不少,可使用commit操做使新增索引生效,同时注意索引的优化,索引优化也是很费资源和时间的,可是优化索引也是提升检索速度的重要方法,所以须要好好权衡这一点;
五、安装完后的Solr目录下有这么几个文件夹:bin文件夹里主要是用于创建镜像和完成远程同步的脚本;conf文件夹下主要是一、2点中提到的配置文件;admin文件夹下是的主要是提供web管理界面的文件;
六、目前Solr1.2不具有安全性设计,没有用户组及权限设置,在进行具体应用时须要注意安全,目前最有效的方法是经过应用服务器上的受权实现。
本文永久连接:http://www.jinsehupan.com/blog/?p=25 windows
[Solr的安装]Solr发行版中已经有一个使用Jetty为servlet容器的小例子,可使用这个例子来体验,那正在在本身想部署的平台和应用服务器上该怎么一个步骤呢? 浏览器
要开始使用 Solr,需安装如下软件:
一、Java 1.5
或更高版本;
二、Ant 1.6.x 或更高版本(用于编译管理Solr工程,我的推荐,固然可使用eclipse);
三、Web
浏览器,用来查看管理页面(官方建议使用Firefox,但实际没有发现和IE有什么差异);
四、servlet 容器,如Tomcat
5.5(不建议使用6版本)。本文以Tomcat 在 8080 端口上运行为例。若是运行的是其余 servlet
容器或在其余的端口上运行,则可能要修改代码中的URL才能访问示例应用程序和 Solr。 缓存
下面开始安装配置: tomcat
1、使用Ant编译工程或下载示例应用程序,将Solr WAR 文件复制到
servlet 容器的webapps目录中;
二、获得Solr文件夹,以备随后将其复制到当前目录,可使用ant
build获得,也能够在下载的压缩包中找到,以它为模板以备以后的修改;
三、能够经过如下三种方式之一设置 Solr 的主位置:
设置 java
系统属性 solr.solr.home (没错,就是 solr.solr.home,通常在嵌入式集成中用得多);
配置
java:comp/env/solr/home 的一个 JNDI 查找指向 solr
目录,创建/tomcat55/conf/Catalina/localhost/solr.xml文件,注意这个xml文件名将是Solr实例名称,2中的当前目录被指定为下面中的f:/solrhome,文件内容以下: 安全
在包含 solr 目录的目录中启动 servlet 容器(默认的 Solr
主目录是当前工做目录下的
solr);
四、最后一点就是若是有CJK(中日韩文字)应用,出现乱码问题,采用以下方法解决(其实已经不算是solr配置问题,而是应用服务器配置问题),修改Tomcat的conf/server.xml文件中对于端口(本文为8080)的链接器统一资源编码为UTF-8,由于Solr1.2内核支持UTF-8编码:
[Solr分词顺序]Solr创建索引和对关键词进行查询都得对字串进行分词,在向索引库中添加全文检索类型的索引的时候,Solr会首先用空格进行分词,而后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果才会加入到索引库中以备查询。分词的顺序以下:
索引
1:空格whitespaceTokenize
2:过滤词StopFilter
3:拆字WordDelimiterFilter
4:小写过滤LowerCaseFilter
5:英文相近词EnglishPorterFilter
6:去除重复词RemoveDuplicatesTokenFilter
查询
1:查询相近词
2:过滤词
3:拆字
4:小写过滤
5:英文相近词
6:去除重复词
以上是针对英文,中文的除了空格,其余都相似
[Solr中文应用的一个实例]
1、首先配置schema.xml,这个至关于数据表配置文件,它定义了加入索引的数据的数据类型的。1.2版本的schema.xml主要包括types、fields和其余的一些缺省设置。
A、首先须要在types结点内定义一个FieldType子结点,包括name,class,positionIncrementGap等等一些参数,name就是这个FieldType的名称,class指向org.apache.solr.analysis包里面对应的class名称,用来定义这个类型的行为。在FieldType定义的时候最重要的就是定义这个类型的数据在创建索引和进行查询的时候要使用的分析器analyzer,包括分词和过滤。在例子中text这个FieldType在定义的时候,在index的analyzer中使用solr.WhitespaceTokenizerFactory这个分词包,就是空格分词,而后使用solr.StopFilterFactory,solr.WordDelimiterFilterFactory,solr.LowerCaseFilterFactory,solr.EnglishPorterFilterFactory,solr.RemoveDuplicatesTokenFilterFactory这几个过滤器。在向索引库中添加text类型的索引的时候,Solr会首先用空格进行分词,而后把分词结果依次使用指定的过滤器进行过滤,最后剩下的结果才会加入到索引库中以备查询。Solr的analysis包并无带支持中文的包,在这里咱们采用lucene里的语言包(在下载后的solr压缩包内,lib目录下有一个lucene-analyzers-2.2.0.jar包,里面含有中文处理的cn和cjk类),有cn和cjk两个类能够支持中文。咱们采用cjk类,并在schema.xml中加入以下配置:
支持类型定义完成了。
B、接下来的工做就是在fields结点内定义具体的字段(相似数据库中的字段),就是filed,filed定义包括name,type(为以前定义过的各类FieldType),indexed(是否被索引),stored(是否被储存),multiValued(是否有多个值)等等。例如定义以下:
field的定义至关重要,有几个技巧需注意一下,对可能存在多值得字段尽可能设置multiValued属性为true,避免建索引是抛出错误;若是不须要存储相应字段值,尽可能将stored属性设为false。
C、建议创建了一个拷贝字段,将全部的全文字段复制到一个字段中,以便进行统一的检索:
并在拷贝字段结点处完成拷贝设置:
D、除此以外,还能够定义动态字段,所谓动态字段就是不用指定具体的名称,只要定义字段名称的规则,例如定义一个dynamicField,name为*_i,定义它的type为text,那么在使用这个字段的时候,任何以_i结尾的字段都被认为是符合这个定义的,例如name_i,gender_i,school_i等。
2、配置solrconfig.xml,用来配置Solr的一些系统属性,比较重要的一个就是能够经过更改其中的dataDir属性来指定索引文件的存放位置,对于有大数据量的状况下还要进行自动commit操做配置,如下设置为当内存索引量达到20W条时自动进行往磁盘写操做,以避免堆溢出,这也是解决单个入库xml文件最好不要超过30M的有效方法:
3、配置好这些后,须要从新启动Solr服务器使配置生效,而后向其中添加数据。
4、添加数据是经过向服务器的update Servlet POST
xml格式的数据来实现的,xml结构是这样的add中间有不少个doc,每一个doc中有不少个field。添加到索引库中的每条记录都必须指定惟一的数字id来惟一标识这条索引。创建好xml文件(例如solr.xml)以后,在exampledocs目录下执行:java
-jar post.jar
solr.xml来添加索引数据。对于post的jar包,若是从新配置了应用服务器,如使用了comcat,端口改成8080,实例名称改成solrx了须要从新生成相应的post.jar包进行操做。
另附ronghao实现中文分词的案例供你们参考:
对全文检索而言,中文分词很是的重要,这里采用了qieqie庖丁分词(很是不错:))。集成很是的容易,我下载的是2.0.4-alpha2版本,其中它支持最多切分和按最大切分。建立本身的一个中文TokenizerFactory继承自solr的BaseTokenizerFactory。
**
* Created by IntelliJ IDEA.
* User: ronghao
* Date: 2007-11-3
* Time: 14:40:59
* 中文切词 对庖丁切词的封装
*/
public class ChineseTokenizerFactory
extends BaseTokenizerFactory {
/**
* 最多切分 默认模式
*/
public static final String
MOST_WORDS_MODE = “most-words”;
/**
* 按最大切分
*/
public static final String
MAX_WORD_LENGTH_MODE = “max-word-length”;
private String mode = null;
public void setMode(String mode)
{
if
(mode==null||MOST_WORDS_MODE.equalsIgnoreCase(mode)
|| “default”.equalsIgnoreCase(mode))
{
this.mode=MOST_WORDS_MODE;
} else if
(MAX_WORD_LENGTH_MODE.equalsIgnoreCase(mode)) {
this.mode=MAX_WORD_LENGTH_MODE;
}
else {
throw new
IllegalArgumentException(”不合法的分析器Mode参数设置:” + mode);
}
}
@Override
public void init(Map args) {
super.init(args);
setMode(args.get(”mode”));
}
public TokenStream create(Reader input)
{
return new PaodingTokenizer(input,
PaodingMaker.make(),
createTokenCollector());
}
private TokenCollector
createTokenCollector() {
if(
MOST_WORDS_MODE.equals(mode))
return new
MostWordsTokenCollector();
if(
MAX_WORD_LENGTH_MODE.equals(mode))
return new
MaxWordLengthTokenCollector();
throw new Error(”never
happened”);
}
}
在schema.xml的字段text配置里加入该分词器。
1. <fieldtype name="text"
class="solr.TextField" positionIncrementGap="100">
2.
3. <analyzer
type="index">
4.
5.
<tokenizer
class="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory"
mode="most-words"/>
6.
7.
8. <filter
class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
9.
10. <filter
class="solr.WordDelimiterFilterFactory" generateWordParts="1"
generateNumberParts="1" catenateWords="1" catenateNumbers="1"
catenateAll="0"/>
11.
12. <filter
class="solr.LowerCaseFilterFactory"/>
13.
14.
15. <filter
class="solr.RemoveDuplicatesTokenFilterFactory"/>
16.
17.
</analyzer>
18.
19. <analyzer
type="query">
20.
21.
<tokenizer
class="com.ronghao.fulltextsearch.analyzer.ChineseTokenizerFactory"
mode="most-words"/>
22.
23. <filter
class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true"
expand="true"/>
24.
25. <filter
class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt"/>
26.
27. <filter
class="solr.WordDelimiterFilterFactory" generateWordParts="1"
generateNumberParts="1" catenateWords="0" catenateNumbers="0"
catenateAll="0"/>
28.
29. <filter
class="solr.LowerCaseFilterFactory"/>
30.
31. <filter
class="solr.RemoveDuplicatesTokenFilterFactory"/>
32.
33.
</analyzer>
34.
35.
</fieldtype>
完成后重启tomcat,便可在http://localhost:8080/solr/admin/analysis.jsp
体验到庖丁的中文分词。注意要将paoding-analysis.jar复制到solr的lib下,注意修改jar包里字典的home。
[Solr的检索运算符]
“:” 指定字段查指定值,如返回全部值*:*²
“?”²表示单个任意字符的通配
“*”
表示多个任意字符的通配(不能在检索的项开始使用*或者?符号)²
“~”²表示模糊检索,如检索拼写相似于”roam”的项这样写:roam~将找到形如foam和roams的单词;roam~0.8,检索返回类似度在0.8以上的记录。
²邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta
apache”~10
“^”²控制相关度检索,如检索jakarta
apache,同时但愿去让”jakarta”的相关度更加好,那么在其后加上”^”符号和增量值,即jakarta^4
apache
布尔操做符AND、||²
布尔操做符OR、²&&
布尔操做符NOT、!、-²(排除操做符不能单独与项使用构成查询)
“+”
存在操做符,要求符号”+”后的项必须在文档相应的域中存在²
( ) 用于构成子查询²
² [] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO
200710]
{}²不包含范围检索,如检索某时间段记录,不包含头尾
date:{200707
TO 200710}
" 转义操做符,特殊字符包括+ -² && || ! ( ) { } [ ] ^ ” ~ * ? : "