solr4.8 DataImportHandler 从关系型数据库导入数据

转载请出自出处:http://eksliang.iteye.com/blog/2097146

1.    概述

       大多数的应用程序将数据存储在关系数据库(例如oracle、mysql、sql service等等)。对这样的数据进行搜索是很常见的应用。对于这样的应用如果技术选型是Solr,就需要把数据从关系型数据库导入到solr服务器,为了解决这个问题,Apache提供了DataImportHandler,所谓的DataImportHandler就是提供一种可配置的方式向solr导入数据,可以一次全部导入,也可以增量导入,还可以声明式提供可配置的任务调度,让数据定时的从关系型数据库更新数据到solr服务器。

 2.    使用步骤

  1. 将solr发布包下面的dist/solr-dataimporthandler-extras-4.8.0.jar 和 solr-dataimporthandler-4.8.0.jar

    导入到solr的lib目录下面

  2. 在需要进行数据导入的core里面引入DataImportHandler 代码如下   

    <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
            <lst name="defaults">
                <str name="config">/home/item /data-config.xml</str>      
            </lst>
     </requestHandler>
     从它的名字上,我们或许也可以猜到,DataImportHandler正是requestHandler的实现。

     

  3. 新建data-config.xml

       在相应的目录创建上面的data-config.xml文件,不过这个文件一般都是放在conf目录下面,那么这时的应该这么写:

        

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

   4.配置data-config.xml

      最简单的实例如下: 

       

<dataConfig>  
   <!-- 数据源 -->
  <dataSource type="JdbcDataSource"  
              driver="com.mysql.jdbc.Driver"  
              url="jdbc:mysql://localhost:3306/dih"  
              user="ickes"  
              password="ickes"/>  
  <document>  
<entity name="item"  query="select id,name from item">  
       <!-- column:数据库的字段名;name:solr的字段名 -->
       <field column="id"    name="id" />
       <field column="name"  name="name" />  
       <field column="type"  name="type" />  
</entity>  
  </document>  
</dataConfig>

  最后记得把相应数据库的驱动包导入,导入后重启tomcat,进入你的solr管理页面,如下图:

  solr4.8 DataImportHandler 从关系型数据库导入数据

    当然你可以可以再url里面直接这样请求:

        http://192.168.238.133:8080/solr/dih_test/dataimport?command=full-import

    所带参数含义:

        commad:该参数可以取值:full-importdelta-importreload-configabort

 

 

 

              full-import:代表全量导入;

              delta-import:增量导入

              reload-config : 如果data-config.xml已经改变,你不希望重启solr,而要重新加载配置时,就用这个值;

              abort : 如果参数是该值,那么会终止一个在运行的操作;

        其他参数:

               clean : (default 'true'). 决定在建立索引之前,删除以前的索引;

               commit : (default 'true'). 决定这个操作之后是否要commit;

               optimize : (default 'true'). 决定这个操作之后是否要优化;

    让一个实例跑起来是不是如此的简单,下面会循序渐进的深入……!

 

       

3.DataImportHandler的参数说明

        在使用步骤中第一步:引入DataImportHandler,第二步:建立data-config.xml文件,这两个步骤是固定的,必须配置,说白了DataImportHandler需要配置就只有data-config.xml文件。

 a) 配置数据源

     如果只有一个数据源,那么可以像上面第一个实例一样配置,那么所有的entity节点中配置的sql都会引用该数据源。

如果有多个数据源,可以如下这么配置,在dataSource标签上面定义一个name的属性,注意这个name的名字必须唯一,然后在entity标签上面通过dataSource属性引用配置的dataSource。

 

