使用Solr索引MySQL數據


環境搭建

1、到apache下載solr,地址:http://mirrors.hust.edu.cn/apache/lucene/solr/

2、解壓到某個目錄

3、cd into D:\Solr\solr-4.10.3\example

4、Execute the server by “java -jar startup.jar”Solr會自動運行在自帶的Jetty上

5、訪問http://localhost:8983/solr/#/

PS:solr-5.0 以上默認對schema的管理是使用managed-schema,不能手動修改,需要使用Schema Restful的API操作。如果要想手動修改配置,把managed-schema拷貝一份修改為schema.xml,在solrconfig.xml中修改如下:

<!-- <schemaFactory class="ManagedIndexSchemaFactory">
    <bool name="mutable">true</bool>
    <str name="managedSchemaResourceName">managed-schema</str>
  </schemaFactory> -->
  
<!-- <processor class="solr.AddSchemaFieldsUpdateProcessorFactory">
      <str name="defaultFieldType">strings</str>
      <lst name="typeMapping">
        <str name="valueClass">java.lang.Boolean</str>
        <str name="fieldType">booleans</str>
      </lst>
      <lst name="typeMapping">
        <str name="valueClass">java.util.Date</str>
        <str name="fieldType">tdates</str>
      </lst>
      <lst name="typeMapping">
        <str name="valueClass">java.lang.Long</str>
        <str name="valueClass">java.lang.Integer</str>
        <str name="fieldType">tlongs</str>
      </lst>
      <lst name="typeMapping">
        <str name="valueClass">java.lang.Number</str>
        <str name="fieldType">tdoubles</str>
      </lst>
    </processor> -->
    
  <schemaFactory class="ClassicIndexSchemaFactory"/>

創建MySQL數據

DataBase Name: mybatis

Table Name: user

