你的位置:首页 > 数据库

[数据库]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;  }