背景说明:在一个项目中需要将Mongodb中的数据导入到solr中完成搜索。在solr中Mysql数据库有对应的DIH包,可以通过配置sql语句完成数据的导入。Mongodb下也有开源的工具用来实现数据的导入。看了下文档,感觉这个工具对数据的定制性不高,并且是python的,不是很满足项目需求。最后决定使用solrj来完成数据的导入。

一、 遇到的问题

1. 全量数据很大,在全量或者增量时无法一次性将数据全部获取: 对数据进行分页获取。(关于两种分页获取数据的性能问题,后面会单独介绍)

2. 全量在更新数据时,需要将之前的老数据clean掉,增量则不需要: clean其实就是删除所有数据。

3. 由于使用了分页获取数据,全量的clean操作必须是在全量开始之前完成,并且为了保证在做全量过程中,之前的老数据不会丢失,删除全部数据的操作对应的commit==false,且在整个全量过程中commit==false, 在最后完成全量后,再进行commit。

4.增量操作和全量操作是通过配置不同的trigger完成的,比如增量每隔五分钟执行一次,全量则一天执行一次。如果没有对任务进行控制,可能会造成 全量和增量同时在做。刚才说了,全量操作的整个过程,commit==false, 所以对增量和全量的任务必须加互斥锁。

