浅尝Solr~~
来源:互联网 发布:百度人工智能研究 编辑:程序博客网 时间:2024/05/29 18:37
由于最近项目组有需求,大致意思是做一个对数据全面的统一搜索。于是乎,就研究了一哈Solr
什么是Solr?
Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。Solr是一个高性能,采用Java5开发,Solr基于Lucene的全文搜索服务器。同时对其进行了扩展,提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文搜索引擎。
为什么选择Solr?
除了Solr,ES(Elasticsearch),也是个不错的选择对于搜索引擎,并且,目前的应用是广于Solr的。ES是一个实时的分布式搜索和分析引擎。具体特性,我也不甚了解,主要特点,分布式引擎,实时搜索,高性能采集。显然,在大数据方面上,ES是个不错选择。但在对索引进行搜索上,Solr是远远优于ES的。我目前的项目,数据级在万以内,并且目前不打算分布式部署搜索引擎,所以我选择了Solr。
Solr部署
本次部署的话,是另开了个项目,采用了Jetty做容器。以下是Jetty的配置。(我萌萌哒的项目经理配的,我只是搬运工~)
public class JettySolrStart { private static Server server; public static void main(String[] args) throws Exception { // change the default file encoding to utf-8 // need add the -Dfile.encoding=utf-8 to command line in deploy // environment int port=8983; int listenerport=8984; String path="/"; String rootdir="./webroot"; if (args!=null && args.length>0){ try{ port=Integer.parseInt(args[0]); }catch(Exception e){ } } if (args!=null && args.length>1){ try{ listenerport=Integer.parseInt(args[1]); }catch(Exception e){ } } if (args!=null && args.length>2){ path=args[2].trim(); } if (args!=null && args.length>3){ rootdir=args[3].trim(); } System.setProperty("file.encoding", "utf-8"); System.setProperty("solr.solr.home", rootdir+"/WEB-INF/solr"); //System.setProperty("solr.solr.home", rootdir); server = new Server(); QueuedThreadPool threadPool = new QueuedThreadPool(); server.setThreadPool(threadPool); Connector connector = new SelectChannelConnector(); connector.setPort(port); server.setConnectors(new Connector[] { connector }); WebAppContext context = new WebAppContext(rootdir, path); HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection contexts = new ContextHandlerCollection(); RequestLogHandler requestLogHandler = new RequestLogHandler(); handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(), requestLogHandler }); contexts.addHandler(context); server.setHandler(handlers); server.setStopAtShutdown(true); server.setSendServerVersion(true); Thread monitor = new MonitorThread(listenerport); monitor.start(); server.start(); server.join(); } private static class MonitorThread extends Thread { private ServerSocket socket; public MonitorThread(int listenerport) { setDaemon(true); setName("StopMonitor"); try { socket = new ServerSocket(listenerport, 1, InetAddress .getByName("127.0.0.1")); } catch (Exception e) { throw new RuntimeException(e); } } @Override public void run() { System.out.println("*** running jetty 'stop' thread"); Socket accept; try { accept = socket.accept(); BufferedReader reader = new BufferedReader( new InputStreamReader(accept.getInputStream())); reader.readLine(); System.out.println("*** stopping jetty embedded server"); server.stop(); accept.close(); socket.close(); System.exit(0); } catch (Exception e) { System.out.println(e.getMessage()); throw new RuntimeException(e); } } }}
public class JettySolrStop { public static void main(String[] args) throws Exception { int port=8984; if (args!=null && args.length>0){ try{ port=Integer.parseInt(args[0]); }catch(Exception e){ } } Socket s = new Socket(InetAddress.getByName("127.0.0.1"), port); OutputStream out = s.getOutputStream(); System.out.println("*** sending jetty stop request"); out.write(("\r\n").getBytes()); out.flush(); s.close(); }}
类似于很多的Jetty配置,大家需要关注的点是2个端口设置,
int port=8983; int listenerport=8984;
8983是启动端口 8984是监听端口,另外还要关注的是对Solr目录的读取,
System.setProperty("solr.solr.home", rootdir+"/WEB-INF/solr");
这个目录结构:
以上文件大家可以在Solr的JAR包里获取,http://lucene.apache.org/solr/ 里下载即可,到这里大致部署是ok了。
Solr索引采集
这个点是我僵了最久了的~ 后来在看了N篇博客后,我大致有了思路。我采取,定时任务去跑数据库全量与增量导入,同时在任何基础请求进行后进行采集索引。
这里重点讲下前一点。基础的solr-solrj-4.7.1.jar是不支持数据库导入索引的,需要引入
接下来是对data-config.xml进行配置:
<?xml version="1.0" encoding="UTF-8" ?><dataConfig> <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/test" user="test" password="test"/> <document name="company"> <entity name="users" query="select * from users"> <field column="UserID" name="UserID"/> <field column="Number" name="Number"/> <field column="RealName" name="RealName"/> <field column="Leavel" name="Leavel"/> <field column="Degrees" name="Degrees"/> <field column="GraduateSchool" name="GraduateSchool"/> <field column="Professional" name="Professional"/> <field column="HouseholdAdd" name="HouseholdAdd"/> <field column="Residenc" name="Residenc"/> <entity name="tq_sys_userHasRoles" query="select roleId from tq_sys_userHasRoles where userId='${users.UserId}'"> <field column="roleId" name="roleId"/> <entity name="tq_sys_roles" query="select roleName,orgId from tq_sys_roles where id='${tq_sys_userHasRoles.roleId}'"> <field column="roleName" name="roleName"/> <field column="orgId" name="orgId"/> <entity name="tq_sys_organizations" query="select orgName from tq_sys_organizations where id='${tq_sys_roles.orgId}'"> <field column="orgName" name="orgName"/> </entity> </entity> </entity> </entity> </document> </dataConfig>
这是部分配置,可看出Solr的数据库导入是支持多表关联查询,然后封装成一个entity的。一个document下可以存在多个entity。(!!!这里的SQ语句复杂程度直接影响导入索引的速度)。
接下来是schema.xml,这文件比较繁杂,截取部分配置用到的吧。
<!-- users --> <field name="UserId" type="int" indexed="true" stored="true" multiValued="false"/> <field name="number" type="int" indexed="true" stored="true" multiValued="false"/> <field name="RealName" type="text_ik" indexed="true" stored="true" multiValued="false"/> <field name="Leavel" type="string" indexed="true" stored="true" multiValued="false"/> <field name="Degrees" type="string" indexed="true" stored="true" multiValued="false"/> <field name="GraduateSchool" type="text_ik" indexed="true" stored="true" multiValued="false"/> <field name="Professional" type="text_ik" indexed="true" stored="true" multiValued="false"/> <field name="HouseholdAdd" type="text_ik" indexed="true" stored="true" multiValued="false"/> <field name="Residenc" type="text_ik" indexed="true" stored="true" multiValued="false"/> <field name="roleId" type="int" indexed="true" stored="true" multiValued="false"/> <field name="roleName" type="string" indexed="true" stored="true" multiValued="false"/> <field name="orgName" type="string" indexed="true" stored="true" multiValued="false"/> <field name="orgId" type="int" indexed="true" stored="true" multiValued="false"/>
显然name与data-config.xml查出的字段名一一对应 ,solr支持各种type,普遍的string、int等都是可用,也支持自己构造type(例如 text_ik)。
介绍下另外3个属性吧,indexed是否可以查询,stored是否可以内容存储 ,multiValued是否复合索引。
这样配置完,可以打开solr的界面看下效果了。
点开dataimport
这里的clean是清空之前所有索引!!!慎勾!!!然后点击execute 你就可以在Query模块查到你所导入的索引啦~(≧▽≦)/~啦啦啦!
另一个数据实时支持,在任何基础请求进行后进行采集索引。这方面的话,我就贴下代码吧,也是比较简单的。
List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); SolrInputDocument solrDocument = new SolrInputDocument(); solrDocument.addField("id", userInfo.getId().toString()); docs.add(solrDocument); SolrUtil.addOrUpdate(docs,GetHttpSolrServer.getInstance());
Solr调用
呃~既然有索引了那接下来就好办了。由于Solr项目跟主项目分离了,我是采取了发送HTTP请求的方式调用Solr。这方面SolrJ提供了HttpSolrServer十分好用。不废话贴代码吧。
HttpSolrServer solr = SolrUtil.getSolrConnection();SolrQuery params = new SolrQuery();params.set("qt", "/select");params.set("q", "RealName:"+q);params.set("wt", "json");params.setRows(Integer.MAX_VALUE);params.setHighlight(true); //开启高亮 params.setHighlightFragsize(200); //返回的字符个数 params.setHighlightRequireFieldMatch(true); params.setHighlightSimplePost("<em>"); //前缀 params.setHighlightSimplePre("</em>"); //后缀 //高亮字段 params.addHighlightField("RealName");QueryResponse query = solr.query(params);QueryResponse req = solr.query(params); SolrDocumentList results = query.getResults();
在最后得到K-V数据处理方面我也是困惑了很久。
为了给前端大哥相对好处理的数据集,我采用了封装成对象,然后根据数据动态映射set方法。(这方面涉及method/invoke的知识,网上还是蛮多的,大家可以自行研究下。)
这里眼尖的 有可能看到了高亮,solr对高亮是有很健壮的支持的,以及之前的分词。我贴下我的配置代码
<!-- Highlighting defaults --> <!-- hl是指定是否使用高亮;hl.fl,指定对哪些域进行高亮,对多个域进行高亮的话,好像是用逗号隔开; f.name.hl.fragsize是指摘要的长度,默认0代表不做摘要。而hl.simple.pre和hl.simple.post则是指定高亮时显示的格式,默认是<em></em> --> <str name="hl">on</str> <str name="hl.fl">content features title name</str> <str name="hl.encoder">html</str> <str name="hl.simple.pre"><font color="red"></str> <str name="hl.simple.post"></b></str> <str name="f.title.hl.fragsize">100</str> <str name="f.title.hl.alternateField">title</str> <str name="f.name.hl.fragsize">0</str> <str name="f.name.hl.alternateField">name</str> <str name="f.content.hl.snippets">3</str> <str name="f.content.hl.fragsize">200</str> <str name="f.content.hl.alternateField">content</str> <strname="f.content.hl.maxAlternateFieldLength">750</str>
新建一个IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 <entry key="ext_dict">ext.dic;</entry> --> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords">stopword.dic;</entry> </properties>
以及
<!-- 分词 --> <fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
下班了写的有点急 有什么不对欢迎大家指出来~
- 浅尝Solr~~
- 浅尝
- PhotoShop浅尝
- CorelDRAW浅尝
- 浅尝触发器
- 浅尝DotNetNuke
- 浅尝Linux
- 浅尝JQchart!
- DWR浅尝
- 浅尝Mina
- 浅尝python
- 浅尝Kivy
- 浅尝sed
- 浅尝awk
- 浅尝 SCALA
- Makefile浅尝
- 浅尝JMX
- Java浅尝
- 数据库连接池原理
- JS打开APP
- 浅谈我对MySQL数据库的范式的理解和设计
- 连接rabbitmq集群报ProbableAuthenticationError
- WR解析报告
- 浅尝Solr~~
- C++11可变参数函数模板
- fitnesse 源码研究和二次开发
- 使用parted划分GPT分区
- Java多线程
- 图论基础(一)
- 在当前时间上加时间(年月日,小时,分钟,秒)
- java程序连接数据库并批量执行.sql文件
- MVC 过滤器详解