15、solr基本使用(lucene笔记)

一、入门

在使用的时候需要和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、将相应的solrweb程序(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中配置

    1

    这里将我们的data文件夹的路径配置进去。

  • 4、设置相应的tomcatcontext
    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>

2

说明:不知道是什么原因,如果不将solr.war放在tomcat\webapps中,当从MyEclipse中启动tomcat服务器的时候就会将这段添加的内容给删除掉。所以这里我们还是将这个solr工程放在tomcat\webapps中。

  • 5、Context设置相应的环境变量,说明solr的主目录的地址。如果启动有误,我们可以将E:\API\Lucene\solr\home\conf\solrconfig.xml中的这段注释掉。即取消Velocity的输出格式。
    3

    然后就可以使用地址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的分词的分词器到solrE:\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>

注意:最后一个绝对路径改成相对路径

4

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"/>

5

注意:在程序中添加域的时候需要将名字对应:

sdoc.addField("msg_title", "第一个solrJ的程序");

此时我们再次运行测试程序,然后使用luke查询索引,此时会发现进行了中文分词。同时注意:后面添加的索引会将前面的覆盖掉,也就是之前的title索引内容没有了。

3、添加复合域
我们经常需要对标题和内容同时查询,使用命令:

msg_title:第一  msg_content:不知道

但是这样显然很麻烦,我们可以在schema.xml文件中进行修改

6

添加了:

<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"/>

7

也就是将msg_titlemsg_content两个域中的内容都拷贝到msg_all中了,就可以使用msg_all进行搜索了。然后我们重建索引。
8

9

我们如果想不加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();
        }
    }
}

说明:这里我们先将每个文档添加到列表中,然后基于列表的添加,测试结果为:

10

下面看基于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();
        }
    }

说明:测试结果为:

11

这里因为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();
        }
    }

说明:这里要注意的是,对于想要高亮的域必须让其高亮,否则是不能高亮的。测试结果:

12

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容