1. 程式人生 > >Solr之基於註解開發-yellowcong

Solr之基於註解開發-yellowcong

通過註解的方式來開發Solr,Solr中,提供了一個@Field註解,可以定義實體bean和索引的關係,然後直接新增實體Bean,進行資料查詢,而不需要通過SolrInputDocument.addField 的方式進行資料的索引。需要重點注意的是1、實體類的id,必須是String型別的,在solr的schema.xml配置的2、注意schema.xml配置檔案中,filed的multiValued欄位配置

案例

Index的實體類

實體類的id,必須是String型別的,這是在solr的schema.xml已經配置過了

package com.yellowcong.index.entity;

import
org.apache.solr.client.solrj.beans.Field; public class Passage { // 用於標明solr索引的id,需要放在欄位上 @Field("id") private String id; @Field("content") private String content; @Field("username") private String username; @Field("title") private String title; public String getId
() { return id; } public void setId(String id) { this.id = id; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getUsername() { return username; } public
void setUsername(String username) { this.username = username; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

新增索引

/**
 * 新增兩個實體Bean
 * @throws Exception
 * @throws SolrServerException
 */
public static void addIndex() throws Exception, SolrServerException {
    // 建立SolrService
    SolrServer server = new HttpSolrServer(SOLR_PATH);

    Passage psg = new Passage();
    psg.setContent("我是逗比,你是不是也是啊?");
    psg.setId("1");
    psg.setTitle("逗比生涯");
    psg.setUsername("yellowcong");

    Passage psg2 = new Passage();
    psg2.setContent("我是中國人");
    psg2.setId("2");
    psg2.setTitle("中國人");
    psg2.setUsername("yellowcong");

    server.addBean(psg);
    server.addBean(psg2);

    // 提交
    server.commit();
}

查詢索引QueryResponse.getBeans

這種方式,是直接通過Bean來裝索引查詢來的資料

/**
* 作者:yellowcong <br/>
 * 日期:2017/12/04 <br/>
 * 時間:15:32:56 <br/>
 * 描述:通過Bean物件來裝資料
 */
public static void queryByBean() throws Exception {
    //查詢資料
        // 建立SolrService
        SolrServer server = new HttpSolrServer(SOLR_PATH);

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.add("q", "title:中");

        //獲取反悔資料
        QueryResponse response = server.query(solrQuery);

        //獲取之
        List<Passage> psgList = response.getBeans(Passage.class);

        for(Passage psg:psgList) {
            System.out.printf("%s:%s:%s",psg.getId(),psg.getTitle(),psg.getContent());
        }
}

通過QueryResponse.query

/**
* 作者:yellowcong <br/>
 * 日期:2017/12/04 <br/>
 * 時間:15:32:11 <br/>
 * 描述:通過QueryResponse.query 來獲取資料
 */
public static void queryByResult() throws Exception {
    // 建立SolrService
    SolrServer server = new HttpSolrServer(SOLR_PATH);

    SolrQuery solrQuery = new SolrQuery();
    solrQuery.add("q", "title:中");

    //獲取反悔資料
    QueryResponse response = server.query(solrQuery);

    //獲取查詢到的文件
    SolrDocumentList docs = response.getResults();

    System.out.println(docs.size());

    for(SolrDocument doc: docs) {
        String id  = doc.get("id").toString();
        String title  = doc.get("title").toString();
        String content  = doc.get("content").toString();
        String username  = doc.get("username").toString();
        System.out.printf("%s:%s:%s:%s",id,title,username,content);
    }
}

完整程式碼

package day12_04;

import java.util.List;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;

import com.yellowcong.index.entity.Passage;

/**
 * 作者:yellowcong <br/>
 * 日期:2017/12/04 <br/>
 * 時間:14:45:10 <br/>
 * 描述:
 */
public class Demo2 {
    // solr的伺服器地址
    private static final String SOLR_PATH = "http://192.168.66.100:8080/solr/";

    public static void main(String[] args) throws Exception {
        //新增索引 
        addIndex();

        //查詢結果,通過QueryResponse.query
        System.out.println("---------------QueryResponse.query方法-----------------");
        queryByResult();


        //實際開發通過標註的方式比較的多  
        //通過Bean 物件來裝資料
        System.out.println("---------------QueryResponse.getBeans方法-----------------");
        queryByBean();

    }
    /**
     * 作者:yellowcong <br/>
     * 日期:2017/12/04 <br/>
     * 時間:15:32:56 <br/>
     * 描述:通過Bean物件來裝資料
     */
    public static void queryByBean() throws Exception {
        //查詢資料
        // 建立SolrService
        SolrServer server = new HttpSolrServer(SOLR_PATH);

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.add("q", "title:中");

        //獲取反悔資料
        QueryResponse response = server.query(solrQuery);

        //獲取之
        List<Passage> psgList = response.getBeans(Passage.class);

        for(Passage psg:psgList) {
            System.out.printf("%s:%s:%s",psg.getId(),psg.getTitle(),psg.getContent());
        }
    }

    /**
     * 作者:yellowcong <br/>
     * 日期:2017/12/04 <br/>
     * 時間:15:32:11 <br/>
     * 描述:通過QueryResponse.query 來獲取資料
     */
    public static void queryByResult() throws Exception {
        // 建立SolrService
        SolrServer server = new HttpSolrServer(SOLR_PATH);

        SolrQuery solrQuery = new SolrQuery();
        solrQuery.add("q", "title:中");

        //獲取反悔資料
        QueryResponse response = server.query(solrQuery);

        //獲取查詢到的文件
        SolrDocumentList docs = response.getResults();

        System.out.println(docs.size());

        for(SolrDocument doc: docs) {
            String id  = doc.get("id").toString();
            String title  = doc.get("title").toString();
            String content  = doc.get("content").toString();
            String username  = doc.get("username").toString();
            System.out.printf("%s:%s:%s:%s",id,title,username,content);
        }
    }
    /**
     * 新增兩個實體Bean
     * @throws Exception
     * @throws SolrServerException
     */
    public static void addIndex() throws Exception, SolrServerException {
        // 建立SolrService
        SolrServer server = new HttpSolrServer(SOLR_PATH);

        Passage psg = new Passage();
        psg.setContent("我是逗比,你是不是也是啊?");
        psg.setId("1");
        psg.setTitle("逗比生涯");
        psg.setUsername("yellowcong");

        Passage psg2 = new Passage();
        psg2.setContent("我是中國人");
        psg2.setId("2");
        psg2.setTitle("中國人");
        psg2.setUsername("yellowcong");

        server.addBean(psg);
        server.addBean(psg2);

        // 提交
        server.commit();
    }

}


執行結果
這裡寫圖片描述

id問題

id是唯一的,如果id相同,就會認為這是一條資料,會將前面的資料更新掉。

#schema.xml 配置檔案中,id是唯一的
<uniqueKey>id</uniqueKey>

#idstring型別的,這個必須注意,索引在Index的bean中, id也是string型別的,不然直接注入不進去
 <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />

這裡寫圖片描述

環境搭建

專案結構

這裡寫圖片描述

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>yellowcong</groupId>
    <artifactId>day12_04</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>day12_04</name>
    <url>http://maven.apache.org</url>

    <!-- 配置國內比較快的 阿里雲的Maven倉庫 -->
    <repositories>
        <repository>
            <id>aliyunmaven</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
        </repository>
    </repositories>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <lucene.version>4.5.1</lucene.version>
        <mmseg4j.version>1.9.1</mmseg4j.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>

        <!-- lucene核心包 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-core</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!--QueryParser 查詢類 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-queryparser</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!-- 分詞器 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-analyzers-common</artifactId>
            <version>${lucene.version}</version>
        </dependency>
        <!-- 高亮顯示 -->
        <dependency>
            <groupId>org.apache.lucene</groupId>
            <artifactId>lucene-highlighter</artifactId>
            <version>${lucene.version}</version>
        </dependency>

        <!-- 庖丁解牛分詞器 -->
        <dependency>
            <groupId>com.chenlb.mmseg4j</groupId>
            <artifactId>mmseg4j-core</artifactId>
            <version>${mmseg4j.version}</version>
        </dependency>
        <dependency>
            <groupId>com.chenlb.mmseg4j</groupId>
            <artifactId>mmseg4j-analysis</artifactId>
            <version>${mmseg4j.version}</version>
        </dependency>

        <!-- ikanalyzer 分詞器 -->
        <dependency>
            <groupId>com.janeluo</groupId>
            <artifactId>ikanalyzer</artifactId>
            <version>2012_u6</version>
        </dependency>

        <!-- solrj -->
        <dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>4.5.1</version>
        </dependency>

        <!-- 日誌配置檔案,必須有,不然會報錯 -->
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.16</version>
        </dependency>
    </dependencies>
</project>

log4j.xml

#log4j.rootLogger=debug,Console
log4j.rootLogger=error,Console

log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c]%m%n

錯誤合集

Invalid setter method

對於Solr索引的實體bean,需要將@Field 標註放在欄位上面,而不是方法上面,下面是一個例子

Exception in thread "main" org.apache.solr.client.solrj.beans.BindingException: Invalid setter method. Must have one and only one parameter
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder$DocField.storeType(DocumentObjectBinder.java:202)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder$DocField.<init>(DocumentObjectBinder.java:150)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder.collectInfo(DocumentObjectBinder.java:119)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder.getDocFields(DocumentObjectBinder.java:99)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder.toSolrInputDocument(DocumentObjectBinder.java:73)
    at org.apache.solr.client.solrj.SolrServer.addBean(SolrServer.java:136)
    at org.apache.solr.client.solrj.SolrServer.addBean(SolrServer.java:125)
    at day12_04.Demo2.main(Demo2.java:31)

solr的實體類,所以的欄位標註,都是在Field欄位上

public class Passage {
    // 用於標明solr索引的id,需要放在欄位上
    @Field("id")
    private int id;
    @Field("content")
    private String content;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }

}

unknown field

這是由於schema.xml 配置檔案,裡面沒有username這個欄位所導致的。

Exception in thread "main" org.apache.solr.client.solrj.impl.HttpSolrServer$RemoteSolrException: ERROR: [doc=2] unknown field 'username'
    at org.apache.solr.client.solrj.impl.HttpSolrServer.request(HttpSolrServer.java:425)
    at org.apache.solr.client.solrj.impl.HttpSolrServer.request(HttpSolrServer.java:180)
    at org.apache.solr.client.solrj.request.AbstractUpdateRequest.process(AbstractUpdateRequest.java:117)
    at org.apache.solr.client.solrj.SolrServer.add(SolrServer.java:116)
    at org.apache.solr.client.solrj.SolrServer.addBean(SolrServer.java:136)
    at org.apache.solr.client.solrj.SolrServer.addBean(SolrServer.java:125)
    at day12_04.Demo2.main(Demo2.java:38)

修改配置檔案

#修改schema.xml 配置檔案
vim /usr/local/solr/solr-4.10.3/example/solr/collection1/conf/schema.xml

#新增欄位,
#name 表示索引的欄位
#type 表示用那個分詞器
#indexed 是否索引
#stored 是否儲存(對於文章內容,不要 stored)
#multiValued 表示的是否是多個數據,陣列型別的資料(這個一定要修改,不然就導致document 變成Bean 有問題)
<field name="title" type="text_general" indexed="true" stored="true" multiValued="false"/>
<field name="username" type="text_general" indexed="true" stored="true" multiValued="false"/>
<field name="content" type="text_general" indexed="false" stored="true" multiValued="false"/>


#重啟tomcat
#關閉tomcat
 /usr/local/solr/apache-tomcat-7.0.62/bin/shutdown.sh

#啟動tomcat
/usr/local/solr/apache-tomcat-7.0.62/bin/startup.sh

Solr例項化物件時,報錯提示無法例項化物件。

解決方案是:實體類的類訪問級別應該是public 的。,我剛開始是把他弄在一個類裡面的,後來導致獲取不到了,需要設定為public的

Caused by: java.lang.IllegalAccessException: Class org.apache.solr.client.solrj.beans.DocumentObjectBinder can not access a member of class day12_04.Demo2$Passage with modifiers ""
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.Class.newInstance(Class.java:436)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder.getBean(DocumentObjectBinder.java:62)
    ... 4 more

id問題( Can not set int field)

id這個欄位,必須是string型別的,因為在solr的schema.xml 配置中,設定id是string型別

Caused by: java.lang.IllegalArgumentException: Can not set int field com.yellowcong.index.entity.Passage.id to java.lang.String
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeIntegerFieldAccessorImpl.set(UnsafeIntegerFieldAccessorImpl.java:98)
    at java.lang.reflect.Field.set(Field.java:764)
    at org.apache.solr.client.solrj.beans.DocumentObjectBinder$DocField.set(DocumentObjectBinder.java:364)
    ... 6 more