前几天被安排到一个项目组里,项目组需要用到搜索引擎技术,因此花了两天调研了一下,后来又说不用了,那就做个小结,写个博文。
一、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="D:\solrHome\solr" override="true" />
</Context>
其中 docBase是我们放solr.war包的路径,这里也可以写绝对路径。
<Environment> 标签是启动tomcat的环境变量,这里name="solr/home"是固定写法,value="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有机会再深入吧。