二、相关的实现

  1. package com.meizu.galaxy2.solr;
  2.  
  3. import org.apache.log4j.Logger;
  4. import org.apache.solr.client.solrj.SolrQuery;
  5. import org.apache.solr.client.solrj.SolrServerException;
  6. import org.apache.solr.client.solrj.impl.CloudSolrClient;
  7. import org.apache.solr.client.solrj.request.UpdateRequest;
  8. import org.apache.solr.common.SolrInputDocument;
  9. import org.apache.solr.common.params.ModifiableSolrParams;
  10.  
  11. import java.io.IOException;
  12. import java.lang.reflect.Field;
  13. import java.util.List;
  14.  
  15. /**
  16. * Created by ltao on 2015-7-16.
  17. */
  18. public class CloudSolrDIHClient {
  19.  
  20. private static final Logger logger = Logger.getLogger(CloudSolrDIHClient.class);
  21. private static final String ID_FILED_NAME = "id";
  22. private CloudSolrClient solrClient;
  23.  
  24. private static final int BATCH_SIZE=500;
  25.  
  26. private String defaultCollection;
  27.  
  28. public CloudSolrDIHClient(String zkHost, String zkNodePath, int zkClientTimeout, int zkConnectTimeout, String defaultCollection) {
  29.  
  30. if (!zkHost.startsWith("zookeeper")) {
  31. logger.error("zk host must start with zookeeper://");
  32. return;
  33. } else {
  34.  
  35. String hosts = zkHost.substring(12);
  36. hosts = hosts + zkNodePath;
  37. solrClient = new org.apache.solr.client.solrj.impl.CloudSolrClient(hosts);
  38. solrClient.setZkClientTimeout(zkClientTimeout);
  39. solrClient.setZkConnectTimeout(zkConnectTimeout);
  40. this.defaultCollection = defaultCollection;
  41. }
  42. }
  43.  
  44. public void connect() throws Exception {
  45. solrClient.connect();
  46. }
  47.  
  48. public void addDoc(SolrInputDocument doc) {
  49. if (this.defaultCollection != null) {
  50. this.addDoc(defaultCollection, doc);
  51. } else {
  52. logger.error("default collection should not be null");
  53. }
  54.  
  55. }
  56.  
  57. public void addDoc(String collection, SolrInputDocument doc) {
  58. try {
  59. solrClient.add(collection, doc);
  60. } catch (Exception e) {
  61. logger.error("add Doc occurs an error,collection:" + collection + ",doc_id:" + doc.getFieldValue(ID_FILED_NAME), e);
  62. }
  63. }
  64.  
  65. public void addDocs(List<SolrInputDocument> docs) {
  66. if (this.defaultCollection != null) {
  67. this.addDocs(defaultCollection, docs);
  68. } else {
  69. logger.error("default collection should not be null");
  70. }
  71. }
  72.  
  73. public void addDocs(String collection, List<SolrInputDocument> docs) {
  74. if(docs!=null && docs.size()>0) {
  75. int size=docs.size();
  76. if(size<=BATCH_SIZE) {
  77. try {
  78. solrClient.add(collection, docs);
  79. } catch (Exception e) {
  80. logger.error("add Docs occurs an error,collection:" + collection, e);
  81. }
  82. }
  83. else
  84. {
  85. int end=size>BATCH_SIZE? BATCH_SIZE:size;
  86. int start=0;
  87. while(true)
  88. {
  89. List<SolrInputDocument> subList=docs.subList(start,end);
  90. try {
  91. solrClient.add(collection, subList);
  92. } catch (Exception e) {
  93. logger.error("add Docs occurs an error,collection:" + collection, e);
  94. }
  95. if(end==size)
  96. {
  97. break;
  98. }
  99. start=start+BATCH_SIZE;
  100. end=(end+BATCH_SIZE);
  101. if(end>size)
  102. {
  103. end=size;
  104. }
  105. }
  106.  
  107. }
  108. }
  109.  
  110. }
  111.  
  112. public void deleteDocByIds(List<String> ids) {
  113. if (this.defaultCollection != null) {
  114. this.deleteDocByIds(defaultCollection, ids);
  115. }
  116. }
  117.  
  118. public void deleteDocByIds(String collection, List<String> ids) {
  119.  
  120. try {
  121. solrClient.deleteById(collection,ids);
  122. } catch (Exception e) {
  123. logger.error("delete Docs occurs an error,collection:" + collection ,e);
  124. }
  125.  
  126. }
  127.  
  128. public void deleteDocById(String collection, String id) {
  129. try {
  130. solrClient.deleteById(collection, id);
  131. } catch (Exception e) {
  132. logger.error("delete Doc occurs an error,collection:" + collection + ",doc_id:" + id, e);
  133. }
  134. }
  135.  
  136. public void deleteDocById(String id) {
  137. if (this.defaultCollection != null) {
  138. this.deleteDocById(defaultCollection, id);
  139.  
  140. } else {
  141. logger.error("default collection should not be null");
  142. }
  143. }
  144.  
  145. public void addBean(String collection, Object obj) {
  146. try {
  147. solrClient.addBean(collection, obj);
  148. } catch (Exception e) {
  149. String id = null;
  150. try {
  151. Field idFiled = obj.getClass().getDeclaredField(ID_FILED_NAME);
  152. if (idFiled != null) {
  153. idFiled.setAccessible(true);
  154. Object idFiledValue = idFiled.get(obj);
  155. id = idFiledValue != null ? idFiledValue.toString() : "";
  156. }
  157. } catch (Exception e1) {
  158. logger.error("get id field occurs an error", e1);
  159. }
  160. logger.error("add bean occurs an error,collection:" + collection + ",bean_id:" + id, e);
  161. }
  162. }
  163.  
  164. public void addBean(Object obj) throws SolrServerException, IOException {
  165. if (this.defaultCollection != null) {
  166. this.addBean(defaultCollection, obj);
  167. } else {
  168. logger.error("default collection should not be null");
  169. }
  170.  
  171. }
  172.  
  173. public void addBeans(List<Object> objs) throws SolrServerException, IOException {
  174. if (this.defaultCollection != null) {
  175. this.addBean(defaultCollection, objs);
  176. } else {
  177. logger.error("default collection should not be null");
  178. }
  179. }
  180.  
  181. public void addBeans(String collection, List<Object> objs) {
  182. if(objs!=null && objs.size()>0) {
  183. int size=objs.size();
  184. if(size<=BATCH_SIZE) {
  185. try {
  186. solrClient.addBeans(collection, objs);
  187. } catch (Exception e) {
  188. logger.error("addBeans occurs an error,collection:" + collection, e);
  189. }
  190. }
  191. else
  192. {
  193. int end=size>BATCH_SIZE? BATCH_SIZE:size;
  194. int start=0;
  195. while(true)
  196. {
  197. List<Object> subList=objs.subList(start,end);
  198. try {
  199. solrClient.addBeans(collection, subList);
  200. } catch (Exception e) {
  201. logger.error("addBeans occurs an error,collection:" + collection, e);
  202. }
  203. if(end==size)
  204. {
  205. break;
  206. }
  207. start=start+BATCH_SIZE;
  208. end=(end+BATCH_SIZE);
  209. if(end>size)
  210. {
  211. end=size;
  212. }
  213. }
  214.  
  215. }
  216. }
  217. }
  218.  
  219. public void commit() throws SolrServerException, IOException {
  220. this.commit(defaultCollection);
  221. }
  222.  
  223. public void commit(String collection) throws SolrServerException, IOException {
  224. solrClient.commit(collection);
  225. }
  226.  
  227. public void clean(Boolean clean) throws SolrServerException, IOException {
  228. this.clean(defaultCollection, clean);
  229. }
  230.  
  231. public void clean(String collection, Boolean clean) throws SolrServerException, IOException {
  232. UpdateRequest updateRequest = new UpdateRequest();
  233. updateRequest.setParam("stream.body", "<delete><query>*:*</query></delete>");
  234. updateRequest.setParam("commit", Boolean.toString(clean));
  235. solrClient.request(updateRequest, collection);
  236. }
  237.  
  238. public void close() throws IOException {
  239. if (solrClient != null) {
  240. solrClient.close();
  241. }
  242. }
  243.  
  244. }

