首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何提高Lucene在分布式环境中的性能?

如何提高Lucene在分布式环境中的性能?
EN

Stack Overflow用户
提问于 2011-06-04 14:39:44
回答 1查看 1.8K关注 0票数 11

在分布式环境中,在主碎片实现上搜索时,我面临着很长的搜索时间(10秒的顺序)。但是,通过Luke的相同查询以毫秒为单位返回。

该应用程序是一个分布式系统。所有节点都共享索引所在的通用NFS挂载。为了简单起见,让我们考虑两个节点Node1Node2/etc/fstab条目如下所示。

代码语言:javascript
复制
nfs:/vol/indexes /opt/indexes nfs rw,suid,nodev,rsize=32768,wsize=32768,soft,intr,tcp 0 0

有多个提要(比如Feed1Feed2 )访问了系统,每个节点的每个提要都有一个碎片,每个提要有一个主提要。索引看起来就像

代码语言:javascript
复制
Feed1-master
Feed1-shard-Node1.com
Feed1-shard-Node1.com0
Feed1-shard-Node1.com1

执行搜索的代码是

代码语言:javascript
复制
FeedIndexManager fim = getManager(feedCode);
searcher = fim.getSearcher();
TopDocs docs = searcher.search(q, filter, start + max, sort);

private FeedIndexManager getManager(String feedCode) throws IOException {
  if (!_managers.containsKey(feedCode)) {
    synchronized(_managers) {
      if (!_managers.containsKey(feedCode)) {
        File shard = getShardIndexFile(feedCode);
        File master = getMasterIndexFile(feedCode);
        _managers.put(feedCode, new FeedIndexManager(shard, master));
      }
    }
  }  
  return _managers.get(feedCode);
}

FeedIndexManager如下所示。

代码语言:javascript
复制
public class FeedIndexManager implements Closeable {

  private static final Analyzer WRITE_ANALYZER = makeWriterAnalyzer();
  private final Directory _master;
  private SearcherManager _searcherManager;
  private final IndexPair _pair;

  private int _numFailedMerges = 0;
  private DateTime _lastMergeTime = new DateTime();

  public FeedIndexManager(File shard, File master) throws IOException {
    _master = NIOFSDirectory.open(master, new SimpleFSLockFactory(master));

    IndexWriter writer = null;
    try {
      writer = new IndexWriter(_master,
                               WRITE_ANALYZER, 
                               MaxFieldLength.LIMITED);
    } finally {
      if (null != writer) {
        writer.close();
      }
      writer = null;
    }

    _searcherManager = new SearcherManager(_master);
    _pair = new IndexPair(_master,
                          shard, 
                          new IndexWriterBuilder(WRITE_ANALYZER));
  }

  public IndexPair getIndexWriter() {
    return _pair;
  }

  public IndexSearcher getSearcher() {
    try {
      return _searcherManager.get();
    }
    catch (IOException ioe) {
      throw new DatastoreRuntimeException(
        "When trying to get an IndexSearcher for " + _master, ioe);
    }
  }

  public void releaseSearcher(IndexSearcher searcher) {
    try {
      _searcherManager.release(searcher);
    }
    catch (IOException ioe) {
      throw new DatastoreRuntimeException(
        "When trying to release the IndexSearcher " + searcher
        + " for " + _master, ioe);
    }
  }

  /**
   * Merges the changes from the shard into the master.
   */
  public boolean tryFlush() throws IOException {
    LOG.debug("Trying to flush index manager at " + _master
              + " after " + _numFailedMerges + " failed merges.");
    if (_pair.tryFlush()) {
      LOG.debug("I succesfully flushed " + _master);
      _numFailedMerges = 0;
      _lastMergeTime = new DateTime();
      return true;
    }
    LOG.warn("I couldn't flush " + _master + " after " + _numFailedMerges
             + " failed merges.");
    _numFailedMerges++;
    return false;
  }

  public long getMillisSinceMerge() {
    return new DateTime().getMillis() - _lastMergeTime.getMillis();
  }

  public long getNumFailedMerges() {
    return _numFailedMerges;
  }

  public void close() throws IOException {
    _pair.close();
  }

  /**
   * Return the Analyzer used for writing to indexes.
   */
  private static Analyzer makeWriterAnalyzer() {
    PerFieldAnalyzerWrapper analyzer = 
      new PerFieldAnalyzerWrapper(new LowerCaseAnalyzer());

    analyzer.addAnalyzer(SingleFieldTag.ID.toString(), new KeywordAnalyzer());
    // we want tokenizing on the CITY_STATE field
    analyzer.addAnalyzer(AddressFieldTag.CITY_STATE.toString(),
            new StandardAnalyzer(Version.LUCENE_CURRENT));
    return analyzer;
  }
}

消耗95%-98%延迟的杀手是这个调用,搜索大约需要20秒,而如果索引是通过Luke打开的,则以毫秒为单位。

代码语言:javascript
复制
TopDocs docs = searcher.search(q, filter, start + max, sort);

我有以下问题

  1. 每个饲料有多个母版是明智的,还是我应该把它减少到一个主版?该指数中的元素数约为5000万。
  2. 在实体数量少于100万的提要上,延迟时间很低(次秒响应)。实体超过200万的提要大约需要20秒。我应该只维护每个节点一个碎片,而每个提要每个节点只维护一个碎片吗?
  3. 每15秒尝试一次从碎片到主服务器的合并。应该调整这个参数吗?

我目前正在使用Lucene3.1.0和JDK1.6。这些盒子是两个64位核心,8GB内存.当前,JVM以4GBmax运行。

任何提高性能的建议都会受到高度赞赏。我已经执行了Lucene通常规定的所有标准性能调优。非常感谢你阅读了这篇长篇文章。

EN

回答 1

Stack Overflow用户

发布于 2011-06-04 14:56:14

也许这不是您想要的答案,但是请看一下弹性搜索。它是一个围绕Lucene的分布式集群服务层,它是通过HTTP查询的,也可以是嵌入式运行的。

而且速度很快,非常可笑。它似乎在封面下正确地调优了Lucene,如果您需要使用它们,它仍然公开完整的Lucene配置选项。

让Lucene在分布式环境中执行是很困难的,正如您正在发现的那样,您最终会遇到严重的锁定问题。ElasticSearch旨在解决这个特殊问题,因此您可以解决其他问题。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6237358

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档