如何在 Apache Solr 中避免 Java OutOfMemoryMemory Java 堆 Space

How to avoid Java OutOfMemoryMemory Java Heap Space in Apache Solr

我是 Java 世界的新手,最近才开始使用 Solr。 我是 运行 Amazon t2.small 盒子上的 Solr 5.2.1,它是单核和 2 gm RAM ubuntu 服务器。我 运行 Solr 具有 1gb 堆 space 配置。 Solr 核心目前有 800 万个文档,其中包含 15 个字段,其中 14 个仅为字符串 ID。另一个是 DateRange 字段类型。

搜索查询通常很长,通常 运行ge 为 15000-20000 个字符。这是因为过滤器查询在 100 秒的 运行ge 上与多个字段值一起使用。例如,

/select?fq=field1:("value-1"+OR+"value-2"+.......+OR+"value-n") , n ranges from 1000-2000

我将 Jetty 的 MaxURLLength 修改为 65535,这让我可以这样做。

之前在文档数<2M的时候,Solr运行很顺利。但是,当文档数量达到 8M 时,Solr 开始崩溃并给出 OutOfMemoryError Heap Space 错误。以下是例外情况

java.lang.OutOfMemoryError: Java heap space
    at org.apache.lucene.util.FixedBitSet.<init>(FixedBitSet.java:115)
    at org.apache.lucene.spatial.prefix.IntersectsPrefixTreeFilter.start(IntersectsPrefixTreeFilter.java:62)
    at org.apache.lucene.spatial.prefix.AbstractVisitingPrefixTreeFilter$VisitorTemplate.getDocIdSet(AbstractVisitingPrefixTreeFilter.java:130)
    at org.apache.lucene.spatial.prefix.IntersectsPrefixTreeFilter.getDocIdSet(IntersectsPrefixTreeFilter.java:57)
    at org.apache.lucene.search.Filter.scorer(Filter.java:95)
    at org.apache.lucene.search.Weight.bulkScorer(Weight.java:137)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:768)
    at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:485)
    at org.apache.solr.search.SolrIndexSearcher.getDocSetNC(SolrIndexSearcher.java:1243)
    at org.apache.solr.search.SolrIndexSearcher.getPositiveDocSet(SolrIndexSearcher.java:926)
    at org.apache.solr.search.SolrIndexSearcher.getProcessedFilter(SolrIndexSearcher.java:1088)
    at org.apache.solr.search.SolrIndexSearcher.getDocListNC(SolrIndexSearcher.java:1609)
    at org.apache.solr.search.SolrIndexSearcher.getDocListC(SolrIndexSearcher.java:1485)
    at org.apache.solr.search.SolrIndexSearcher.search(SolrIndexSearcher.java:561)
    at org.apache.solr.handler.component.QueryComponent.process(QueryComponent.java:518)
    at org.apache.solr.handler.component.SearchHandler.handleRequestBody(SearchHandler.java:255)
    at org.apache.solr.handler.RequestHandlerBase.handleRequest(RequestHandlerBase.java:143)
    at org.apache.solr.core.SolrCore.execute(SolrCore.java:2064)
    at org.apache.solr.servlet.HttpSolrCall.execute(HttpSolrCall.java:654)
    at org.apache.solr.servlet.HttpSolrCall.call(HttpSolrCall.java:450)
    at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:227)
    at org.apache.solr.servlet.SolrDispatchFilter.doFilter(SolrDispatchFilter.java:196)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:585)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
  1. 上面的异常是不是内存不足?
  2. 是否是查询太长进而影响搜索?

这可能是由于过滤器的数量所致:每个过滤器对索引中的每个文档使用 1 位。对于 8M 文档,每个过滤器使用 1MB。

如果您 solrconfig.xml 中的 filterCache 部分来自示例,则其大小为 512。这意味着随着时间的推移,它将包含 512*1MB 的索引数据。对于 1GB 的堆,运行 内存不足听起来很合理。

简单的解决方案是减少过滤器缓存中的条目数量。这可能会对您的搜索速度产生负面影响,或者它可能根本不会影响它,如果您的过滤器在调用之间是唯一的。你将不得不测试它。

https://wiki.apache.org/solr/SolrCaching#filterCache

如果您在 date 字段上进行过滤,则使用 date range filter(代替具有 100 个值的布尔 OR)将从(I/O , CPU 和 memory 的开销)每次查询扫描您的集合 100 次。

Solr 的 TrieDateField 类型以某种方式(使用 Trie)进行索引,因此查找具有范围内日期值的文档是一种廉价操作(与迭代整个集合相比)。

如果您要查询过去 1000-2000 天内日期为 "at the same time of day" 的文档,请考虑在其自己的字段中单独编码时间(作为 int 可能保存 space?) 这样您就可以在删除超过 2000 天的文档之前首先将过滤器集中在一天中的时间。