<dataSource type="JdbcDataSource" name="ds-1"
	            driver="com.mysql.jdbc.Driver"
				url="jdbc:mysql://db1-host/dbname"
	            user="xxx" password="xxx"/>
	<dataSource type="JdbcDataSource" name="ds-2"
	            driver="com.mysql.jdbc.Driver"
				url="jdbc:mysql://db1-host/dbname"
	            user="xxx" password="xxx"/>
     
	<entity name="one" dataSource="ds-1" ...> </entity>
    <entity name="two" dataSource="ds-2" ...> </entity>

     多数据源配置就是如此的简单,你没有看错…..!

  

  b) 配置entity

        Entity的配置相对来说没有上面的那么” 如此的简单”,当然也是相当容易的,毕竟是Apache的东西,对吧!

 DataImportHander为了能够从数据获得想要的数据,设计支持标准的sql规范.以下是entiry的属性含义,来源于官网的翻译,英语不是很好,这是根据我理解翻译的。如果你英语厉害,可以自己去官网上浏览学习,地址如下:http://wiki.apache.org/solr/DataImportHandler

  • name(必需的):name是唯一的,用以标识entity

     

  • processor:只有当datasource不是RDBMS时才是必需的。默认值是SqlEntityProcessor

  • transformer:转换器将会被应用到这个entity上,下面章节会继续详细介绍。

  • pk:entity的主键,它是可选的,但使用“增量导入”的时候是必需。它跟schema.xml中定义的uniqueKey没有必然的联系,但它们可以相同。

  • rootEntity:默认情况下,document元素下就是根实体了,如果没有根实体的话,直接在实体下面的实体将会被看做根实体。对于根实体对应的数据库中返回的数据的每一行,solr都将生成一个document。

  • query:是获取全部数据的SQL;用于全量导入

  • deltaQuery:查询出所有经过修改的记录的ID ,可能是修改操作,添加操作,删除操作产生的;(此查询只对增量导入起作用,而且只能返回ID值,这个Id对应的是Entity标签的pk属性)
  • deletedPkQuery: 此操作值查询那些数据库里伪删除的数据的ID(即isdelete标识为1的数据) 
     solr通过它来删除索引里面对应的数据 
     (此查询只对增量导入起作用,而且只能返回ID值,这个Id对应的是Entity标签的pk属性) 

  • deltaImportQuery:获取增量数据时使用的SQL

  • parentDeltaQuer:从deltaQuery中取得当前表中更新的行,并把这些行提交给父表。因为,当子表中的一行发生改变时,我们需要更新它的父表的solr文档。

从关系型数据库导入数据到solr服务器建立索引,内容就这么多;

 

 

4.综合实例

         本实例涵盖了solr从关系型数据库导入的全部,理解本实例是进行企业级开发的关键。

    数据库模型的实体关系图如下:

 

    solr4.8 DataImportHandler 从关系型数据库导入数据

简单解释上面的模型图:

Feature(我叫他特征表)表与item(项目表)是一对多的关系,feature是一方,item是多方,feature表通过item_id引用主表item的id

 

Item表与category(类别表)表是多对多的关系,该关系通过第三张表item_category进行关联,简单理解就是拆分为两个一对多的关系。这种设计相信大家在开发都干过

 

    如下图所示(原谅的截图,让你不能复制,这是因为如果是文字,文档太丑了)是定义的与之对应的core的schema.xml文件,与数据库这个模型进行映射。  solr4.8 DataImportHandler 从关系型数据库导入数据     细心的读者可能注意到了feature_description(代表feature表的description字段)和categroy_description(代表categroy表的description字段)这两个字段的multiValued属性的值为ture,这是因为这两个字段与item表是多方的关系。

     data-config.xml配置如下图所示这是单独的增量配置:

     solr4.8 DataImportHandler 从关系型数据库导入数据

 

 

 

对上图entity标签(映射配置)解释如下:

这里, 根实体是一个名叫“item”的表,它的主键是id。我使用语句select id,name,manu,weight,price,includes from item读取数据,他的每一条记录都是对应solr的一个document。

    从上面的数据库实体关系图可以看出他与feature是一对多的关系如下,注意了,我是怎么处理这种一对多的关系的。

    如下图所示:

     solr4.8 DataImportHandler 从关系型数据库导入数据

   

相同地,我们将item和category连表(它们是多对多的关系)。注意了,我是怎样处理这种对对多的关系的。

   如下图所示:

solr4.8 DataImportHandler 从关系型数据库导入数据
    上面的${item.id}表达式的含义相信你现在已经猜出他的含义了,不错他的含义就是引用他父entity中query属性在执行完sql从结果集中取出来的值。

 

   文档写到这里,我们继续深入,上面的例子只是全量导入,下面看我怎么引入增量导入,这次我在item表上面加了一个字段create_time(创建时间),同时data-config.xml的配置如下图所示

solr4.8 DataImportHandler 从关系型数据库导入数据
 这时我最顶层的entity标签中加入一个detaQuery的属性,该属性的含义为查询出所有经过修改的记录的ID ,可能是修改操作,添加操作,删除操作产生的(此查询只对增量导入起作用,而且只能返回ID值,这个Id对应的是Entity标签的pk属性) ;然后将这些更新过的数据,从数据库拉到solr服务器的索引中,更新索引,让数据同步。

