在Java中实现Lucene搜索的最佳实践

时间:2009-12-10 20:45:07

标签: java full-text-search lucene

我的Lucene索引中的每个文档都类似于stackoverflow中的帖子,我试图搜索索引(其中包含数百万个文档)。每个用户应该只能搜索用户的公司帖子。我无法控制数据的索引方式,我只需要在其上实现一个简单的搜索(可行)。

这是我的初稿:

String q = "mysql"
String companyId = "1001"

String[] fields = { "body", "subject", "number", "category", "tags"};

Float float10 = new Float(10);
Float float5 = new Float(5);

Map<String, Float> boost = new HashMap<String, Float>();
boost.put("body", float10);
boost.put("subject", float10);
boost.put("number", float5);
boost.put("category", float5);
boost.put("tags", float5);;

MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields, new StandardAnalyzer(), boost);
mfqp.setAllowLeadingWildcard(true); 
Query userQuery = mfqp.parse(q);

TermQuery companyQuery = new TermQuery(new Term("company_id", companyId));

BooleanQuery booleanQuery = new BooleanQuery();
BooleanQuery.setMaxClauseCount(50000)
booleanQuery.add(userQuery, BooleanClause.Occur.MUST);
booleanQuery.add(companyQuery, BooleanClause.Occur.MUST);

FSDirectory directory = FSDirectory.getDirectory(new File("/tmp/index"));
IndexSearcher searcher = SearcherManager.getIndexSearcherInstance(directory);
Hits hits = searcher.search(booleanQuery);

它主要在功能上工作,但我看到一些内存问题。我每隔4天,5天就得到一个Out of Memory错误,我拿了一个堆转换,看到Lucene Term和TermInfo对象在列表中排名第一。我正在使用IndexSearcher的单例实例,我只能在堆中看到它的一个实例。

对我的工作方式有任何评论吗?我做错了什么以及我能做些什么更好?

3 个答案:

答案 0 :(得分:1)

您的代码中没有明显的错误(至少不是我能说的)。使用比visualvm更强大的工具来分析你的heapdump可能是最好的。我建议使用eclipse的Memory Analyzer (MAT)(默认情况下不安装,但可以从默认更新站点获得)。太棒了。

如果您需要使用MAT的帮助,请参阅Markus Kohler撰写的此博文"Eclipse Memory Analyzer, 10 useful tips/articles"。他是该工具的作者。

答案 1 :(得分:1)

你的堆大小是多少?某些搜索是否会导致内存使用率过高?

我的猜测是,当你执行通配符查询时,你正在击中OOME。在内部,Lucene将通配符查询扩展为与通配符匹配的所有术语的OR查询。由于您允许使用前导通配符,因此会加剧此问题。运行像“body:*”这样的搜索会将正文中的每个术语加载到内存中。

我的建议是在运行通配符查询时运行内存分析器,看看你得到了什么。如果通配符查询是罪魁祸首,那么至少禁用前导通配符,或者降低查询子句限制。

答案 2 :(得分:0)

您通常在哪里遇到内存不足问题?它在这个街区附近吗?

MultiFieldQueryParser mfqp = new MultiFieldQueryParser(fields, new StandardAnalyzer(), boost);
mfqp.setAllowLeadingWildcard(true); 
Query userQuery = mfqp.parse(q);

另外,您是否在索引过程中运行查询代码?