solr使用dataimporter.request的参数实现增量导入

一、${dih.delta.id}和${dataimporter.last_index_time}实现的solr增量导入

该增量导入方式,当数据库时间慢于solr服务器时间,会导致增量导入的数据缺少记录;会发出N+1条sql,效率低。

1、 配置

1)
需要导入的表结构

create table SOLRTEST

(

  ID         number,

  EMP_NAME   VARCHAR2(100),

  CREATETIME DATE

)

2)     solr配置

i)   创建索引库

     ${solr.home}\bin\solr.cmdcreate -c solrtest

ii)  配置${solr.home}\server\solr\solrtest\conf\managed-schema文件

配置中文分词器

<fieldType name="solr_cnAnalyzer" class="solr.TextField" positionIncrementGap="100">
    		<analyzer type="index">
		  <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
		</analyzer>
		<analyzer type="query">
		  <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
		</analyzer>
</fieldType>

配置索引字段

<field name="empName" type="solr_cnAnalyzer" indexed="true" stored="true" required="true" multiValued="false" />
<field name="createtime" type="pdate" indexed="true" stored="true" required="true" multiValued="false" />

solr使用dataimporter.request的参数实现增量导入插图

iii) 指定dataImportHandler的数据源配置文件,${solr.home}\server\solr\solrtest\conf\solrconfig.xml文件中添加:

	<requestHandler name="/dataimport" class="solr.DataImportHandler">  
		<lst name="defaults">  
			<str name="config">./data-config.xml</str>  
		</lst>  
	</requestHandler>创建${solr.home}\server\solr\solrtest\conf\data-config.xml,并配置:

iv)     创建${solr.home}\server\solr\solrtest\conf\data-config.xml,并配置:

<?xml version="1.0" encoding="UTF-8" ?>  
<dataConfig>   
<dataSource type="JdbcDataSource"   
          driver="oracle.jdbc.driver.OracleDriver"   
          url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"   
          user="scott"   
          password="tiger"/>   
<document>   
    <entity pk="ID" name="solrtest" 
	        query="select * from solrtest" 
			deltaImportQuery = "select * from solrtest where id='${dih.delta.ID}'" 
			deltaQuery="select id from solrtest where createtime > to_date('${dataimporter.last_index_time}','yyyy-mm-dd hh24:mi:ss')">
         <field column="ID" name="id"/> 
         <field column="EMP_NAME" name="empName"/> 
		 <field column="CREATETIME" name="createtime"/>		 
    </entity>   	
</document>   
</dataConfig>

solr使用dataimporter.request的参数实现增量导入插图1

配置文件中,列字段(字段名带下划线,oracle数据库)使用小写,导致出错

solr使用dataimporter.request的参数实现增量导入插图2

查看${solr.home}\server\logs日志文件,有报错:

solr使用dataimporter.request的参数实现增量导入插图3

2、数据库时间慢于solr服务器时间,导致增量导入数据不一致

solr增量导入的通常配置方式是,在数据导入配置文件“data-config.xml”中配置的sql中,引用内置变量${dataimporter.last_index_time}(最近一次索引的时间)。${dataimporter.last_index_time}变量对应的是solr服务器${solr.home}\server\solr\solrtest\conf\dataimport.properties文件中记录的时间

solr使用dataimporter.request的参数实现增量导入插图4

当数据库时间慢于solr服务器时间不匹配时,导入数据会缺失,时间差的部分。

solr使用dataimporter.request的参数实现增量导入插图5

3、  发出N+1条sql,效率慢

网页中手动执行增量同步

solr使用dataimporter.request的参数实现增量导入插图6

  N+1条sql

solr使用dataimporter.request的参数实现增量导入插图7

二、使用dataimporter.request的参数实现指定范围导入

在solr导入的配置文件${solr.home}\server\solr\solrtest\conf\data-config.xml中,可以引用dataimporter.request的参数

 
solr使用dataimporter.request的参数实现增量导入插图8

网页中指定dataimporter.request的参数,导入

startTime=2018-06-01 00:00:00&endTime=2018-07-05 23:59:59

 
solr使用dataimporter.request的参数实现增量导入插图9

仅发出一条sql

select * from solrtest where createtime between to_date(‘2018-06-01 00:00:00’, ‘yyyy-mm-dd hh24:mi:ss’) and to_date(‘2018-07-05 23:59:59’, ‘yyyy-mm-dd hh24:mi:ss’) 

solr使用dataimporter.request的参数实现增量导入插图10

三、java使用solrj客户端API,实现增量导入

 
solr使用dataimporter.request的参数实现增量导入插图11

实现思路是,首先获取solr库中记录的最近日期,再导入从最近日期到当前时间点的数据

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by panzp on 2018/6/25.
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring-temp3.xml"})
public class solrImportTest {
    @Autowired
    private HttpSolrClient httpSolrClient;

    @Test
    public void testImport() throws Exception {
        importIndex();
    }

    /**
     * 首先获取solr库中记录的最近日期,再导入从最近日期到当前时间点的数据
     *
     * @throws Exception
     */
    public void importIndex() throws Exception {
        SolrQuery query = new SolrQuery();
        query.setRequestHandler("/dataimport");
        query.setParam("command","full-import");
        query.setParam("clean","false");

        //获取solr库中记录的最近日期
        Date retDate = retLastDate();
        if(retDate != null){
            //UTC时差8小时
            retDate = new Date(retDate.getTime() - 8*60*60*1000);
        }else{
            //没有记录则设置表中最早时间之前
            retDate = new Date(new Date().getTime() - 1000*24*60*60*1000);
        }

        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String sourceDate = dateFormat.format(retDate);
        //当前时间点
        String targetDate = dateFormat.format(new Date());
        query.setParam("startTime",sourceDate);
        query.setParam("endTime",targetDate);
        httpSolrClient.query(query);
    }

    //获取solr库中记录的最近日期
    public Date retLastDate() throws IOException, SolrServerException {
        SolrQuery solrQuery = new SolrQuery("*:*");
        solrQuery.addSort("createtime", SolrQuery.ORDER.desc);
        QueryResponse response = httpSolrClient.query(solrQuery);
        SolrDocumentList docs = response.getResults();
        if(docs.size()>0){
            return (Date) (docs.get(0).get("createtime"));
        }
        return null;
    }
}

标签