Solr DataImportHandler 之一 关系数据库批量和增量导数据

Description:

     大多数的应用程序将数据存储在关系数据库、xml文件中。对这样的数据进行搜索是很常见的应用。所谓的DataImportHandler提供一种可配置的方式向solr导入数据,可以一次全部导入,也可以增量导入。

      概览

        

  •      能够读取关系数据库中的数据。
  •      通过可配置的方式,能够将数据库中多列、多表的数据生成solr文档  
  •      能够通过solr文档更新solr
  •      提供 通过配置文件就能够导入所有数据的能力
  •       能够发现并处理由insert、update带来的变化(我们假定在表中有一个叫做“last-modified的列”)
  •       能够配置 “完全导入”和“增量导入”的时间
  •       让读取xml文件,并建立索引成为可配置。
  •       能够将其他的数据源(例如:ftp,scp,etc)或者其他格式的文档(Json,csv)以插件的形式集成到项目中。

          设计思路

           这个Handler首先要在solrconfig.xml文件中配置下,如下所示。

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

 从它的名字上,我们或许也可以猜到,DataImportHandler正是requestHandler的实现。我们一共需要在两个地方配置文件中进行一些配置。 
  • solrconfig.xml 。 data-config.xml必须在这个文件中配置,datasource也可以。不过,一般将datasource放在data-config.xml文件中。
  • data-config.xml
  1.    怎样获取数据?(查询语句、url等等)
  2.   要读什么样的数据(关系数据库中的列、或者xml的域)
  3.    做什么样的处理(修改/添加/删除)

      跟关系数据库一起使用

             下面几个步骤是必要的.

  •      定义一个data-config.xml 文件,并这个它的路径配置到solrconfig.xml 中关于DataImportHandler的配置中。
  •       给出Connection的信息(假设你选择在solrconfig中配置datasource)
  • 打开DataImportHandler页面去验证,是否该配置的都配置好了。http://localhost:8983/solr/dataimport
  • 使用“完全导入”命令将数据从数据库中导出,并提交给solr建立索引
  • 使用“增量导入”命令对数据库发生的变化的数据导出,并提交给solr建立索引。

           配置数据源

        将dataSource标签直接添加到dataConfig下面,即成为dataConfig的子元素.

 
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/dbname" user="db_username" password="db_password"/>
  •       数据源也可以配置在solrconfig.xml中
  • 属性type 指定了实现的类型。它是可选的。默认的实现是JdbcDataSource。
  • 属性 name  是datasources的名字,当有多个datasources时,可以使用name属性加以区分
  • 其他的属性都是随意的,根据你使用的DataSource实现而定。
  • 当然 你也可以实现自己的DataSource。

          多数据

     一个配置文件可以配置多个数据源。增加一个dataSource元素就可以增加一个数据源了。name属性可以区分不同的数据源。如果配置了多于一个的数据源,那么要注意将name配置成唯一的。

   例如:

<dataSource type="JdbcDataSource" name="ds-1" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db1-host/dbname" user="db_username" password="db_password"/> <dataSource type="JdbcDataSource" name="ds-2" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://db2-host/dbname" user="db_username" password="db_password"/>
 然后这样使用
 
.. <entity name="one" dataSource="ds-1" ...> .. </entity> <entity name="two" dataSource="ds-2" ...> .. </entity> ..
配置JdbcDataSource 
 JdbcDataSource中的属性有 
  • driver(必需的):jdbc驱动名称
  • url(必需的):jdbc链接
  • user:用户名
  • password:密码
  • 批量大小:jdbc链接中的批量大小

任何其他的在JdbcDataSource中配置的属性,都会被直接传给jdbc driver

配置data-config.xml

   solr document是schema,它的域上的值可能来自于多个表.

   data-config.xml的根元素是document。一个document元素代表了一种文档。一个document元素中包含了一个或者多个root实体。一个root实体包含着一些子实体,这些子实体能够包含其他的实体。实体就是,关系数据库上的表或者视图。每个实体都能够包含多个域,每个域对应着数据库返回结果中的一列。域的名字跟列的名字默认是一样的。如果一个列的名字跟solr field的名字不一样,那么属性name就应该要给出。其他的需要的属性在solrschema.xml文件中配置。

    为了能够从数据库中取得想要的数据,我们的设计支持标准sql规范。这使得用户能够使用他任何想要的sql语句。root实体是一个中心表,使用它的列可以把表连接在一起。

     dataconfig的结构

    dataconfig的结构不是一成不变的,entity和field元素中的属性是随意的,这主要取决于processor和transformer。

      以下是entity的默认属性

  •  name(必需的):name是唯一的,用以标识entity
  • processor:只有当datasource不是RDBMS时才是必需的。默认值是SqlEntityProcessor
  • transformer:转换器将会被应用到这个entity上,详情请浏览transformer部分。
  • pk:entity的主键,它是可选的,但使用“增量导入”的时候是必需。它跟schema.xml中定义的uniqueKey没有必然的联系,但它们可以相同。
  • rootEntity:默认情况下,document元素下就是根实体了,如果没有根实体的话,直接在实体下面的实体将会被看做跟实体。对于根实体对应的数据库中返回的数据的每一行,solr都将生成一个document。

     一下是SqlEntityProcessor的属性

 

  •  

    query (required) :sql语句

  •  

    deltaQuery : 只在“增量导入”中使用

  •  

    parentDeltaQuery : 只在“增量导入”中使用

  •  

    deletedPkQuery : 只在“增量导入”中使用

  •  

    deltaImportQuery : (只在“增量导入”中使用) . 如果这个存在,那么它将会在“增量导入”中导入phase时代替query产生作用。这里有一个命名空间的用法${dataimporter.delta.}详情请看solr1.4.

