当我们要从数据库中导入数据到solr的索引库中,就需要自己配置data-config.xml文件来引入记录
dataconfig.xml的创建
- 首先在solrhome的core的conf文件夹加新建data-config.xml,并添加如下类似内容:
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/dp" user="root" password="123456" />
<document>
<entity name="haLock" query="select * from ha_lock" deltaQuery="select * from ha_lock">
<field column="id" name="id" />
<field column="type" name="type" />
<field column="lock_kind" name="lock_kind" />
<field column="name" name="name" />
<field column="lock_no" name="lock_no" />
</entity>
</document>
</dataConfig>
2.在managed-schema中配置相应的域,field:
<field name="type" type="string" indexed="true" stored="true"/>
<field name="lock_kind" type="string" indexed="true" stored="true"/>
<field name="lock_no" type="string" indexed="true" stored="true"/>
3.在solrconfig.xml文件中,查询到requestHandler标签的位置,并在它前面添加代码:
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
4.将solr-7.5.0\dist下的solr-dataimporthandler-7.2.1.jar和mysql驱动包mysql-connector-java-5.1.35.jar,放入…\tomcat\webapps\solr\WEB-INF\lib文件夹下;
这样一个引入数据库文档的data-config.xml基本上就建立好了
然后是关于data-config.xml文件中的一些详细配置,在标签内
- query是获取全部数据的SQL
- deltaImportQuery是获取增量数据时使用的SQL
- deltaQuery是获取pk的SQL
- parentDeltaQuery是获取父Entity的pk的SQL
Full Import(全导入)工作原理:
- 执行本Entity的Query,获取所有数据;
- 针对每个行数据Row,获取pk,组装子Entity的Query;
- 执行子Entity的Query,获取子Entity的数据。
Delta Import(增量导入)工作原理:
- 查找子Entity,直到没有为止;
- 执行Entity的deltaQuery,获取变化数据的pk;
- 合并子Entity parentDeltaQuery得到的pk;
- 针对每一个pk Row,组装父Entity的parentDeltaQuery;
- 执行parentDeltaQuery,获取父Entity的pk;
- 执行deltaImportQuery,获取自身的数据;
- 如果没有deltaImportQuery,就组装Query
限制:
- 子Entity的query必须引用父Entity的pk
- 子Entity的parentDeltaQuery必须引用自己的pk
- 子Entity的parentDeltaQuery必须返回父Entity的pk
- deltaImportQuery引用的必须是自己的pk
DataImportHandler
大多数的应用程序将数据存储在关系数据库、xml文件中。对这样的数据进行搜索是很常见的应用。所谓的DataImportHandler提供一种可配置的方式向solr导入数据,可以一次全部导入,也可以增量导入。
目标
能够读取关系数据库中的数据。
通过可配置的方式,能够将数据库中多列、多表的数据生成solr文档
能够通过solr文档更新solr
提供 通过配置文件就能够导入所有数据的能力
能够发现并处理由insert、update带来的变化(我们假定在表中有一个叫做“last-modified的列”)
能够配置 “完全导入”和“增量导入”的时间
让读取xml文件,并建立索引成为可配置。
能够将其他的数据源(例如:ftp,scp,etc)或者其他格式的文档(Json,csv)以插件的形式集成到项目中。
配置dataconfig.xml:
solr document是schema,它的域上的值可能来自于多个表.
data-config.xml的根元素是document。一个document元素代表了一种文档。一个document元素中包含了一个或者多个root实体。一个root实体包含着一些子实体,这些子实体能够包含其他的实体。实体就是,关系数据库上的表或者视图。每个实体都能够包含多个域,每个域对应着数据库返回结果中的一列。域的名字跟列的名字默认是一样的。如果一个列的名字跟solr field的名字不一样,那么属性name就应该要给出。其他的需要的属性在solrschema.xml文件中配置。
为了能够从数据库中取得想要的数据,我们的设计支持标准sql规范。这使得用户能够使用他任何想要的sql语句。root实体是一个中心表,使用它的列可以把表连接在一起。
dataconfig的结构
以下是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.}
Commands
The handler 通过httprequest 向外界提供它的API . 以下是一些或许你会用到的操作
(1). 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)
-
(2). delta-import : 当遇到一些增量的输入,或者发生一些变化时使用 http://:/solr/dataimport?command=delta-import . 它同样支持 clean, commit, optimize and debug 这几个参数.
(3). status : 想要知道命令执行的状态 , 访问 URL http://:/solr/dataimport .它给出了关于文档创建、删除,查询、结果获取等等的详细状况。
(4). reload-config : 如果data-config.xml已经改变,你不希望重启solr,而要重新加载配置时,运行一下的命令http://:/solr/dataimport?command=reload-config
(5). abort : 你可以通过访问 url http://:/solr/dataimport?command=abort 来终止一个在运行的操作
看一个full import的例子
<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>
这里, 根实体是一个名叫“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中域的名字是一样的话,完全避免使用在实体中配置域也是可以的。当然,如果你需要使用转换器的话,你还是需要加上域实体的。
下面是一个更短的版本:
<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>
简洁了很多
增量导入命令
你可以通过访问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:
<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>
注意到item实体的 属性deltaquery了吗,它包含了一个能够查出最近更新的sql语句。注意,变量{dataimporter.last_index_time} 是DataImporthandler传过来的变量,我们叫它时间戳,它指出“完全导入”或者“部分导入”的最后运行时间。你可以在data-config.xml文件中的sql的任何地方使用这个变量,它将在processing这个过程中被赋值。
注意上面例子中deltaQuery 只能够发现item中的更新,而不能发现其他表的。你可以像下面那样在一个sql语句中指定所有的表的更新。这里要特别说明一下的就是,它的细节对于一个使用者来说是一个不错的练习。
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文档。
关于两种数据导入就是这样,更具体内容:https://blog.csdn.net/boolbo/article/details/50352331#commentBox