问题:有一亿的数据,分100个mysql表存储,每一个表使用DIH分批导入到Solr。表中有一个标签的字段,多个标签使用逗号隔开,在solr中定义的字段设置multiValued="true",原来的配置是:
<dataConfig> <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/dmpreport" user="root" password="root" batchSize="10000"/> <document name="report"> <entity name="dmpreport0" pk="device_id_md5" query="select device_id_md5,device_id,device_type,tags1,update_time1,crowds from t_device_info_0"> <field column="device_id_md5" name="id" /> <entity name="tags" query="select split(tags1,',') as tag from t_device_info_0 where device_id_md5 = '${dmpreport0.device_id_md5}'"> <field column="tag" name="tags1" /> </entity> <entity name="crowds" query="select split(tags1,',') as crowd from t_device_info_0 where device_id_md5 = '${dmpreport0.device_id_md5}'"> <field column="crowd" name="crowds" /> </entity> </entity> </document> </dataConfig>
这样导入Sorl的话,Requests会大大增加,导入100万数据需要12分钟,1亿数据估计需要17个小时,3亿数据需要50个小时!
后来想到了修改Solr的源码,DIH导入时不再进行子查询,而是当遇到multiValued字段时,直接将数据库中逗号隔开的数据导入,使用程序将逗号隔开,修改DIH源码:
org.apache.solr.handler.dataimport.DocBuilder.java中addFieldToDoc方法改成下面这样使用split分割再进行建索引:
private void addFieldToDoc(Object value, String name, float boost, boolean multiValued, DocWrapper doc) { if (value instanceof Collection) { Collection collection = (Collection) value; if (multiValued) { for (Object o : collection) { if (o != null) doc.addField(name, o, boost); } } else { if (doc.getField(name) == null) for (Object o : collection) { if (o != null) { doc.addField(name, o, boost); break; } } } } else if (multiValued) { if (value != null) { String [] values = ((String)value).split(","); if(values != null && values.length > 0){ for(String str : values){ doc.addField(name, str, boost); } } } } else { if (doc.getField(name) == null && value != null) doc.addField(name, value, boost); } }
修改完后,将class文件覆盖solr-dataimporthandler-5.5.3.jar中的相应的class文件,重启solr服务即可!
修改完后,导入100万数据只需2分钟,大大减少了建索引的时间!