一、入门
在使用的时候需要和lucene
的版本一致
1.1 安装
这里我们使用老版本的solr
,解压之后使用命令:
java –jar E:\API\Lucene\lucene3.5.0\apache-solr-3.5.0\example\start.jar
启动solr
,然后使用地址http://localhost:8983/solr/admin
访问solr
。但是此时solr
使用的是jetty
服务器,我们首先让tomcat
来管理solr
,也就是使用tomcat
来启动solr
。
步骤:
1、我们在
E:\API\Lucene
中新建一个solr
文件夹来保存solr
相关的信息,同时在此solr
文件夹中新建一个home
文件夹,然后将solr
解压目录中example
下的solr
文件夹中的内容拷贝到home
文件夹中。拷贝之后将/home/data
中的文件全部删除。2、将相应的
solr
的web
程序(E:\API\Lucene\lucene3.5.0\apache-solr-3.5.0\example\webapps
)中的solr.war
拷贝到tomcat
中,启动tomcat
之后此文件会被解压,然后将tomcat
中的solr.war
删除。-
3、在
home/conf/solrconfig.xml
中配置
这里将我们的data
文件夹的路径配置进去。 4、设置相应的
tomcat
的context
在E:\apache\tomcat\tomcat\conf\server.xml
中
<Context docBase="E:\apache\tomcat\tomcat\webapps\solr" path="/solr" reloadable="false">
<Environment name="solr/home" type="java.lang.String" value="E:\API\Lucene\solr\home" overrid="true"/>
</Context>
说明:不知道是什么原因,如果不将
solr.war
放在tomcat\webapps
中,当从MyEclipse
中启动tomcat
服务器的时候就会将这段添加的内容给删除掉。所以这里我们还是将这个solr
工程放在tomcat\webapps
中。
- 5、
Context
设置相应的环境变量,说明solr
的主目录的地址。如果启动有误,我们可以将E:\API\Lucene\solr\home\conf\solrconfig.xml
中的这段注释掉。即取消Velocity
的输出格式。
然后就可以使用地址http://localhost:8080/solr
访问solr
了。
2.2 添加中文分词器
- 将中文分词的这两个包拷贝到solr服务器中的路径
E:\API\Lucene\solr\server\solr\WEB-INF\lib
中:
mmseg4j-solr-1.8.5.jar
mmseg4j-all-1.8.5.jar
- 下面我们添加了三个
MMSEG
的分词的分词器到solr
的E:\API\Lucene\solr\home\conf\schema.xml
<fieldType name="textComplex" class="solr.TextField" >
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="complex" dicPath="dic"/>
</analyzer>
</fieldType>
<fieldType name="textMaxWord" class="solr.TextField" >
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="max-word" dicPath="dic"/>
</analyzer>
</fieldType>
<fieldType name="textSimple" class="solr.TextField" >
<analyzer>
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="simple" dicPath="dic"/>
</analyzer>
</fieldType>
注意:最后一个绝对路径改成相对路径
将
MMSEG
中的数据(E:\API\Lucene\mmseg\data
)拷贝到solr
服务器中(E:\API\Lucene\solr\home\dic
),其中dic
是自己新建的一个目录。
注意:如果想在solr中使用中文,即让中文生效,必须在tomcat中进行指明:
2.3 入门程序(工程solr01
)
- 1、需要的依赖包
commons-codec-1.5.jar
commons-httpclient-3.1.jar
commons-io-1.4.jar
jcl-over-slf4j-1.6.1.jar
slf4j-api-1.6.1.jar
apache-solr-solrj-3.5.0.jar
apache-solr-core-3.5.0.jar
注意:不需要加入lucene
的相关包,以免冲突。
- 2、测试程序
SolrTest.java
package cn.solr.test;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.junit.Before;
import org.junit.Test;
public class SolrTest {
private final static String URL = "http://localhost:8080/solr";
@Test
public void test01(){
//创建一个solr服务器SolrServer对象(CommonsHttpSolrServer, EmbeddedSolrServer)
//第一个是需要启动web服务器,后一个是内嵌式的
try {
CommonsHttpSolrServer server = new CommonsHttpSolrServer(URL);
//server.deleteByQuery("*:*");//这里的“*:*”就表示将源服务器中的所有文档索引全部删除
//server.commit();//需要提交才能真正删除
SolrInputDocument sdoc = new SolrInputDocument();
//这一下面所有添加的域都必须在schema文件中添加,否则会报错
//id是唯一的主键,当多次添加的时候,最后添加的相同的id域会覆盖前面的域
sdoc.addField("id", "1");//id是什么类型的我们可以在schema.xml文件中查看
sdoc.addField("title", "第一个solrJ的程序");
//sdoc.addField("msg_title", "第一个solrJ的程序");
//sdoc.addField("msg_content", "不知道这个程序能不能正确执行");
//sdoc.addField("text", "测试默认域");//默认搜索的域为text
server.add(sdoc);
server.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明:然后我们在页面中使用命令*:*
查询所有可以查询出我们刚才添加的索引。我们还可以使用命令title:第一
来进行查询,发现也是可以查询到的。但是我们使用luke
进行查看(生成的索引文件放在E:\API\Lucene\solr\home\data\index
中),发现是没有进行中文分词的(因为默认使用的是lucene
的标准分词器),此时我们可以修改E:\API\Lucene\solr\home\conf\schema.xml
文件来让其使用我们添加的中文分词器(MMSEG
)。在这里我们添加自己的域:
<!--添加自己的域-->
<!--这里type要和MMSEG中的对应,存储,进行索引-->
<field name="msg_title" type="textComplex" store="true" indexed="true"/>
<field name="msg_content" type="textComplex" store="true" indexed="true"/>
注意:在程序中添加域的时候需要将名字对应:
sdoc.addField("msg_title", "第一个solrJ的程序");
此时我们再次运行测试程序,然后使用luke
查询索引,此时会发现进行了中文分词。同时注意:后面添加的索引会将前面的覆盖掉,也就是之前的title
索引内容没有了。
3、添加复合域
我们经常需要对标题和内容同时查询,使用命令:
msg_title:第一 msg_content:不知道
但是这样显然很麻烦,我们可以在schema.xml
文件中进行修改
添加了:
<field name="msg_all" type="textComplex" store="false" indexed="true" multiValued="true"/>
同时加上
<!--添加自己的copyField-->
<copyField source="msg_title" dest="msg_all"/>
<copyField source="msg_content" dest="msg_all"/>
也就是将
msg_title
和msg_content
两个域中的内容都拷贝到msg_all
中了,就可以使用msg_all
进行搜索了。然后我们重建索引。我们如果想不加
msg_all
则可以这样,先看下面这行代码:
sdoc.addField("text", "测试默认域");//默认搜索的域为text
然后我们可以进行搜索,不需要在前面加上域,发现是可以搜索到的,这是因为text
是默认搜索的域,如果我们想不加msg_all
则可以将schema.xml
中的这个域换成msg_all
,这样msg_all
便成了默认搜索的域,就不需要加上索引前缀。
三、添加文档(工程solr2
)
添加文档有两种方式,一种是像上面那样直接添加;一种是基于javabean
的添加。
对于直接添加,这里其实还有一种基于列表的添加:
package cn.solr.test;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.common.SolrInputDocument;
import org.junit.Before;
import org.junit.Test;
public class SolrTest {
private final static String URL = "http://localhost:8080/solr";
private CommonsHttpSolrServer server = null;
@Before
public void init(){
try {
server = new CommonsHttpSolrServer(URL);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
@Test
public void test02(){
try {
//基于列表的添加
List<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
SolrInputDocument sdoc = new SolrInputDocument();
sdoc.addField("id", "2");
sdoc.addField("msg_title", "很好,solr终于工作了");
sdoc.addField("msg_content", "solr总算可以正式工作了");
docs.add(sdoc);
sdoc = new SolrInputDocument();
sdoc.addField("id", "3");
sdoc.addField("msg_title", "测试solr添加");
sdoc.addField("msg_content", "看能不能添加一个列表信息");
docs.add(sdoc);
server.add(docs);
server.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
}
说明:这里我们先将每个文档添加到列表中,然后基于列表的添加,测试结果为:
下面看基于javabean
的添加:
首先我们创建一个java
对象
Message.java
package cn.solr.test;
import org.apache.solr.client.solrj.beans.Field;
public class Message {
private String id ;
private String title ;
private String[] content ;
public Message(){}
public Message(String id, String title, String[] content) {
this.id = id;
this.title = title;
this.content = content;
}
public String getId() {
return id;
}
@Field
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
@Field("msg_title")
public void setTitle(String title) {
this.title = title;
}
public String[] getContent() {
return content;
}
@Field("msg_content")
public void setContent(String[] content) {
this.content = content;
}
}
测试方法:
@Test
public void test03() {
try {
// 基于列表的添加
List<Message> msgs = new ArrayList<Message>();
msgs.add(new Message("4", "基于 java bean 的添加", new String[] {
"通过 java bean 完成添加", " java bean 的添加附件" }));
msgs.add(new Message("5", "基于 java bean 的列表数据添加", new String[] {
"测试一下", "测试两下" }));
server.addBeans(msgs);
server.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
说明:测试结果为:
这里因为
content
域为一个数组,所以我们需要为其设置:multiValued="true"
。
四、搜索
@Test
public void test04() {
//定义查询字符串
//SolrQuery query = new SolrQuery("msg_all:测试");
SolrQuery query = new SolrQuery("*:*");//查询所有
query.setStart(0);//设置查询的起始点
query.setRows(2);//设置每次查询到的条数
try {
//查询出来的结果都保存在SolrDocument中
QueryResponse resp = server.query(query);
SolrDocumentList sdl = resp.getResults();
for(SolrDocument sd : sdl){
System.out.println(sd);
System.out.println(sd.getFieldValue("msg_title"));
}
System.out.println(sdl.getNumFound());//查询到的数据总条数
} catch (SolrServerException e) {
e.printStackTrace();
}
}
@Test
public void test05() {
//SolrQuery query = new SolrQuery("msg_all:测试");
SolrQuery query = new SolrQuery("*:*");//查询所有
query.setStart(0);//设置查询的起始点
query.setRows(2);//设置每次查询到的条数
try {
QueryResponse resp = server.query(query);
//可以直接查询响应的bean对象,但是不是很常用
List<Message> list = resp.getBeans(Message.class);//将查询到的数据转换成java对象
System.out.println(list.size());
for(Message m : list){
System.out.println(m.getTitle());
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
说明:这里我们给出两种查询,第一种是基于结果集的查询,这种查询是常用的,我们可以使用此种方式进行分页、高亮等操作,而第二种是基于javabean
的查询,我们可以直接将查询到的结果转换成java
对象,但是这种查询不常用,因为不能取得获取查询的总数量。同时对于content
,如果我们设置让其存储,那么是可以查询到的。
五、高亮
@Test
public void test06() {
SolrQuery query = new SolrQuery("msg_all:测试");
// 设置高亮
query.setHighlight(true)
.setHighlightSimplePre("<span class='highligter'>")
.setHighlightSimplePost("</span>").setStart(0).setRows(2);
query.setParam("hl.fl", "msg_title,msg_content");//设置高亮的区域
try {
QueryResponse resp = server.query(query);
SolrDocumentList sdl = resp.getResults();
for (SolrDocument sd : sdl) {
String id = (String) sd.getFieldValue("id");
//注意:如果content域不存储,则是不能高亮的
System.out.println(resp.getHighlighting().get(id).get("msg_content"));
}
} catch (SolrServerException e) {
e.printStackTrace();
}
}
说明:这里要注意的是,对于想要高亮的域必须让其高亮,否则是不能高亮的。测试结果: