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

一、 遇到的问题

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

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

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

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

二、相关的实现

package com.meizu.galaxy2.solr;

import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams; import java.io.IOException;
import java.lang.reflect.Field;
import java.util.List; /**
* Created by ltao on 2015-7-16.
*/
public class CloudSolrDIHClient { private static final Logger logger = Logger.getLogger(CloudSolrDIHClient.class);
private static final String ID_FILED_NAME = "id";
private CloudSolrClient solrClient; private static final int BATCH_SIZE=500; private String defaultCollection; public CloudSolrDIHClient(String zkHost, String zkNodePath, int zkClientTimeout, int zkConnectTimeout, String defaultCollection) { if (!zkHost.startsWith("zookeeper")) {
logger.error("zk host must start with zookeeper://");
return;
} else { String hosts = zkHost.substring(12);
hosts = hosts + zkNodePath;
solrClient = new org.apache.solr.client.solrj.impl.CloudSolrClient(hosts);
solrClient.setZkClientTimeout(zkClientTimeout);
solrClient.setZkConnectTimeout(zkConnectTimeout);
this.defaultCollection = defaultCollection;
}
} public void connect() throws Exception {
solrClient.connect();
} public void addDoc(SolrInputDocument doc) {
if (this.defaultCollection != null) {
this.addDoc(defaultCollection, doc);
} else {
logger.error("default collection should not be null");
} } public void addDoc(String collection, SolrInputDocument doc) {
try {
solrClient.add(collection, doc);
} catch (Exception e) {
logger.error("add Doc occurs an error,collection:" + collection + ",doc_id:" + doc.getFieldValue(ID_FILED_NAME), e);
}
} public void addDocs(List<SolrInputDocument> docs) {
if (this.defaultCollection != null) {
this.addDocs(defaultCollection, docs);
} else {
logger.error("default collection should not be null");
}
} public void addDocs(String collection, List<SolrInputDocument> docs) {
if(docs!=null && docs.size()>0) {
int size=docs.size();
if(size<=BATCH_SIZE) {
try {
solrClient.add(collection, docs);
} catch (Exception e) {
logger.error("add Docs occurs an error,collection:" + collection, e);
}
}
else
{
int end=size>BATCH_SIZE? BATCH_SIZE:size;
int start=0;
while(true)
{
List<SolrInputDocument> subList=docs.subList(start,end);
try {
solrClient.add(collection, subList);
} catch (Exception e) {
logger.error("add Docs occurs an error,collection:" + collection, e);
}
if(end==size)
{
break;
}
start=start+BATCH_SIZE;
end=(end+BATCH_SIZE);
if(end>size)
{
end=size;
}
} }
} } public void deleteDocByIds(List<String> ids) {
if (this.defaultCollection != null) {
this.deleteDocByIds(defaultCollection, ids);
}
} public void deleteDocByIds(String collection, List<String> ids) { try {
solrClient.deleteById(collection,ids);
} catch (Exception e) {
logger.error("delete Docs occurs an error,collection:" + collection ,e);
} } public void deleteDocById(String collection, String id) {
try {
solrClient.deleteById(collection, id);
} catch (Exception e) {
logger.error("delete Doc occurs an error,collection:" + collection + ",doc_id:" + id, e);
}
} public void deleteDocById(String id) {
if (this.defaultCollection != null) {
this.deleteDocById(defaultCollection, id); } else {
logger.error("default collection should not be null");
}
} public void addBean(String collection, Object obj) {
try {
solrClient.addBean(collection, obj);
} catch (Exception e) {
String id = null;
try {
Field idFiled = obj.getClass().getDeclaredField(ID_FILED_NAME);
if (idFiled != null) {
idFiled.setAccessible(true);
Object idFiledValue = idFiled.get(obj);
id = idFiledValue != null ? idFiledValue.toString() : "";
}
} catch (Exception e1) {
logger.error("get id field occurs an error", e1);
}
logger.error("add bean occurs an error,collection:" + collection + ",bean_id:" + id, e);
}
} public void addBean(Object obj) throws SolrServerException, IOException {
if (this.defaultCollection != null) {
this.addBean(defaultCollection, obj);
} else {
logger.error("default collection should not be null");
} } public void addBeans(List<Object> objs) throws SolrServerException, IOException {
if (this.defaultCollection != null) {
this.addBean(defaultCollection, objs);
} else {
logger.error("default collection should not be null");
}
} public void addBeans(String collection, List<Object> objs) {
if(objs!=null && objs.size()>0) {
int size=objs.size();
if(size<=BATCH_SIZE) {
try {
solrClient.addBeans(collection, objs);
} catch (Exception e) {
logger.error("addBeans occurs an error,collection:" + collection, e);
}
}
else
{
int end=size>BATCH_SIZE? BATCH_SIZE:size;
int start=0;
while(true)
{
List<Object> subList=objs.subList(start,end);
try {
solrClient.addBeans(collection, subList);
} catch (Exception e) {
logger.error("addBeans occurs an error,collection:" + collection, e);
}
if(end==size)
{
break;
}
start=start+BATCH_SIZE;
end=(end+BATCH_SIZE);
if(end>size)
{
end=size;
}
} }
}
} public void commit() throws SolrServerException, IOException {
this.commit(defaultCollection);
} public void commit(String collection) throws SolrServerException, IOException {
solrClient.commit(collection);
} public void clean(Boolean clean) throws SolrServerException, IOException {
this.clean(defaultCollection, clean);
} public void clean(String collection, Boolean clean) throws SolrServerException, IOException {
UpdateRequest updateRequest = new UpdateRequest();
updateRequest.setParam("stream.body", "<delete><query>*:*</query></delete>");
updateRequest.setParam("commit", Boolean.toString(clean));
solrClient.request(updateRequest, collection);
} public void close() throws IOException {
if (solrClient != null) {
solrClient.close();
}
} }

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