该属性的sql条件中有一个表达式{dataimporter.last_index_time},是DataImporthandler传过来的变量,它指出“完全导入”或者“部分导入”的最后运行时间。你可以在data-config.xml文件中的sql的任何地方使用这个变量。对于每次的增量导入、和全量导入这个导入时间都会保存在conf/dataimport.properties文件中,以便下次导入时引用。

     注意限制条件:deltaQuery :必须返回自己的pk

5.实例进阶

   现在有一个问题,对于detaQuery属性可以发现数据库的更新操作,但是有些应用场景要求数据的删除不能物理删除,要求他必须伪删除,也就是在表中定义一个字段isDelete,来判断这条记录是否有效。对于这个问题你可能想到的方法是在solr进行查询时,加一个条件isdelete=0查询出有效不就可以了吗,但是这样做有一个不好的地方,那就是让索引冗余了,这些无效的数据保存在数据库中就可以了,不要交给solr;我相信企业在技术选型上选择solr的原因只有一个,那就是利用solr的建立的倒排索引,来提高检索速度,这样的话索引当然是越小越好,因此这种带isdelte=1的条件查询明显不是好的一个选择。

   为了解决这个问题,Apache的攻城狮们在entity标签中引入了另外一个属性,deletedPkQuery这个属性的含义为:查询那些数据库里伪删除的数据的ID(即isdelete标识为1的数据)solr通过它来删除索引里面对应的无效数据  (此查询只对增量导入起作用,而且只能返回ID值,这个Id对应的是Entity标签的pk属性)。

为了测试这个过程,我在item表中又加了一个字段isDelete(国际惯例0代表有效、1代表无效)来标识这条记录是不是有效的,相应的我的data-config.xml变成如图下所示:

solr4.8 DataImportHandler 从关系型数据库导入数据
 
      这时伪删除的场景业务模型得到了解决。

   我还是循序渐进,接下来解决的问题是:对于上面的配置,有这么一个问题,那就是增量导入时,上面配置只能捕捉到父entity(也就是item表)数据的变动,从而将数据更新到solr,如果现在的业务是这样的,那就是当关联表(feature表、category表)的数据变动时也能联动更新索引,这个怎么做呢?强大的Apache当然考虑到了,说多了都是扯淡,直接上实例代码,如下图所示:

solr4.8 DataImportHandler 从关系型数据库导入数据
 

 

从上面代码中可以看到,我在子entity标签中加入了parentDeltaQuer,跟deltaQuery属性,其中parentDeltaQuer属性的含义如下:从deltaQuery中取得当前表中更新的行,并把这些行提交给父表。因为,当子表中的一行发生改变时,我们需要更新它的父表的solr索引。这样一来上面的问题便得到了解决。

限制条件

         子Entity的parentDeltaQuery必须引用自己的pk
         子Entity的parentDeltaQuery必须返回父Entity的pk

 

         看清楚了,一个是引用,一个是返回

 

6.原理

Full Import工作原理:

先删除当前core里面的所有数据;

执行本Entity的Query,获取所有数据;

针对每个行数据Row,获取pk,组装子Entity的Query;

执行子Entity的Query,获取子Entity的数据;

Delta Import工作原理:

执行Entity的deltaQuery,获取变化数据的pk;

合并所有子Entity parentDeltaQuery得到的主表中变化的pk;

(变化pk:包括数据中新增、修改、删除的pk,这里的变化是指数据库的变化)

得到变化pk以后,先从solr中删除在数据库中修改和删除过的索引,然后添加新增、修改、删除的索引

如果配置了deltaImportQuery,执行deltaImportQuery,将他获得数据全部插入

从这里可以看出deltaImportQuery往往是多余的,因为deltaQuery会将更新的数据插入(就已经包括了新增的数据)

7.数据同步总结

从oracle同步数据时,日期转换处理:

<entity name="users"  query="select to_char(birthday,'yyyy-MM-dd HH24:mi:ss') as birthday from USERS"  transformer="DateFormatTransformer">
     <field column="SIGNAL_TIME" name="SIGNAL_TIME" dateTimeFormat="yyyy-MM-dd HH:mm:ss"/>
</entity>

8.任务调度

   任务调度有两种,想知道怎么使用这两种,请听下篇分析;

 

 

 

 

 

 

 

 

 

 

相关推荐