实际工程应用中,从数据库导出数据创建索引再常见不过了,现在实验一下从数据库导入数据创建索引
Solr版本:4.7.0
数据库:sqlserver2005
1) solr-dataimporthandler-extras-4.7.0.jar;
在solr发布包solr-4.7.0\dist里面有
2) solr-dataimporthandler-4.7.0.jar;
在solr发布包solr-4.7.0\dist里面有
3) 连接数据的驱动包
要想哪个core从数据库导入数据建索引就修改哪个core的配置。
添加如下这段配置:
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
在solrconfig.xml同一个文件夹内建立data-config.xml,其配置如下:
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<dataSource type="JdbcDataSource"
driver="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://localHost/MyHousekeeper"
user="sa"
password="123456"/>
<document>
<entity name="pay" query="SELECT payId,payName,payMoney,payDescription,payDatetime FROM t_pay">
<field column="payId" name="id" />
<field column="payName" name="name" />
<field column="payMoney" name="money" />
<field column="payDescription" name="description" />
<field column="payDatetime" name="datetime" />
</entity>
</document>
</dataConfig>
修改这个的目的是让solr知道有哪些field,是否需要索引,是否需要在索引库中存储原文,以及field类型。在上面的sql中有很多种数据类型。
payId:整型
payName:字符型
payMoney:浮点数
payDescription:大文本
payDatetime:日期时间格式
首先在schema.xml中申明field类型,配置在<types> </types>内
下面配置的sring类型是不会做分词处理的,视为完整的一个词,text_ik是一个中文分词器ik-analyzer,专门处理中文分词。
如下:
<types>
<fieldtype name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float"class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="date"class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
</types>
然后申明field
field的名字应该和sql的查询结果集列名一致,如果不一致,需要在data-config.xml中entity标签中用field指明列column和field的名字name对应关系。
Field配置如下:
<fields>
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="id" type="long" indexed="true" stored="true" multiValued="false" required="true"/>
<field name="name" type="string" indexed="true" stored="true" multiValued="false" />
<field name="money" type="float" indexed="true" stored="true" multiValued="false" />
<field name="description" type="text_ik" indexed="true" stored="true" multiValued="false" />
<field name="datetime" type="date" indexed="true" stored="true" multiValued="false" />
</fields>
其中如下field是必须的,用于标记版本信息,由solr内部自己维护。
<field name="_version_" type="long" indexed="true" stored="true"/>
进入solr管理界面,command选择full-import全部导入;entity需要导入的实体,也就是配置的哪个sql,点击 execute执行导入,如果数据很多的话需要导一段时间,不时的点一下refresh status刷新一下,看看导入是否完成,导入完成后会告诉你导入了多少数据,用了多少时间。如下图
做个查询测试,query,
q,description:米;查询description这个field名的米相关数据
wt,json;查询结果返回格式,默认json
execute query,执行查询,看到返回的json格式的查询结果了。
参考http://m.blog.csdn.net/blog/ytp151730/41964035
http://www.aboutyun.com/thread-10496-1-1.html
前面我的文章 DIH全量导入 中已经学会了如何全量导入Oralce和MySQL的数据,大家都知道全量导入在数据量大的时候代价非常大,一般来说都会适用增量的方式来导入数据,下面介绍如何增量导入MYSQL数据库中的数据,以及如何设置 定时来做。
下面介绍的所有操作都是基于前面已经完成的全量导入的基础上来做的。
前面已经创建好了一个UserInfo的表,这里为了能够进行增量导入,需要新增一个字段,类型为TIMESTAMP,默认值为CURRENT_TIMESTAMP。
有了这样一个字段,Solr才能判断增量导入的时候,哪些数据是新的。
因为Solr本身有一个默认值last_index_time,记录最后一次做full import或者是delta import(增量导入)的时间,这个值存储在文件conf目录的dataimport.properties文件中。
<!-- transformer 格式转化:HTMLStripTransformer 索引中忽略HTML标签 --->
<!-- query:查询数据库表符合记录数据 --->
<!-- deltaQuery:增量索引查询主键ID ---> 注意这个只能返回ID字段
<!-- deltaImportQuery:增量索引查询导入的数据 --->
<!-- deletedPkQuery:增量索引删除主键ID查询 ---> 注意这个只能返回ID字段
有关“query”,“deltaImportQuery”, “deltaQuery”的解释,引用官网说明,如下所示:
The query gives the data neededto populate fields of the Solr document in full-import
The deltaImportQuery gives thedata needed to populate fields when running a delta-import
The deltaQuery gives the primarykeys of the current entity which have changes since the last index time
最终针对步骤一中创建的UserInfo表,我们的data-config.xml文件的配置内容如下:
1. <dataConfig>
2. <dataSourcetype="JdbcDataSource" driver="com.mysql.jdbc.Driver"url="jdbc:mysql://localhost:3306/test" user="root"password="passok" />
3. <document>
4. <entityname="userInfo" pk="UserID"
5. query="SELECT * FROM userinfo"
6. deltaImportQuery="SELECT * FROM userinfo whereUserID='${dih.delta.UserID}'"
7. deltaQuery="SELECT UserID FROM userinfo whereUpdateTime > '${dataimporter.last_index_time}'">
8. <field column="UserID" name="id"/>
9. <field column="UserName"name="userName"/>
10. <field column="UserAge"name="userAge"/>
11. <field column="UpdateTime"name="updateTime"/>
12. </entity>
13. </document>
14. </dataConfig>
意思是首先按照query指定的SQL语句查询出符合条件的记录。
然后从这些数据中根据deltaQuery指定的SQL语句查询出所有需要增量导入的数据的ID号。
最后根据deltaImportQuery指定的SQL语句返回所有这些ID的数据,即为这次增量导入所要处理的数据。
核心思想是:通过内置变量“${dih.delta.id}”和 “${dataimporter.last_index_time}”来记录本次要索引的id和最近一次索引的时间。
注意:刚新加上的UpdateTime字段也要在field属性中配置,同时也要在schema.xml文件中配置:
<fieldname="updateTime" type="date" indexed="true"stored="true" />
在浏览器中输入:http://localhost:8087/solr/dataimport?command=delta-import 然后到http://localhost:8087/solr/#/collection1/query检索一条不存在的数据,然后利用SQL语句插入一条数据:
1. INSERT INTO `test`.`userinfo`
2. (`UserID`,
3. `UserName`,
4. `UserAge`)
5. VALUES
6. (6,
7. '季义钦增量数据测试',
8. 25);
再次在浏览器中数据刚才的连接,再次检索。
很多人利用Windows计划任务,或者Linux的Cron来定期访问增量导入的连接来完成定时增量导入的功能,这其实也是可以的,而且应该没什么问题。
但是更方便,更加与Solr本身集成度高的是利用其自身的定时增量导入功能。
1、下载apache-solr-dataimportscheduler-1.0.jar放到Tomcat的webapps的solr目录的WEB-INF的lib目录下:
下载地址:http://code.google.com/p/solr-dataimport-scheduler/downloads/list
也可以到我的云盘下载:http://pan.baidu.com/s/1dDw0MRn
2、修改solr的WEB-INF目录下面的web.xml文件:
为<web-app>元素添加一个子元素
1. <listener>
2. <listener-class>
3. org.apache.solr.handler.dataimport.scheduler.ApplicationListener
4. </listener-class>
5. </listener>
3、新建配置文件dataimport.properties:
在SOLR_HOME\solr目录下面新建一个目录conf(注意不是SOLR_HOME\solr\collection1下面的conf),然后用解压文件打开apache-solr-dataimportscheduler-1.0.jar文件,将里面的dataimport.properties文件拷贝过来,进行修改,下面是最终我的自动定时更新配置文件内容:
1. #################################################
2. # #
3. # dataimport schedulerproperties #
4. # #
5. #################################################
6.
7. # to sync or not to sync
8. # 1 - active; anything else -inactive
9. syncEnabled=1
10.
11. # which cores to schedule
12. # in a multi-core environment you can decidewhich cores you want syncronized
13. # leave empty or comment it out if usingsingle-core deployment
14. # syncCores=game,resource #因为我的是single-core,所以注释掉了,默认就是collection1
15.
16. # solr server name or IP address
17. # [defaults to localhost if empty]
18. server=localhost
19.
20. # solr server port
21. # [defaults to 80 if empty]
22. port=8087
23.
24. # application name/context
25. # [defaults to currentServletContextListener's context (app) name]
26. webapp=solr
27.
28. # URL params [mandatory]
29. # remainder of URL
30. # 增量更新的请求参数
31. params=/dataimport?command=delta-import&clean=true&commit=true
32.
33. # schedule interval
34. # number of minutes between tworuns
35. # [defaults to 30 if empty]
36. # 这里配置的是2min一次
37. interval=2
38.
39. # 重做索引的时间间隔,单位分钟,默认7200,即5天;
40. # 为空,为0,或者注释掉:表示永不重做索引
41. reBuildIndexInterval=7200
42.
43. # 重做索引的参数
44. reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true
45.
46. # 重做索引时间间隔的计时开始时间,第一次真正执行的时间=reBuildIndexBeginTime+reBuildIndexInterval*60*1000;
47. # 两种格式:2012-04-1103:10:00 或者 03:10:00,后一种会自动补全日期部分为服务启动时的日期
48. reBuildIndexBeginTime=03:10:00
至此就完成了定时增量更新的配置,启动tomcat服务器,不需要再浏览器请求增量导入了,可以看到已经开始定期增量更新了。
1、数据更新频率:每天数据增量有多大,随时更新还是定时更新
2、数据总量:数据要保存多长时间
3、一致性要求:期望多长时间内看到更新的数据,最长允许多长时间延迟
4、数据特点:数据源包括哪些,平均单条记录大小
5、业务特点:有哪些排序要求,检索条件
6、资源复用:已有的硬件配置是怎样的,是否有升级计划
新建一张新表,同样要有UpdateTime字段:
在data-config.xml文件中增加这个表的entity配置:
1. <dataConfig>
2. <dataSourcetype="JdbcDataSource" driver="com.mysql.jdbc.Driver"url="jdbc:mysql://localhost:3306/test" user="root"password="passok" />
3. <document>
4. <entityname="userInfo" pk="UserID"
5. query="SELECT * FROM userinfo"
6. deltaImportQuery="SELECT * FROM userinfo whereUserID='${dih.delta.UserID}'"
7. deltaQuery="SELECT UserID FROM userinfo whereUpdateTime > '${dataimporter.last_index_time}'">
8. <field column="UserID" name="id"/>
9. <field column="UserName" name="userName"/>
10. <field column="UserAge"name="userAge"/>
11. <field column="UpdateTime"name="updateTime"/>
12. </entity>
13. <!-- 新加的entity -->
14. <entityname="myArticle" pk="AID"
15. query="SELECT * FROM article"
16. deltaImportQuery="SELECT * FROM article whereAID='${dih.delta.AID}'"
17. deltaQuery="SELECT AID FROM article where UpdateTime> '${dataimporter.last_index_time}'">
18. <field column="AID" name="id"/>
19. <field column="ArTitle" name="arTitle"/>
20. <field column="UpdateTime"name="updateTime"/>
21. </entity>
22. </document>
23. </dataConfig>
在schema,xml文件中增加想要索引的列的配置:
1. <!-- ===========jiyiqin add======================-->
2. <field name="userName" type="text_general"indexed="true" stored="true" />
3. <field name="userAge" type="int"indexed="true" stored="true" />
4. <field name="updateTime"type="date" indexed="true" stored="true"/>
5. <field name="arTitle"type="text_general" indexed="true" stored="true"/>
就这样启动tomcat服务器,就会自动增量导入Article这个表的数据并为ArTitle这列建立索引了。
我自己的环境是这样的,用的是oracle数据库,时间格式是yyyy-MM-ddhh24:mi:ss 2015-04-16 09:33:21 这种格式的数据库,当我在schema.xml中配置该field的type的时,如果用的是solr自带的date或者tdate,是有问题的,会报Invalid Date String 2015-04-16 09:33:21 错误。
最后的解决方法是将该field的type设置成String。
比较感谢的是solr的dataimport.properties文件中,记录该搜索核上次索引的时间格式是
last_index_time=2015-05-15 14\:30\:53,与数据库中的一致,因此在做增量查询deltaQuery的时候,日期就不用转格式了,如果是其他格式,比如timestamp格式的,则需要进行转格式。具体见《Solr DataImportHandler配置 二》这个网络日志,自己也将这个网页保存到本地了。
可能是apache-solr-dataimportscheduler-1.0.jar的一个bug,使用修改过的
solr-dataimportscheduler-1.1.jar包,自己整理的文件夹中有。
定时任务一直无法执行,后来找了很多原因,分析日志后发现增量索引的请求都没发送,又经过一番折腾才在网上找到了解决方法,是apache-solr-dataimportscheduler-1.0.jar的一个bug,post请求无法正确发送