Solr索引的建立和优化
目前我知道Solr建索引有2种方法,这里介绍一下:
第一种就是我们常用的SolrServer.add(Collection<SolrInputDocument>),下面介绍一个各种SolrServer.
* HttpSolrServer,这个是我们最常用的就不说了
* ConcurrentUpdateSolrServer, 这个是创建和更新时使用,查询时不要用。保存了一个HttpSolrServer,用多线程技术并发向服务端提交索引数据,提高建索引的速度。
* LBHttpSolrServer, 这个保存了多个HttpSolrServer,进行负载均衡,提交查询时会判断哪个Server的压力最小,向那个Server提交请求。和上面相反,查询时使用,创建和更新索引时不建议使用。
* CloudSolrServer, 这个保存了一个LBHttpSolrServer,查询时和LBHttpSolrServer类似,但创建和更新索引时,在客户端会根据索引信息提交到对应的服务端。而HttpSolrServer是在服务端判断索引需要提交到哪个对应服务端,然后进行转发
* EmbeddedSolrServer,这个本地Server,单机使用,索引是保存在本地
这种建索引的方法,除EmbeddedSolrServer外,客户端除了发送数据外,服务端做了剩余的全部工作,想要提高建索引速度,就2个方案,1客户端用多线程提交索引,提高数据发送速度,但这个还取决于服务端接收数据的速度,服务端在高负荷的时候,速度就不会再提高了。2增加服务端节点数,这个就不说了,主要看硬件资源
另一种并不常见,我看了solr-map-reduce部分的代码才发现的。把建索引的过程分为了2步,
* 第一步利用EmbeddedSolrServer先在本地创建索引文件,这样客户端就分担了大部分的服务端的工作,
* 第二步利用合并索引的功能把本地索引文件提交到服务端,这里有个关键问题,就是合并索引时不再是http方式,而是磁盘目录的方式,所以本地索引文件位置必须对服务端是可见,所以要把本地索引文件共享出来,可以用NFS的方式,另一种方法就是用hdfs,solr源码里是用的hdfs。
这种建索引的方法,好处是客户端分担了不少服务端的压力,而不像前一种,除了发送数据外,其他时间都闲置了。我们可以用多线程技术,对数据分片,让客户端一边建索引,服务端同时合并已经建好的本地索引,性能大幅度的提升了。
下面贴2段关键代码,从solr源码里考出来的。
创建EmbeddedSolrServer
public EmbeddedSolrServer createEmbeddedSolrServer(Path solrHomeDir, FileSystem fs, Path outputShardDir)
throws IOException {
if (solrHomeDir == null) {
throw new IOException("Unable to find solr home setting");
}
System.out.println("Creating embedded Solr server with solrHomeDir: " + solrHomeDir + ", fs: " + fs + ", outputShardDir: " + outputShardDir);
Path solrDataDir = new Path(outputShardDir, "data");
String dataDirStr = solrDataDir.toUri().toString();
SolrResourceLoader loader = new SolrResourceLoader(solrHomeDir.toString(), null, null);
System.out.println(String
.format(
"Constructed instance information solr.home %s (%s), instance dir %s, conf dir %s, writing index to solr.data.dir %s, with permdir %s",
solrHomeDir, solrHomeDir.toUri(), loader.getInstanceDir(),
loader.getConfigDir(), dataDirStr, outputShardDir));
// TODO: This is fragile and should be well documented
System.setProperty("solr.directoryFactory", HdfsDirectoryFactory.class.getName());
System.setProperty("solr.lock.type", "hdfs");
System.setProperty("solr.hdfs.nrtcachingdirectory", "false");
System.setProperty("solr.hdfs.blockcache.enabled", "false");
System.setProperty("solr.autoCommit.maxTime", "600000");
System.setProperty("solr.autoSoftCommit.maxTime", "-1");
CoreContainer container = new CoreContainer(loader);
container.load();
Properties props = new Properties();
props.setProperty(CoreDescriptor.CORE_DATADIR, dataDirStr);
CoreDescriptor descr = new CoreDescriptor(container, "core1", solrHomeDir.toString(), props);
SolrCore core = container.create(descr);
if (!(core.getDirectoryFactory() instanceof HdfsDirectoryFactory)) {
throw new UnsupportedOperationException(
"Invalid configuration. Currently, the only DirectoryFactory supported is "
+ HdfsDirectoryFactory.class.getSimpleName());
}
EmbeddedSolrServer solr = new EmbeddedSolrServer(container, "core1");
return solr;
}
合并索引
public Request call() {
Request req = new Request();
LOG.info("Live merge " + dir.getPath() + " into " + mergeUrl);
final HttpSolrServer server = new HttpSolrServer(mergeUrl);
try {
CoreAdminRequest.MergeIndexes mergeRequest = new CoreAdminRequest.MergeIndexes();
mergeRequest.setCoreName(name);
mergeRequest.setIndexDirs(Arrays.asList(dir.getPath().toString() + "/data/index"));
try {
mergeRequest.process(server);
req.success = true;
} catch (SolrServerException e) {
req.e = e;
return req;
} catch (IOException e) {
req.e = e;
return req;
}
} finally {
server.shutdown();
}
return req;
}