Commands

The handler 通过httprequest 向外界提供它的API . 以下是一些或许你会用到的操作

  • full-import : "完全导入"这个操作可以通过访问URL http://:/solr/dataimport?command=full-import 完成。

    • 这个操作,将会新起一个线程。response中的attribute属性将会显示busy。

    • 这个操作执行的时间取决于数据集的大小。

    • 当这个操作运行完了以后,它将在conf/dataimport.properties这个文件中记录下这个操作的开始时间

    • 当“增量导入”被执行时,stored timestamp这个时间戳将会被用到

    • solr的查询在“完全导入”时,不是阻塞的

    • 它还有下面一些参数:

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

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

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

      • debug : (default false). 工作在debug模式下。详情请看 the interactive development mode (see here)

  • delta-import : 当遇到一些增量的输入,或者发生一些变化时使用`DataImport - 航梦 - 火星?地球? http://:/solr/dataimport?command=delta-import . 它同样支持  clean, commit, optimize and debug 这几个参数.

  • status : 想要知道命令执行的状态 , 访问 URL http://:/solr/dataimport .它给出了关于文档创建、删除,查询、结果获取等等的详细状况。

  • reload-config : 如果data-config.xml已经改变,你不希望重启solr,而要重新加载配置时,运行一下的命令http://:/solr/dataimport?command=reload-config

  • abort : 你可以通过访问 url http://:/solr/dataimport?command=abort 来终止一个在运行的操作

Full Import 例子

让我们来看下面的例子. 假设我们数据库中的表结构如下:

This is a relational model of the same schema that Solr currently ships with. 我们使用这个例子来为我们的DataImportHandler建data-config.xml。我们已经使用这个结构在HSQLDB上建立了一个数据库. 好,现在开始了, 跟着下面的步骤走: 

  1. 下载 example-solr-home.jar 并使用 jar解压  jar -xvf example-solr-home.jar ,解压到你的本地系统. 这个jar文件包含了一个完整的solrhome(里面的配置文件很齐全了)和一个RSS的例子。它也包含了一个hssqldb数据库的例子.

  2. 在 example-solr-home目录, 这里有一个 solr.war. 拷贝 这个 war 文件到你的 tomcat/jetty webapps 文件夹.  这个 war file 也包含了hsqldb的JDBC driver. 如果你想在你已经有了的solr项目中部署,你只需要将  'dataimport.jar' 拷贝到 你的solr项目的 WEB-INF/lib 目录下。

  3. 使用example-data-config目录下的solr目录作为你solrhome

  4. 访问 DataImport - 航梦 - 火星?地球? http://localhost:8983/solr/dataimport 验证一下配置

  5. 访问 DataImport - 航梦 - 火星?地球? http://localhost:8983/solr/dataimport?command=full-import 执行一个“完全导入”

上面给出的solr目录是一个多核的solr home。它有两个核,一个是DB example,一个是RSSexample(新属性)。

这个例子的data-config.xml 如下:

<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document name="products"> <entity name="item" query="select * from item"> <field column="ID" name="id" /> <field column="NAME" name="name" /> <field column="MANU" name="manu" /> <field column="WEIGHT" name="weight" /> <field column="PRICE" name="price" /> <field column="POPULARITY" name="popularity" /> <field column="INSTOCK" name="inStock" /> <field column="INCLUDES" name="includes" /> <entity name="feature" query="select description from feature where item_id='${item.ID}'"> <field name="features" column="description" /> </entity> <entity name="item_category" query="select CATEGORY_ID from item_category where item_id='${item.ID}'"> <entity name="category" query="select description from category where id = '${item_category.CATEGORY_ID}'"> <field column="description" name="cat" /> </entity> </entity> </entity> </document> </dataConfig>

这里, 根实体是一个名叫“item”的表,它的主键是id。我们使用语句 "select * from item"读取数据. 每一项都拥有多个特性。看下面feature实体的查询语句

 <entity name="feature" query="select description from feature where item_id='${item.id}'"> <field name="feature" column="description" /> </entity>

feature表中的外键item_id跟item中的主键连在一起从数据库中取得该row的数据。相同地,我们将item和category连表(它们是多对多的关系)。注意,我们是怎样使用中间表和标准sql连表的

 <entity name="item_category" query="select category_id from item_category where item_id='${item.id}'">
                <entity name="category" query="select description from category where id = '${item_category.category_id}'">
                    <field column="description" name="cat" />
                </entity>
            </entity>

 

短一点的 data-config

在上面的例子中,这里有好几个从域到solr域之间的映射。如果域的名字和solr中域的名字是一样的话,完全避免使用在实体中配置域也是可以的。当然,如果你需要使用转换器的话,你还是需要加上域实体的。

下面是一个更短的版本

<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document> <entity name="item" query="select * from item"> <entity name="feature" query="select description as features from feature where item_id='${item.ID}'"/> <entity name="item_category" query="select CATEGORY_ID from item_category where item_id='${item.ID}'"> <entity name="category" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"/> </entity> </entity> </document> </dataConfig>
 

使用“增量导入”命令

你可以通过访问URL DataImport - 航梦 - 火星?地球? http://localhost:8983/solr/dataimport?command=delta-import 来使用增量导入。操作将会新起一个线程,response中的属性statue也将显示busy now。操作执行的时间取决于你的数据集的大小。在任何时候,你都可以通过访问   http://localhost:8983/solr/dataimport 来查看状态。

当 增量导入被执行的时候,它读取存储在conf/dataimport.properties中的“start time”。它使用这个时间戳来执行增量查询,完成之后,会更新这个放在conf/dataimport.properties中的时间戳。

Delta-Import 例子

我们将使用跟“完全导入”中相同的数据库。注意,数据库已经被更新了,每个表都包含有一个额外timestamp类型的列  叫做last_modified。或许你需要重新下载数据库,因为它最近被更新了。我们使用这个时间戳的域来区别出那一行是上次索引以来有更新的。

看看下面的这个 data-config.xml

<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document name="products"> <entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'"> <entity name="feature" pk="ITEM_ID" query="select description as features from feature where item_id='${item.ID}'"> </entity> <entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'"> <entity name="category" pk="ID" query="select description as cat from category where id = '${item_category.CATEGORY_ID}'"> </entity> </entity> </entity> </document> </dataConfig>

注意到item实体的 属性deltaquery了吗,它包含了一个能够查出最近更新的sql语句。注意,变量{dataimporter.last_index_time} 是DataImporthandler传过来的变量,我们叫它时间戳,它指出“完全导入”或者“部分导入”的最后运行时间。你可以在data-config.xml文件中的sql的任何地方使用这个变量,它将在processing这个过程中被赋值。

DataImport - 航梦 - 火星?地球? 注意

  • 上面例子中deltaQuery 只能够发现item中的更新,而不能发现其他表的。你可以像下面那样在一个sql语句中指定所有的表的更新。这里要特别说明一下的就是,它的细节对于一个使用者来说是一个不错的练习。DataImport - 航梦 - 火星?地球?

 deltaQuery="select id from item where id in (select item_id as id from feature where last_modified > '${dataimporter.last_index_time}') or id in (select item_id as id from item_category where item_id in (select id as item_id from category where last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}') or last_modified > '${dataimporter.last_index_time}'"
  • 写一个类似上面的庞大的deltaQuery 并不是一件很享受的工作,我们还是选择其他的方法来达到这个目的

       

<dataConfig> <dataSource driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:/temp/example/ex" user="sa" /> <document> <entity name="item" pk="ID" query="select * from item" deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}'"> <entity name="feature" pk="ITEM_ID" query="select DESCRIPTION as features from FEATURE where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID from FEATURE where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${feature.ITEM_ID}"/> <entity name="item_category" pk="ITEM_ID, CATEGORY_ID" query="select CATEGORY_ID from item_category where ITEM_ID='${item.ID}'" deltaQuery="select ITEM_ID, CATEGORY_ID from item_category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ID from item where ID=${item_category.ITEM_ID}"> <entity name="category" pk="ID" query="select DESCRIPTION as cat from category where ID = '${item_category.CATEGORY_ID}'" deltaQuery="select ID from category where last_modified > '${dataimporter.last_index_time}'" parentDeltaQuery="select ITEM_ID, CATEGORY_ID from item_category where CATEGORY_ID=${category.ID}"/> </entity> </entity> </document> </dataConfig>

除了根实体(有两个)以外,这里一共有三个查询,每个实体个一个。

查询语句,为我们取得需要建立索引的数据。

  • deltaQuery 取得从上次索引更新时间以来有更新的实体的主键。

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

下面是一些值得注意的地方:

  • 对于query语句返回的每一行,子实体的query都将被执行一次

  • 对于deltaQuery返回的每一行,parentDeltaQuery都将被执行。

  • 一旦根实体或者子实体中的行发生改变,我们将重新生成包含该行的solr文档。

 本文转自:http://blog.sina.com.cn/s/blog_496c82a90100eg4o.html

原文英文版:http://wiki.apache.org/solr/DataImportHandler

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值