测试软件环境:

    1、16G windows7 x64  32core cpu 。

    2、jdk 1.7  tomcat 6.x  solr 4.8

数据库软件环境:

    1、16G windows7 x64  32core cpu 。

    2、Oracle 11g

一、Solr默认索引工具DIH。

  使用Solr DIH索引数据,一千九百万数据,耗时45分钟左右,每秒钟6500条/s,合计39w条每分钟。

  相关jvm最大堆内存为4G,solr index config使用默认参数。

  Solr DIH 导入截图:

  

  导入2500w条数据总耗时一个小时左右

  

  索引字段,总共15个左右

  

  (备注:字段越少,字段值越小,索引的速度也越快,因此优化Solr查询和索引效率,schema设计显得尤为重要)

二、Solrj API 索引数据。

  使用Solrj api效率稍差,合计30w每秒,耗时一个多小时。

  Solr Server配置参数同上。在客户端机器上,读取数据库数据,使用Solrj api进行索引。代码如下:

  

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StringUtils;
import com.tianditu.search.v2.POI; public class ImportPOI implements IJobDef{ private SolrServer server;
private DatasourceConfig jdbcConfig;
private SolrConfig solrConfig;
private POIImportConfig poiConfig; public DatasourceConfig getJdbcConfig() {
return jdbcConfig;
}
public void setJdbcConfig(DatasourceConfig jdbcConfig) {
this.jdbcConfig = jdbcConfig;
}
public SolrConfig getSolrConfig() {
return solrConfig;
}
public void setSolrConfig(SolrConfig solrConfig) {
this.solrConfig = solrConfig;
}
public POIImportConfig getPoiConfig() {
return poiConfig;
}
public void setPoiConfig(POIImportConfig poiConfig) {
this.poiConfig = poiConfig;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("app-spring.xml");
ImportPOI importTool = (ImportPOI) context.getBean("importPOITool");
importTool.submit(new JobDoneCallBack() { public void onCallback(JobStatus status) {
// TODO Auto-generated method stub
System.out.println(status.getStatus());
System.out.println(status.getMessage());
}
},new JobTimer() { public void onTimeUpdate(long timeCost) {
// TODO Auto-generated method stub
System.out.println("solr提交一次,距任务开始已耗时:"+timeCost/(1000*60)+"分钟"); }
}); }
public SolrServer getServer() {
return server;
}
public void setServer(SolrServer server) {
this.server = server;
} public boolean importPOI(HashMap<String, Object> params){
return false; } private POI getPOI(ResultSet rs) throws SQLException{
POI poi = new POI(); poi.setId((UUID.randomUUID()).toString());
poi.setName(rs.getString("nameforStore"));
poi.setAddress(rs.getString("addressforStore")); String lat = rs.getString("lat"); if(lat!=null&&!lat.equalsIgnoreCase("null")&&lat.length()>0){
poi.setLat(Double.valueOf(lat));
} String lon = rs.getString("lon"); //poi.setLon(rs.getDouble("lon")); if(lon!=null&&!lon.equalsIgnoreCase("null")&&lon.length()>0){
poi.setLon(Double.valueOf(lon));
} poi.setNid(rs.getString("DOCID")); String totalCity = rs.getString("totalcity");
if(!StringUtils.isEmpty(totalCity)){//---------citycode
String[] cities = totalCity.split(" ");
List<String> cs = new ArrayList<String>();
for(String c:cities){
cs.add(c);
}
poi.setCities(cs);
} String types = rs.getString("type");
if(!StringUtils.isEmpty(types)){//type-----------------
String[] typea = types.split(" ");
List<String> t = new ArrayList<String>();
for(String c:typea){
t.add(c);
}
//poi.setCities(cs);
poi.setTypes(t);
} return poi;
};
public void submit(JobDoneCallBack callback,JobTimer timer) { if(solrConfig==null){
throw new IllegalArgumentException("SolrJ未正确配置.");
} if(jdbcConfig == null){ throw new IllegalArgumentException("JDBC未正确配置.");
} if(poiConfig == null){
throw new IllegalArgumentException("POI配置文件未正确配置.");
} Connection con = null;
Statement pst = null;
ResultSet rs = null; SolrServer ss = null; JobStatus status = new JobStatus();
status.setName("ImportPOI");
status.setStatus("failure"); int i = 0;
int c = 0;
long start = System.currentTimeMillis();
try { Class.forName(jdbcConfig.getDriverClass()).newInstance();
con = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassWord()); int batchSize = Integer.valueOf(poiConfig.getImportRecordSize());
ss = new HttpSolrServer(solrConfig.getSolrUrl());
if(poiConfig.isDeleteOnstartup()){
ss.deleteByQuery("*:*");
ss.commit();
}
if(jdbcConfig.getDriverClass().toString().contains("mysql")){//mysql
pst = (com.mysql.jdbc.Statement) con.createStatement(ResultSet.FETCH_FORWARD,ResultSet.CONCUR_READ_ONLY);
pst.setFetchSize(1);
((com.mysql.jdbc.Statement) pst).enableStreamingResults();
}else{
pst = con.createStatement();
} rs = pst.executeQuery(poiConfig.getImportSQL()); POI p = null; List<POI> pois = new ArrayList<POI>(); while(rs.next()){ p = getPOI(rs); //ss.addBean(p);
pois.add(p);
if(i>=batchSize){
long commitT = System.currentTimeMillis();
//System.out.println("已耗时:"+(commitT-start)/1000*60+"分钟");
timer.onTimeUpdate((commitT-start));
//System.out.println("提交一次");
ss.addBeans(pois);
ss.commit();
pois.clear();
c++;
i=0;
}else{
i++;
} }
ss.addBeans(pois);
ss.commit();
long end = System.currentTimeMillis();
status.setStatus("success");
status.setMessage("处理成功,总耗时:"+(end-start)/1000*60+"分钟");
status.setTimeCost((end-start)/1000*60); } catch (SQLException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
} catch (SolrServerException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
status.setMessage(e.toString());
}finally{ try {
if(rs!=null){
rs.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace(); }
try {
if(pst!=null)pst.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(con!=null)
con.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} if(callback!=null){
callback.onCallback(status);
}
}
//return false;
}; }

  整个过程是读取数据库,将数据转成DTO,然后通过SolrServer.addBeans插入solr server,调用SolrServer.commit进行索引提交(就可以查询结果)。

  从数据库中读取转换过程代码如下:

  

	private POI  getPOI(ResultSet rs) throws SQLException{
POI poi = new POI(); poi.setId((UUID.randomUUID()).toString());
poi.setName(rs.getString("nameforStore"));
poi.setAddress(rs.getString("addressforStore")); String lat = rs.getString("lat"); if(lat!=null&&!lat.equalsIgnoreCase("null")&&lat.length()>0){
poi.setLat(Double.valueOf(lat));
} String lon = rs.getString("lon"); //poi.setLon(rs.getDouble("lon")); if(lon!=null&&!lon.equalsIgnoreCase("null")&&lon.length()>0){
poi.setLon(Double.valueOf(lon));
} poi.setNid(rs.getString("DOCID")); String totalCity = rs.getString("totalcity");
if(!StringUtils.isEmpty(totalCity)){//---------citycode
String[] cities = totalCity.split(" ");
List<String> cs = new ArrayList<String>();
for(String c:cities){
cs.add(c);
}
poi.setCities(cs);
} String types = rs.getString("type");
if(!StringUtils.isEmpty(types)){//type-----------------
String[] typea = types.split(" ");
List<String> t = new ArrayList<String>();
for(String c:typea){
t.add(c);
}
//poi.setCities(cs);
poi.setTypes(t);
} return poi;
};

  SolrJ索引过程代码:

  

				List<POI> pois = new ArrayList<POI>();

				while(rs.next()){//遍历JDBC ResultSet

					p = getPOI(rs);

					//ss.addBean(p);
pois.add(p);
if(i>=batchSize){//定量批量索引逻辑
long commitT = System.currentTimeMillis();
//System.out.println("已耗时:"+(commitT-start)/1000*60+"分钟");
timer.onTimeUpdate((commitT-start));
//System.out.println("提交一次");
ss.addBeans(pois);//发向SolrServer
ss.commit();
pois.clear();
c++;
i=0;
}else{
i++;
} }
ss.addBeans(pois);//做最后提交
ss.commit();

  分析:

    1、性能差别主要在哪里?

    答:方案一和方案主要差别在于,方案一访问数据之后直接调用Solr内部UpdateHandler,直接将数据放入索引。而方案二,调用SolrJ索引数据,多了一道网络IO。而且,方案二,在solrj索引之前,先将数据转换为DTO,然后Solrj将DTO转换为SolrInputDocument对象,然后SolrInputDocument对象转换成solr rest 接口所需字符串,中间有多处转换,也存在性能损耗(备注:调用Solrj addBeans批量导入索引的方法是提高性能的方式,如果一个一个的提交,性能会更差,http请求更多)。

    2、怎么优化?

    答:问题一的分析,就是问题二的答案。主要那么多数据实体转换那块,主要遵守:1、使用调用接口尽量简单,使用ResultSet直接转换成SolrInputDocument对象,少一些数据转换。2、使用数组等数据结构,替换掉目前的List<Bean>。

    3、使用Solr EmbededSolrServer直接创建索引是否能提高效率?

    答:经过测试EmbededSolrServer 可以提高索引效率,大约是DIH的一倍多。使用方式如下代码所示: 

    private SolrServer getSolrServer(){
// System.setProperty("solr.solr.home", "R:\\solrhome1\\solr\\POI\\");
CoreContainer coreContainer = new CoreContainer("R:\\solrhome1\\solr\\");
coreContainer.load();//初始化
// while(!coreContainer.isLoaded("POI")){
// System.out.println("loading...");
// }
System.out.println(coreContainer.getAllCoreNames());
server = new EmbeddedSolrServer(coreContainer,"POI");
return server; }

  (备注:EmbededSolrServer保证程序运行在Solr服务器上,是无法通过http方法的,使用场景通常是两个core,一个用此方法,完成以后,swarp一下这个core,让其对外提供检索服务)

文章转载,请注明出处:http://www.cnblogs.com/likehua/p/4465514.html

Solrj和Solr DIH索引效率对比分析的更多相关文章

  1. solr安装部署、solr测试创建core、用solrj 访问solr(索引和搜索)

    一.安装solr4.8: 1.把apache-solr-4.8.1\example\webapps下的solr.war文件拷贝到Tomcat下的Tomcat7.0\webapps目录下,tomcat启 ...

  2. 使用solrj操作solr索引库

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

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

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

  4. Lua大量字符串拼接方式效率对比及原因分析

    Lua大量字符串拼接方式效率对比及原因分析_AaronChan的博客-CSDN博客_lua字符串拼接消耗 https://blog.csdn.net/qq_26958473/article/detai ...

  5. 重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化

    重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化 一:Mysql原理与慢查询 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

  6. 微软和Google的盈利模式对比分析

    一: 微软和Google是世界上最成功科技巨头之一,但他们之间却有着不同的产品和业务,二者的盈利方式也各有不同,本文将分析和探讨的二者盈利模式的异同. 微软的盈利模式 在1975年由大学肄业的Bill ...

  7. 转: 三大WEB服务器对比分析(apache ,lighttpd,nginx) (2008年的旧文,仅供参考之用)

    from:  http://www.blogjava.net/daniel-tu/archive/2008/12/29/248883.html 三大WEB服务器对比分析(apache ,lighttp ...

  8. List集合总结,对比分析ArrayList,Vector,LinkedList

    前面已经写了三篇关于Java集合的文章,包括: Java集合 ArrayList原理及使用 再说Java集合,subList之于ArrayList Java集合 LinkedList的原理及使用 关于 ...

  9. c#数据结构之Array、ArrayList、List、LinkedList对比分析

    一.前言: 在c#数据结构中,集合的应用非常广泛,无论是做BS架构还是CS架构开发,都离不开集合的使用,比如我们常见的集合包括:Array.ArrayList.List.LinkedList等.这一些 ...

随机推荐

  1. 让你忘记 Flash 的15款精彩 HTML5 游戏

    HTML5 游戏开发是一个热门的话题,开发人员和设计人员最近经常谈论到.虽然不能迅速取代 Flash 的地位,但是 HTML5 凭借它的开放性和强大的编程能力,取代 Flash 是必然的趋势.你会看到 ...

  2. JS高程1.javascript简介

    1.javaScript诞生于1995年,最开始是为了处理以前由服务器端语言负责的一些诸如验证的操作. 2.一些名词: ECMA:European Computer Manufacturers Ass ...

  3. jQuery的document ready与 onload事件——你真的思考过吗?

    在进行实验和资料查询时,我遇到了几个关键问题: 1. window.onload到底是什么加载完触发? 2. body为什么会有onload事件? 3. 为什么是window.onload,而不是do ...

  4. python任务执行之线程,进程,与协程

    一.线程 线程为程序中执行任务的最小单元,由Threading模块提供了相关操作,线程适合于IO操作密集的情况下使用 #!/usr/bin/env python # -*- coding:utf-8 ...

  5. SharePoint 向多行文本类型字段插入特殊类型链接

    1.在测试列表中插入一个多行文本字段,名字叫做Content,如下图: 2.在Content字段里,添加一个Link,如下图: 3.尝试输入Notes格式的Link,如下图: 4.点击OK的时候,弹出 ...

  6. Android之Splash页面

    在继上个任务没有解决之后,心灰意冷之后,现在的我在跟着视频学习开发一个手机卫士的软件.在写自己的笔记之前,我先来展示一下我的结果. 下面我来总结一下我跟随视频学习到的知识点: 一.代码的组织结构: 1 ...

  7. Android.mk相关知识

    Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握jni,就必须熟练掌握Andr ...

  8. 安卓开发NDK环境搭建

    第一步preferences - android - NDK 第二步 输入ndk文件所在目录 第三步 创建文件名(右击项目,阿 androidtool - add native sppuort)

  9. IOS 音效

    IOS 音效 音效我们也可以成为短音频通常在程序中播放时间为1~2秒. 在应用程序中起到点缀效果,提升整体用户体验 音效文件只需要加载一次 示例代码: // // ViewController.m / ...

  10. iOS-UITableView的优化(纯手打原创)

    TableView的优化 一:什么是TableView的优化以及为什么要优化 1)CPU(中央处理器)和GPU(图形处理器)   CPU主要从事逻辑计算的一些工作 GPU主要从事图形处理方面的工作 2 ...