首页 > 代码库 > 搜索引擎之solr小结
搜索引擎之solr小结
前几天被安排到一个项目组里,项目组需要用到搜索引擎技术,因此花了两天调研了一下,后来又说不用了,那就做个小结,写个博文。
一、Solr定义现在被应用的最多的搜索引擎就是solr,solr的定义先贴一下:
Solr是一个基于Lucene的Java搜索引擎服务器。Solr 提供了层面搜索、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 格式)。它易于安装和配置,而且附带了一个基于 HTTP 的管理界面。Solr已经在众多大型的网站中使用,较为成熟和稳定。Solr 包装并扩展了 Lucene,所以Solr的基本上沿用了Lucene的相关术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。通过对Solr 进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。此外,很多 Lucene 工具(如Nutch、 Luke)也可以使用Solr 创建的索引。
我总结一句话:lucene是工具包,Solr就是lucene的服务化。
二、Solr的安装:
1、solr下载
现在最新的Solr版本是4.9,重点!这里要注意,4.9版本对应的jdk的版本要1.7。我就是在这吃了大亏,找了好久才发现这个问题。jdk1.6的版本要4.7以前的,我是采用的4.2.0的solr版本。
下载地址:http://archive.apache.org/dist/lucene/solr/
我下了三个包,分别是 源码包、linux压缩包、win压缩包。
2、Tomcat下载
下载地址:http://tomcat.apache.org/download-60.cgi
我们一般使用Core 核心包,Deployer的是给tomcat的开发爱好者用的,一般情况下用不上。
3、windows下solr安装。
Solr文件分两部分,一部分是webApp,也就是管理页面,需要放到tomcat下发布。另一部分是 索引等数据存储地方,就类似数据库里存数据的位置。
那么,先找一个地方把下好的安装文件解压缩,我在D盘建立了路径 D:\solrHome,然后将zip包放到下面,解压缩。
solr-4.2.0里存放了我们需要的两部分:
webApp文件在D:\solrHome\solr-4.2.0\dist\solr-4.2.0.war
数据存储文件在D:\solrHome\solr-4.2.0\example\solr(整个solr文件夹都是)
(1)第一步安装Tomcat,我们下绿色版本就行
(2)将solr-4.2.0.war包,放到D:\apache-tomcat-solr\webapps下(重命名为solr.war,方便访问)。
(3)将solr的数据存储文件,解压到任意位置,我是放到了solrHome的下面,因为后面还要进行配置。
(4)编辑Tomcat下 \conf\server.xml文件,
这里8080端口随意改,还要添加“URIEncoding="UTF-8",因为要支持中文索引。
(5)然后再Tomcat的conf文件夹里创建Catalina\localhost\solr.xml。
<?xml version="1.0" encoding="UTF-8"?> <Context docBase="\solr.war" crossContext="true" > <Environment name="solr/home" type="java.lang.String" value=http://www.mamicode.com/"D:/solrHome/solr" override="true" />>其中 docBase是我们放solr.war包的路径,这里也可以写绝对路径。<Environment> 标签是启动tomcat的环境变量,这里name="solr/home"是固定写法,value=http://www.mamicode.com/"D:/solrHome/solr"是我们的存放数据文件的文职。
(6)运行 D:\apache-tomcat-solr\bin\startup.bat
启动成功。
4、linux下solr安装。
理解了安装原理后,不在重复了。我把数据文件放在:/opt/solr
webApp放在:/opt/tomcat/apache-tomcat-solr/webapps/solr.war
环境变量配置:vi /etc/profile 在profile文件下面添加export JAVA_OPTS="$JAVAOPTS -Dsolr.solr.home=/opt/solr"这一行。
然后,启动tomcat。
三、Solr的JAVA API应用:
1、pom文件:<dependency> <groupId>apache-solr-solrj</groupId> <artifactId>apache-solr-solrj</artifactId> <version>3.6.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpmime</artifactId> <version>4.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.7.5</version> </dependency>这块我用的solr代码包版本有点低。这几个包都是必须的,否则就会各种报错~2、服务初始化
百度上的都是最早的solr版本例子,大概是1.4版本的。所以我把demo贴过来报错,因此去看看源码,翻了翻,找到了新的服务获取方式。
// solr服务 public static SolrServer server; /** * 初始化 */ static { String url = "http://<span style="font-family:Microsoft YaHei;">xx</span>.<span style="font-family:Microsoft YaHei;">xx</span>.<span style="font-family:Microsoft YaHei;">xx</span>.<span style="font-family:Microsoft YaHei;">xx</span>:<span style="font-family:Microsoft YaHei;">xxxx</span>/solr"; server = new HttpSolrServer(url); }3、手动添加索引/** * 手动添加索引。 * @throws IOException * @throws SolrServerException */ public void addIndexFromFiled() throws IOException, SolrServerException { // 删除所有索引 server.deleteByQuery( "*:*" ); SolrInputDocument doc1 = new SolrInputDocument(); doc1.addField( "id", "id1", 1.0f ); doc1.addField( "name", "doc1", 1.0f ); doc1.addField( "price", 10 ); SolrInputDocument doc2 = new SolrInputDocument(); doc2.addField( "id", "id2", 1.0f ); doc2.addField( "name", "冰羽", 1.0f ); doc2.addField( "price", 20 ); Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); docs.add( doc1 ); docs.add( doc2 ); // 添加索引 server.add( docs ); // 提交索引 server.commit(); // 优化索引 server.optimize(); }4、ListBean添加索引,这种事最常用的写法。这里需要bean里的字段要加上标签@Field
@Field private String id;如果不加的话,不会报错,也不会添加索引。这种有个重点,如果添加索引,可能需要修改solr数据文件下的 solr\collection1\conf\schema.xml
如图
<!-- 自定义 --> <field name="age" type="int" indexed="true" stored="true"/> <field name="type" type="string" indexed="true" stored="true"/>类型一定要跟JavaBean匹配上。/** * 通过编辑List<Bean>,设置索引 */ public void addIndexFromBean() { try{ // 删除所有索引 server.deleteByQuery( "*:*" ); List<Item> list = new ArrayList<Item>(); list.add(new Item("一号","dog1",5,"松狮")); list.add(new Item("2","dog2",3,"哈士奇")); list.add(new Item("3","dog3",1,"泰迪")); // 添加索引 server.addBeans(list); // 提交索引 server.commit(); // 优化索引 server.optimize(); } catch (SolrServerException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } }5、通过DB查询数据,添加索引。/** * 通过Db查询,设置索引 */ public void addIndexFromDb() { try{ Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>(); // 此处的 dbResultList 应该是从db查询出来的结果集。 List<Cat> dbResultList = new ArrayList<Cat>(); for (int i = 0; i < dbResultList.size(); i++) { Cat cat = dbResultList.get(i); //设置每个字段不得为空,可以在提交索引前进行检查 SolrInputDocument doc = new SolrInputDocument(); //在这里请注意date的格式,要进行适当的转化,上文已提到 doc.addField("id", cat.getName()); // ………… docs.add(doc); } // 添加索引 server.add( docs ); // 提交索引 server.commit(); // 优化索引 server.optimize(); } catch (SolrServerException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } catch (IOException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } }6、getFieldValue的查询方式。/** * getFieldValue的查询方式。 * @throws SolrServerException */ public void findByField(String queryStr) throws SolrServerException { SolrQuery query = new SolrQuery(); if (queryStr == null) queryStr = "*:*"; // 创建检索条件 query.setQuery(queryStr); // 设置偏移量,从第0个开始。 query.setStart(0); // 一次取几条,分页用 query.setRows(10); // 按"price"索引 倒序 query.addSortField( "price", SolrQuery.ORDER.desc ); QueryResponse rsp = server.query( query ); SolrDocumentList docsList = rsp.getResults(); for(Iterator<SolrDocument> doc =docsList.iterator();doc.hasNext();){ SolrDocument d = doc.next(); System.out.print(d.getFieldValue("id")+"->"); System.out.println(d.getFieldValue("name")); } }7、findByBeans的查询方式。/** * findByBeans的查询方式。 * @throws SolrServerException */ public void findByBeans(String queryStr) throws SolrServerException { SolrQuery query = new SolrQuery(); // 创建检索条件 if (queryStr == null) queryStr = "*:*"; query.setQuery(queryStr); // 设置偏移量,从第0个开始。 query.setStart(0); // 一次取几条,分页用 query.setRows(10); query.addSortField( "id", SolrQuery.ORDER.desc ); QueryResponse rsp = server.query( query ); // 此方法需要Item有无参构造函数 List<Item> itemList = rsp.getBeans(Item.class); for (Item item : itemList) { System.out.print("id:" + item.getId() + " "); System.out.print("name:" + item.getName() + " "); System.out.print("age:" + item.getAge() + " "); System.out.println("type:" + item.getType()); } }8、删除索引/** * 删除所有索引 * @throws IOException * @throws SolrServerException */ public void delIndex() throws IOException, SolrServerException { // delete everything! // *:*第一个* 代表索引名称,第二个*代表索引内容。 // "name:dog1"表示 索引里的name字段为dog1的。 // "name" server.deleteByQuery( "*:*" ); }9、测试public static void main(String[] args) throws IOException, SolrServerException { SolrDemo demo = new SolrDemo(); demo.delIndex(); demo.addIndexFromBean(); // 如果只传入一个参数,好像是默认查询field为name 的内容。待确认 demo.findByBeans("*:*"); }四、总结:
对solr的调研只有两天时间其中一天都浪费在版本包问题的解决上了。感觉效果不理想,只掌握了基本的使用手法,或者说知道solr是什么样一个东西了。一些solr的中高级用法也没有时间去看,太仓促的原因,solr的服务化的优势我也没有去体会。不过solr的使用上来讲,因为涉及到启动独立的服务,未必所有人都喜欢,而且内存的占用说实话也不小。
很多人可能更喜欢lucene的jar包的方式,来灵活的运用吧。我不方便评价二者究竟哪个更好,因为我并未来得及体会solr服务化的强大之处。
最近JAVA的基础知识落下了,得先补几天JAVA基础知识和设计模式,solr有机会再深入吧。