上面是对solrclient的简单封装:增加、删除、clean

全量和增量进行加锁互斥

  1. private static Lock lock = new ReentrantLock();
  2.  
  3. public void importDelta() {
  4. boolean hasGetLock = false;
  5. try {
  6. hasGetLock = lock.tryLock();
  7. if (hasGetLock) {
  8. logger.info("start import delta hotel data ");
  9. long start = System.currentTimeMillis();
  10. hotelService.importDelta();
  11. long end = System.currentTimeMillis();
  12. logger.info("finish import delta hotel data ,spend " + (end - start) + " ms");
  13. }
  14. } finally {
  15. if (hasGetLock) {
  16. lock.unlock();
  17. }
  18. }
  19.  
  20. }
  21.  
  22. public void importAll() {
  23.  
  24. try {
  25. lock.lock();
  26. logger.info("start import all hotel data ");
  27. long start = System.currentTimeMillis();
  28. hotelService.importAll();
  29. long end = System.currentTimeMillis();
  30. logger.info("finish import all hotel data ,spend " + (end - start) + " ms");
  31. } finally {
  32. lock.unlock();
  33. }
  34. }
  35.  
  36. public DataImportService getHotelService() {
  37. return hotelService;
  38. }

这里用了Lock的tryLock,tryLock()会尝试获取锁,如果当前锁已被使用,则放弃该次获取锁操作。lock()则会阻塞,直到获取到锁。这样可以较大概率的保证全量一定能够执行。(如果增量一直都在运行,可能会造成全量一直阻塞,在实际运行中不会遇到这种情况;或者在某种机缘巧合下,增量一个接一个的获取到了锁,全量则一直阻塞,个人觉得应该可以使用公平锁解决刚才的这个问题,不过其实没必要)。

使用solrj进行DIH操作的更多相关文章

  1. solr的客户端操作:使用solrj进行curd操作

    导入相关的jar包 <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-s ...

  2. solr+mongo-connector+mongdb+tomcat集成

    话题:solr安装 一.下载solr 本例采用4.10.3版本. Solr所有版本下载地址:http://archive.apache.org/dist/lucene/solr/ 下载完成后,解压的目 ...

  3. Solr DataImportHandler 配置

    DIH主要用于从数据库抓取数据并创建索引.另外还能够从HTTP(RSS.ATOM)拉数据. 相关概念: Datasource:数据源,包含获取数据必需的信息:数据位置(url).数据库driver.登 ...

  4. Solrj和Solr DIH索引效率对比分析

    测试软件环境: 1.16G windows7 x64  32core cpu . 2.jdk 1.7  tomcat 6.x  solr 4.8 数据库软件环境: 1.16G windows7 x64 ...

  5. 使用solrj操作solr索引库

    (solrj)初次使用solr的开发人员总是很郁闷,不知道如何去操作solr索引库,以为只能用<五分钟solr4.5教程(搭建.运行)>中讲到的用xml文件的形式提交数据到索引库,其实没有 ...

  6. 使用solrj操作solr索引库,solr是lucene服务器

    客户端开发 Solrj 客户端开发 Solrj Solr是搭建好的lucene服务器 当然不可能完全满足一般的业务需求 可能 要针对各种的架构和业务调整 这里就需要用到Solrj了 Solrj是Sol ...

  7. 利用SolrJ操作solr API完成index操作

    使用SolrJ操作Solr会比利用httpClient来操作Solr要简单.SolrJ是封装了httpClient方法,来操作solr的API的.SolrJ底层还是通过使用httpClient中的方法 ...

  8. Solr 14 - SolrJ操作SolrCloud集群 (Solr的Java API)

    目录 1 pom.xml文件的配置 2 SolrJ操作SolrCloud 1 pom.xml文件的配置 项目的pom.xml依赖信息请参照: Solr 09 - SolrJ操作Solr单机服务 (So ...

  9. Solr 09 - SolrJ操作Solr单机服务 (Solr的Java API)

    目录 1 SolrJ是什么 2 SolrJ对索引的CRUD操作 2.1 创建Maven工程(打包方式选择为jar) 2.2 配置pom.xml文件, 加入SolrJ的依赖 2.3 添加和修改索引 2. ...

随机推荐

  1. Nginx高性能服务器安装、配置、运维 (2) —— Nginx安装

    三.Nginx 安装 使用SecureCRT以Root身份登录阿里云,在安装Nginx前先做好阿里云磁盘挂载 -------------- 挂载磁盘 -------------- 1.df -h #显 ...

  2. Java并发——线程池Executor框架

    线程池 无限制的创建线程 若采用"为每个任务分配一个线程"的方式会存在一些缺陷,尤其是当需要创建大量线程时: 线程生命周期的开销非常高 资源消耗 稳定性 引入线程池 任务是一组逻辑 ...

  3. R-大数据分析挖掘(4-R爬虫实现)

     library("XML") #获取全部的链接 url <- 'http://www.csdn.net/tag/' i_url_parse<-htmlParse(ur ...

  4. (转)使用OpenVPN的一些注意事项

    原文地址:http://www.365mini.com/page/16.htm 本文介绍的只是OpenVPN连接或使用过程中的一些注意事项,如果你尚未下载安装OpenVPN,你可以点击查看OpenVP ...

  5. JavaScript中的Date

    Date 对象用于处理日期和时间. var myDate=new Date() Date 对象会自动把当前日期和时间保存为其初始值. Date常用方法有: myDate.getYear(); //获取 ...

  6. ASP.NET的GET和POST方式的区别归纳总结

    表单提交中,ASP.NET的Get和Post方式的区别归纳如下 几点: 1. get是从服务器上获取数据,post是向服务器传送数据. 2.  get是把参数数据队列加到提交表单的ACTION属性所指 ...

  7. Java---Hibernate>>Can't create table './xxx/#sql-b2c_1a.frm' (errno: xxx)解决方法

    通用方案:删除相关表,重新生成. 1.关联表之间数据引擎不一致导致: 修改相关表的引擎设定,保持一致. 2.关联表索引字段的引用类型不一样(如A表关联字段是int,B表索引是char): 修改相关表的 ...

  8. Ubuntu 之旅—— 调整扩展屏分辨率

    打开终端输入 xrandr 得到如下信息 Screen 0: minimum 320 x 200, current 2390 x 768, maximum 8192 x 8192 LVDS conne ...

  9. ubuntu logout 命令

    gnome-session-quit 点击打开链接http://askubuntu.com/questions/15795/how-can-you-log-out-via-the-terminal

  10. php ini_set('display_errors', $value)

    正常情况下,在开发模式中,把错误显示出来,方便纠正,但在布署模式中,就得把错误关闭: ini_set('display_errors', 1); // 开启 ini_set('display_erro ...