作者 白宁超
2016年4月12日16:31:48
摘要:搜索已经作为生活中不可缺少的一部分,诸如:百度、google、还是在微信上寻找好友或者通过一段文本查找关键字。另外亚马逊、京东、天猫、苏宁等电商在搜索中也是别有洞天(多面搜索等)。对于开发人员,搜索往往是大部分应用的关键功能,特别是对大规模文本数据驱动应用更是如此。另一类搜索像语音智能检索,其采用分类、聚类、神经网络等方法进行模型评估,反馈给用户比较理想的匹配结果,这里需要强调的是其采用评分机制反馈的模糊近似查询结果,与传统精确采用是不一样的。这种结果的反馈评分主要依托正确率和召回率。这里自己构建搜索工具好处在于:灵活性、开发费用低、自己更了解自己的搜索工具、价格当然是免费的啦。本文作者花费大量时间,经过资料收集,研究和实验所得,旨在技术分享。(本文原创,转载需说明出处:自己动手搭建搜索工具。)
目录
【文本挖掘(0)】快速了解什么是自然语言处理
【文本挖掘(1)】OpenNLP:驾驭文本,分词那些事
【文本挖掘(2)】【NLP】Tika 文本预处理:抽取各种格式文件内容
【文本挖掘(3)】自己动手搭建搜索工具
1 Apache Solr搜索服务器简介
1.1. Solr 是什么?
Solr它是一种开放源码的、基于 Lucene Java 的搜索服务器,易于加入到 Web 应用程序中。Solr 提供了层面搜索(就是统计)、命中醒目显示并且支持多种输出格式(包括XML/XSLT 和JSON等格式)。它易于安装和配置,而且附带了一个基于HTTP 的管理界面。可以使用 Solr 的表现优异的基本搜索功能,也可以对它进行扩展从而满足企业的需要。Solr的特性包括:
- 高级的全文搜索功能
- 专为高通量的网络流量进行的优化
- 基于开放接口(XML和HTTP)的标准
- 综合的HTML管理界面
- 可伸缩性-能够有效地复制到另外一个Solr搜索服务器
- 使用XML配置达到灵活性和适配性
- 可扩展的插件体系
2. Lucene 是什么?
Lucene是一个基于Java的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta(雅加达) 家族中的一个开源项目。也是目前最为流行的基于Java开源全文检索工具包。目前已经有很多应用程序的搜索功能是基于 Lucene ,比如Eclipse 帮助系统的搜索功能。Lucene能够为文本类型的数据建立索引,所以你只要把你要索引的数据格式转化的文本格式,Lucene 就能对你的文档进行索引和搜索。
3. Solr vs Lucene
Solr与Lucene 并不是竞争对立关系,恰恰相反Solr 依存于Lucene,因为Solr底层的核心技术是使用Lucene 来实现的,Solr和Lucene的本质区别有以下三点:搜索服务器,企业级和管理。Lucene本质上是搜索库,不是独立的应用程序,而Solr是。Lucene专注于搜索底层的建设,而Solr专注于企业应用。Lucene不负责支撑搜索服务所必须的管理,而Solr负责。所以说,一句话概括 Solr: Solr是Lucene面向企业搜索应用的扩展。Solr使用Lucene并且扩展了它!一个真正的拥有动态字段(Dynamic Field)和唯一键(Unique Key)的数据模式(Data Schema)
- 对Lucene查询语言的强大扩展!
- 支持对结果进行动态的分组和过滤
- 高级的,可配置的文本分析
- 高度可配置和可扩展的缓存机制
- 性能优化
- 支持通过XML进行外部配置
- 拥有一个管理界面
- 可监控的日志
- 支持高速增量式更新(Fast incremental Updates)和快照发布(Snapshot Distribution)
2 安装下载最新的Solr
1)本文使用Solr4.8版本,Solr 最新版本有出入请以官方网站内容为准。Solr官方网站下载地址:http://www.apache.org/dyn/closer.cgi/lucene/solr/
Solr 程序包的部分目录结构
dist :存放Solr 构建完成的JAR 文件、WAR 文件和Solr 依赖的JAR 文件。
example :是一个安装好的Jetty 中间件,其中包括一些样本数据和Solr 的配置信息。
example/etc :Jetty 的配置文件。
example/multicore :当安装Slor multicore 时,用来放置多个Solr 主目录。
example/solr :默认安装时一个Solr 的主目录。
example/webapps :Solr 的WAR 文件部署在这里。
Solr 的主目录展开后为如下结构:
bin :建议将集群复制脚本放在这个目录下。
conf :放置配置文件。
conf/schema.xml :建立索引的schema 包含了字段类型定义和其相关的分析器。
conf/solrconfig.xml :这个是Solr 主要的配置文件。
conf/xslt :包含了很多xslt 文件,这些文件能将Solr 的XML 的查询结果转换为特定的格式,比如:Atom/RSS。
data :放置Lucene 产生的索引数据。
lib :放置可选的JAR 文件比如对Slor 扩展的插件,这些JAR 文件将会在Solr 启动时加载。
2)在example目录有start.jar文件,启动:浏览器访问:http://localhost:8983/solr/,你看到的就是solr的管理界面
cd C:\\Users\\bnc\\Desktop\\NPL\\apache-solr\\example java -jar start.jar
目前你看到的界面没有任何数据,你可以通过POSTing命令向Solr中添加(更新)文档,删除文档,在exampledocs目录包含一些示例文件,运行命令:
cd exampledocs java -jar post.jar *.xml
3 Solr在tomcat下配置集成与启动验证
1 下载solr源文件与tomcat源文件
2 建立文件夹命名solr放置3个文件夹:
solr-4.8.0\example\solr文件夹改名home
tomcat改名server
solr-4.8.0\dist下solr-4.8.0.war改名solr.war放在solr\server\webapps下
3 打开solr\server\conf下server.xml <Host></Host>放入
<Context path="" docBase="solr" reloadable="false" crosscontext="true">
<Environment name="sole/home" type="java.lang.String" value="C:\Users\bnc\Desktop\solr\home" override="true" />
</Context>
4 solr-4.8.0\example\lib\ext下库文件放在solr\server\lib
5 配置solr\server\bin下setclasspath.bat
set "JAVA_HOME=C:\Program Files\Java\jdk1.7.0_79"
6 打开solr\server\bin下点击startup.sh
7 启动验证
1)Tomcat(server)添加role和user \solr\server\conf下 tomcat-user.xml 添加
<role rolename="solr" />
<user username="admin" password="admin" roles="solr" />
2)solr\server\webapps\solr\WEB-INF和solr\server\webapps\ROOT\WEB-INF下web.xml
<security-constraint>
<web-resource-collection>
<web-resource-name>Solr Lockdown</web-recource-name>
<url-pattern>/</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>solr</role-name>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>Solr</realm-name>
</login-config>
4 solr中文分词(MMSEG4j):配置中文分词和验证中文分词
1 下载分词工具
mmseg4j-analysis-*.jar mmseg4j-core-*.jar mmseg4j-solr-*.jar
2 拷贝到solr\server\webapps\solr\WEB-INF\lib和solr\server\webapps\ROOT\WEB-INF\lib
3 打开 \solr\home\collection1\conf下schema.xml添加
<fieldtype name="textComplex" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="complex" dicPath="../dic"/>
</analyzer>
</fieldtype>
<fieldtype name="textMaxWord" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="max-word" />
</analyzer>
</fieldtype>
<fieldtype name="textSimple" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="simple" dicPath="../dic" />
</analyzer>
</fieldtype>
然后修改
<field name="title" type="textComplex" indexed="true" stored="true" multiValued="true"/> <field name="subject" type="textComplex" indexed="true" stored="true"/> <field name="description" type="textComplex" indexed="true" stored="true"/> <field name="comments" type="textComplex" indexed="true" stored="true"/> <field name="author" type="textComplex" indexed="true" stored="true"/> <field name="keywords" type="textComplex" indexed="true" stored="true"/> <field name="category" type="textComplex" indexed="true" stored="true"/> <field name="resourcename" type="textComplex" indexed="true" stored="true"/> <field name="url" type="textComplex" indexed="true" stored="true"/> <field name="content_type" type="string" indexed="true" stored="true" multiValued="true"/> <field name="last_modified" type="date" indexed="true" stored="true"/> <field name="links" type="string" indexed="true" stored="true" multiValued="true"/>
4 启动server/bin/start.bat文件
5 配置collection1 并在分析字段和字段类型配置中文分词工具textComplex即可
5 solrJ后台的使用
1) solr-4.8.0\dist\solrj-lib下所有jar文件和solr-solrj-4.8.0.jar复制到java工程lib里面。
2) SolrJ客户端插入数据
//Solr4.x版本插入数据
public void add(String id,String name) throws SolrServerException, IOException{
for(int i=0;i<5;i++){
SolrInputDocument doc=new SolrInputDocument();
doc.addField("id", id+i);
doc.addField("name", "The "+name+" is "+i);
server.add(doc);
}
}
3) SolrJ客户端更数据
//Solr4.x版本插入数据
public void add(String id,String name) throws SolrServerException, IOException{
for(int i=0;i<5;i++){
SolrInputDocument doc=new SolrInputDocument();
doc.addField("id", id+i);
doc.addField("name", "The "+name+" is "+i);
server.add(doc);
}
}
4) SolrJ客户端查询数据
//solr查询数据
public void select() throws SolrServerException{
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("q", "id:*");
params.set("start", "0");
QueryResponse response = server.query(params);
SolrDocumentList results = response.getResults();
for (int i = 0; i < results.size(); ++i) {
System.out.println(results.get(i));
}
}
5) SolrJ客户端删除数据
//删除solr中的视频文档:按照规则删除
public void delete() throws SolrServerException, IOException{
server.deleteByQuery("*:*");
server.commit();
}
6) 完整solrJ工具类源码
package SolrSearch; import java.io.IOException; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.CloudSolrServer; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocumentList; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.params.ModifiableSolrParams; /** * Solr工具类 * @author 白宁超 * @version 2016年4月11日12:57:01 */ public class SolrUtils { //baseURL是固定的访问地址 public static final String SOLL_URL="http://localhost:8080/solr/"; private final HttpSolrServer server; public SolrUtils(){ server=new HttpSolrServer(SOLL_URL); server.setAllowCompression(true); //减少服务器交换的数据量 //server.setSoTimeout(72000); //设置收索超时 } //Solr4.x版本插入视频文档 public void add(Vidio vidio) throws SolrServerException, IOException{ SolrInputDocument doc=new SolrInputDocument(); doc.addField("id", vidio.getId()); doc.addField("name", vidio.getName()); doc.addField("type", vidio.getType()); server.add(doc); server.commit(); } //Solr4.x版本插入数据 public void add(String id,String name) throws SolrServerException, IOException{ for(int i=0;i<100;i++){ SolrInputDocument doc=new SolrInputDocument(); doc.addField("id", id+i); doc.addField("name", "The "+name+" is "+i); server.add(doc); } server.commit(); } //SolrCloud插入数据 public static void addCloud(String id,String name) throws SolrServerException, IOException { String zkHost = "localhost:8080"; String defaultCollection = "collection1"; CloudSolrServer server = new CloudSolrServer(zkHost); System.out.println(); for (int i = 0; i < 1000; ++i) { SolrInputDocument doc = new SolrInputDocument(); doc.addField("id", "book-" + i); doc.addField("name", "The Legend of Po part " + i); server.add(doc); } server.commit(); } //更新solr中的视频文档 public void update(Vidio vidio) throws SolrServerException, IOException { add(vidio); } //更新solr中信息 public void update(String id,String name) throws SolrServerException, IOException { add(id,name); } //删除solr中的视频文档:按照规则删除 public void delete() throws SolrServerException, IOException{ server.deleteByQuery("*:*"); server.commit(); } //删除solr中的视频文档:按照规则删除 public void deleteById(Vidio vidio) throws SolrServerException, IOException{ server.deleteById(vidio.getId() +""); server.commit(); } //solr查询数据 public void select() throws SolrServerException{ ModifiableSolrParams params = new ModifiableSolrParams(); params.set("q", "id:*"); params.set("start", "0"); QueryResponse response = server.query(params); SolrDocumentList results = response.getResults(); for (int i = 0; i < results.size(); ++i) { System.out.println(results.get(i)); } } }