全量和增量进行加锁互斥

  private static Lock lock = new ReentrantLock();

    public void importDelta() {
boolean hasGetLock = false;
try {
hasGetLock = lock.tryLock();
if (hasGetLock) {
logger.info("start import delta hotel data ");
long start = System.currentTimeMillis();
hotelService.importDelta();
long end = System.currentTimeMillis();
logger.info("finish import delta hotel data ,spend " + (end - start) + " ms");
}
} finally {
if (hasGetLock) {
lock.unlock();
}
} } public void importAll() { try {
lock.lock();
logger.info("start import all hotel data ");
long start = System.currentTimeMillis();
hotelService.importAll();
long end = System.currentTimeMillis();
logger.info("finish import all hotel data ,spend " + (end - start) + " ms");
} finally {
lock.unlock();
}
} public DataImportService getHotelService() {
return hotelService;
}

这里用了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. .net+easyui系列--Pagination 分页

    使用 JS 创建分页 <div id="pat" style="background:#efefef;border:1px solid #ccc;"> ...

  2. JQ实现复选框的全选反选不选

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. JS修改JSON中key的方法

    function modifyJosnKey(json,oddkey,newkey){ var val=json[oddkey]; delete json[oddkey]; json[newkey]= ...

  4. SQL 编译与重编译

    编译的含义 当SQLSERVER收到任何一个指令,包括查询(query).批处理(batch).存储过程.触发器(trigger) .预编译指令(prepared statement)和动态SQL语句 ...

  5. Python入门 学习笔记 (二)

      今天学习了一些简单的语法规则,话不多说,开始了:      二.数据类型                常用数据类型中的整形和浮点型就不多说了.                1.字符串     ...

  6. 我眼中真正优秀的CTO

    该文转自“肉饼铺子”.作者robbin是前JavaEye网站的创始人,TOPITCLUB互联网俱乐部发起人.  原文链接 现在进入正题,最近几个月,不断有人找我推荐CTO人选,这两年互联网创业和创投实 ...

  7. CSS Masking(翻译)

    原文地址:http://www.html5rocks.com/en/tutorials/masking/adobe/ 关于计算机图形,两种常见的操作是:cliping(裁剪) and  masking ...

  8. 【ADO.NET】2、各种版本的 简单登录验证

    一.简单登录验证(防SQL注入) GetString(序号) 返回某一列的值(当用户不记得列名序号时,可使用GetOrdinal()获取到序号)GetInt32(序号) 针对的是 int 字段,返回i ...

  9. BFC与hasLayout之间的故事

    刚拒绝了一个很有诱惑的公司,不是不想去,而是对现在的能力还不确定,希望能够进一步提高自己的技能,所有想写博客了,监督自己的学习进度·········现在还没有开放博客,希望成熟一些后再开放吧! 进入正 ...

  10. 纯原生js移动端日期选择插件

    最近在项目上需要使用日期选择插件,由于是移动端的项目,对请求资源还是蛮节约的,可是百度上一搜,诶~全是基于jquery.zepto的,本来类库就很大,特别像mobiscroll这种样式文件一大堆又丑又 ...