Db.sql

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userName` varchar(50) DEFAULT NULL,
  `userAge` int(11) DEFAULT NULL,
  `userAddress` varchar(200) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'summer', '30', 'shanghai');
INSERT INTO `user` VALUES ('2', 'test1', '22', 'suzhou');
INSERT INTO `user` VALUES ('3', 'test1', '29', 'some place');
INSERT INTO `user` VALUES ('4', 'lu', '28', 'some place');
INSERT INTO `user` VALUES ('5', 'xiaoxun', '27', 'nanjing');
View Code

使用DataImportHandler導入並索引數據

1) 配置D:\Solr\solr-4.10.3\example\solr\collection1\conf\solrconfig.xml

<requestHandler name="/select" class="solr.SearchHandler">前面上加上一個dataimport的處理的Handler

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
       <lst name="defaults">
          <str name="config">data-config.xml</str>
       </lst>
  </requestHandler>

2) 在同目錄下添加data-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<dataConfig>
    <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/mybatis" user="root" password="luxx" batchSize="-1" />
  <document name="testDoc">
        <entity name="user" pk="id"
                query="select * from user">
            <field column="id" name="id"/>
           <field column="userName" name="userName"/>
            <field column="userAge" name="userAge"/>
            <field column="userAddress" name="userAddress"/>
     </entity>
  </document>
</dataConfig>

說明:

dataSource是數據庫數據源。

Entity就是一張表對應的實體,pk是主鍵,query是查詢語句。

Field對應一個字段,column是數據庫里的column名,后面的name屬性對應着Solr的Filed的名字。

3) 修改同目錄下的schema.xml,這是Solr對數據庫里的數據進行索引的模式

1)保留_version_ 這個field

2)添加索引字段:這里每個field的name要和data-config.xml里的entity的field的name一樣,一一對應。

<field name="id" type="int" indexed="true" stored="true" required="true" multiValued="false" />

<!--<field name="id" type="int" indexed="true" stored="true" required="true" multiValued="false"/> -->

<field name="userName" type="text_general" indexed="true" stored="true" />

<field name="userAge" type="int" indexed="true" stored="true" />

<field name="userAddress" type="text_general" indexed="true" stored="true" />

3)刪除多余的field,刪除copyField里的設置,這些用不上。注意:text這個field不能刪除,否則Solr啟動失敗。

<field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>

(4)設置唯一主鍵:<uniqueKey>id</uniqueKey>,注意:Solr中索引的主鍵默認是只支持type="string"字符串類型的,而我的數據庫中id是int型的,會有問題,解決方法:修改同目錄下的elevate.xml,注釋掉下面2行,這貌似是Solr的Bug,原因不明。

<doc id="MA147LL/A" />
<doc id="IW-02" exclude="true" />

4)拷貝mysql-connector-java-5.1.22-bin.jar和solr-dataimporthandler-4.10.3.jar到D:\Solr\solr-4.10.3\example\solr-webapp\webapp\WEB-INF\lib。一個是mysql的java驅動,另一個在D:\Solr\solr-4.10.3\dist目錄里,是org.apache.solr.handler.dataimport.DataImportHandler所在的jar。

重啟Solr。

如果配置正確就可以啟動成功。

solrconfig.xml是solr的基礎文件,里面配置了各種web請求處理器、請求響應處理器、日志、緩存等。

schema.xml配置映射了各種數據類型的索引方案。分詞器的配置、索引文檔中包含的字段也在此配置。

索引測試

進入Solr主頁,在Core Selector中選擇collection1:http://localhost:8983/solr/#/collection1

點擊Dataimport,Command選擇full-import(默認),點擊“Execute”,Refresh Status就可以看到結果:

Indexing completed. Added/Updated: 7 documents.Deleted 0 documents.

Requests: 1, Fetched: 7, Skipped: 0, Processed: 7

Started: 8 minutes ago

Query測試:在q中輸入userName:test1進行檢索就可以看到結果。

這里使用full-import索引了配置數據庫中的全部數據,使用Solr可以查詢對應的數據。

使用Solrj索引並檢索數據

上面是使用Solr Admin頁面上的功能測試索引和檢索,也可以使用代碼來操作Solr,下面的代碼測試了在Solr索引中添加了一個User類實體,並通過查找所有的index來返回結果。

User實體類:

package com.mybatis.test.model;

import org.apache.solr.client.solrj.beans.Field;

public class User {

    @Field
    private int id;
    
    @Field
    private String userName;
    
    @Field
    private int userAge;
    
    @Field
    private String userAddress;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserAge() {
        return userAge;
    }

    public void setUserAge(int userAge) {
        this.userAge = userAge;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    @Override
    public String toString() {
        return this.userName + " " + this.userAge + " " + this.userAddress;
    }

}

使用@Field注解的屬性要和Solr配置的Field對應。

測試代碼:

package com.solr.test;

import java.io.IOException;

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.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;

import com.mybatis.test.model.User;

public class SolrTest {
    
    private static SolrServer server;
    
    private static final String DEFAULT_URL = "http://localhost:8983/solr/collection1";
    
    public static void init() {
        server = new HttpSolrServer(DEFAULT_URL);
    }
    
    public static void indexUser(User user){
        try {
            //添加user bean到索引庫
            try {
                UpdateResponse response = server.addBean(user);
                server.commit();
                System.out.println(response.getStatus());
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } 
    }
    
    //測試添加一個新的bean實例到索引
    public static void testIndexUser(){
        User user = new User();
        user.setId(8);
        user.setUserAddress("place");
        user.setUserName("cdebcdccga");
        user.setUserAge(83);
        
        indexUser(user);
    }
    
    public static void testQueryAll() {
        SolrQuery params = new SolrQuery();
        
        // 查詢關鍵詞,*:*代表所有屬性、所有值,即所有index
        params.set("q", "*:*");
        
        // 分頁,start=0就是從0開始,rows=5當前返回5條記錄,第二頁就是變化start這個值為5就可以了。
        params.set("start", 0);
        params.set("rows", Integer.MAX_VALUE);
            
        // 排序,如果按照id排序,那么將score desc 改成 id desc(or asc)
        // params.set("sort", "score desc");
        params.set("sort", "id asc");
        
        // 返回信息*為全部,這里是全部加上score,如果不加下面就不能使用score
        params.set("fl", "*,score");
        
        QueryResponse response = null;
        try {
            response = server.query(params);
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        
        if(response!=null){
            System.out.println("Search Results: ");
            SolrDocumentList list = response.getResults();
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
        }
    }
     
    public static void main(String[] args) {
        init();
        //testIndexUser();
        testQueryAll();
    }
}

如果在數據庫中添加一條數據,但是Solr索引中沒有index這條數據,就查不到,所以一般在使用Solr檢索數據庫里的內容時,都是先插入數據庫,再在Solr中index這條數據,使用Solr的模糊查詢或是分詞功能來檢索數據庫里的內容。

DIH增量從MYSQL數據庫導入數據
已經學會了如何全量導入MySQL的數據,全量導入在數據量大的時候代價非常大,一般來說都會適用增量的方式來導入數據,下面介紹如何增量導入MYSQL數據庫中的數據,以及如何設置定時來做。

1)數據庫表的更改

前面已經創建好了一個User的表,這里為了能夠進行增量導入,需要新增一個字段updateTime,類型為timestamp,默認值為CURRENT_TIMESTAMP。

有了這樣一個字段,Solr才能判斷增量導入的時候,哪些數據是新的。

因為Solr本身有一個默認值last_index_time,記錄最后一次做full import或者是delta import(增量導入)的時間,這個值存儲在文件conf目錄的dataimport.properties文件中。

2)data-config.xml中必要屬性的設置

transformer 格式轉化:HTMLStripTransformer 索引中忽略HTML標簽

query:查詢數據庫表符合記錄數據

deltaQuery:增量索引查詢主鍵ID  注意這個只能返回ID字段   

deltaImportQuery:增量索引查詢導入的數據 

deletedPkQuery:增量索引刪除主鍵ID查詢 注意這個只能返回ID字段   

有關“query”,“deltaImportQuery”, “deltaQuery”的解釋,引用官網說明,如下所示:
The query gives the data needed to populate fields of the Solr document in full-import
The deltaImportQuery gives the data needed to populate fields when running a delta-import
The deltaQuery gives the primary keys of the current entity which have changes since the last index time

如果需要關聯子表查詢,可能需要用到parentDeltaQuery

The parentDeltaQuery uses the changed rows of the current table (fetched with deltaQuery) to give the changed rows in theparent table. This is necessary because whenever a row in the child table changes, we need to re-generate the document which has that field.

更多說明看DeltaImportHandler的說明文檔。

針對User表,data-config.xml文件的配置內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<dataConfig>
    <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/mybatis" user="root" password="luxx" batchSize="-1" />
  <document name="testDoc">
        <entity name="user" pk="id"
                query="select * from user"
                deltaImportQuery="select * from user where id='${dih.delta.id}'"
                deltaQuery="select id from user where updateTime> '${dataimporter.last_index_time}'">
            <field column="id" name="id"/>
           <field column="userName" name="userName"/>
            <field column="userAge" name="userAge"/>
            <field column="userAddress" name="userAddress"/>
<field column="updateTime" name="updateTime"/>
     </entity>
  </document>
</dataConfig>

增量索引的原理是從數據庫中根據deltaQuery指定的SQL語句查詢出所有需要增量導入的數據的ID號。

然后根據deltaImportQuery指定的SQL語句返回所有這些ID的數據,即為這次增量導入所要處理的數據。

核心思想是:通過內置變量“${dih.delta.id}”和 “${dataimporter.last_index_time}”來記錄本次要索引的id和最近一次索引的時間。

注意:剛新加上的updateTime字段也要在field屬性中配置,同時也要在schema.xml文件中配置:

<field name="updateTime" type="date" indexed="true" stored="true" />

如果業務中還有刪除操作,可以在數據庫中加一個isDeleted字段來表明該條數據是否已經被刪除,這時候Solr在更新index的時候,可以根據這個字段來更新哪些已經刪除了的記錄的索引。

這時候需要在dataConfig.xml中添加:

query="select * from user where isDeleted=0"
deltaImportQuery="select * from user where id='${dih.delta.id}'"
deltaQuery="select id from user where updateTime> '${dataimporter.last_index_time}' and isDeleted=0"
deletedPkQuery="select id from user where isDeleted=1"

這時候Solr進行增量索引的時候,就會刪除數據庫中isDeleted=1的數據的索引。

測試增量導入

如果User表里有數據,可以先清空以前的測試數據(因為加的updateTime沒有值),用我的Mybatis測試程序添加一個User,數據庫會以當前時間賦值給該字段。在Solr中使用Query查詢所有沒有查詢到該值,使用dataimport?command=delta-import增量導入,再次查詢所有就可以查詢到剛剛插入到MySQL的值。

設置增量導入為定時執行的任務

可以用Windows計划任務,或者Linux的Cron來定期訪問增量導入的連接來完成定時增量導入的功能,這其實也是可以的,而且應該沒什么問題。

但是更方便,更加與Solr本身集成度高的是利用其自身的定時增量導入功能。

1、下載apache-solr-dataimportscheduler-1.0.jar放到\solr-webapp\webapp\WEB-INF\lib目錄下:
下載地址:http://code.google.com/p/solr-dataimport-scheduler/downloads/list
也可以到百度雲盤下載:http://pan.baidu.com/s/1dDw0MRn

注意:apache-solr-dataimportscheduler-1.0.jar有bug,參考:http://www.denghuafeng.com/post-242.html

2、修改solr的WEB-INF目錄下面的web.xml文件:
為<web-app>元素添加一個子元素

<listener>
        <listener-class>
    org.apache.solr.handler.dataimport.scheduler.ApplicationListener
        </listener-class>
    </listener>

3、新建配置文件dataimport.properties:

在SOLR_HOME\solr目錄下面新建一個目錄conf(注意不是SOLR_HOME\solr\collection1下面的conf),然后用解壓文件打開apache-solr-dataimportscheduler-1.0.jar文件,將里面的dataimport.properties文件拷貝過來,進行修改,下面是最終我的自動定時更新配置文件內容:

#################################################
#                                               #
#       dataimport scheduler properties         #
#                                               #
#################################################

#  to sync or not to sync
#  1 - active; anything else - inactive
syncEnabled=1

#  which cores to schedule
#  in a multi-core environment you can decide which cores you want syncronized
#  leave empty or comment it out if using single-core deployment
#  syncCores=game,resource
syncCores=collection1

#  solr server name or IP address
#  [defaults to localhost if empty]
server=localhost

#  solr server port
#  [defaults to 80 if empty]
port=8983

#  application name/context
#  [defaults to current ServletContextListener's context (app) name]
webapp=solr

#  URLparams [mandatory]
#  remainder of URL
#http://localhost:8983/solr/collection1/dataimport?command=delta-import&clean=false&commit=true
params=/dataimport?command=delta-import&clean=false&commit=true

#  schedule interval
#  number of minutes between two runs
#  [defaults to 30 if empty]
interval=1

#  重做索引的時間間隔,單位分鍾,默認7200,即1天; 
#  為空,為0,或者注釋掉:表示永不重做索引
# reBuildIndexInterval=2

#  重做索引的參數
reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true

#  重做索引時間間隔的計時開始時間,第一次真正執行的時間=reBuildIndexBeginTime+reBuildIndexInterval*60*1000;
#  兩種格式:2012-04-11 03:10:00 或者  03:10:00,后一種會自動補全日期部分為服務啟動時的日期
reBuildIndexBeginTime=03:10:00

這里為了做測試每1分鍾就進行一次增量索引,同時disable了full-import全量索引。

4、測試

在數據庫中插入一條數據,在Solr Query中查詢,剛開始查不到,Solr進行一次增量索引后就可以查詢到了。

一般來說要在你的項目中引入Solr需要考慮以下幾點:
1、數據更新頻率:每天數據增量有多大,及時更新還是定時更新
2、數據總量:數據要保存多長時間
3、一致性要求:期望多長時間內看到更新的數據,最長允許多長時間延遲
4、數據特點:數據源包括哪些,平均單條記錄大小
5、業務特點:有哪些排序要求,檢索條件
6、資源復用:已有的硬件配置是怎樣的,是否有升級計划

 

代碼托管在GitHub上:https://github.com/luxiaoxun/Code4Java

 

參考:

http://wiki.apache.org/solr/DataImportHandler

http://wiki.apache.org/solr/Solrj

http://www.denghuafeng.com/post-242.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM