精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-11-25
最后修改:2008-11-25
本文主要讨论solr中的dataImportHandler机制,对这个不熟的朋友,可以先看下。solr wiki中的dataimporthandler这篇文章,笔者也对dataimporthandler进行了一些翻译,不过效果不是很好,有兴趣的朋友也可以参考一下。 http://mxsfengg.blog.163.com/blog/static/26370218200810250524813/。 想对比较多的数据建立索引,当然要考虑一个量的问题。之前怀疑sqlEntityProcessor是一条条的去数据库中取数据的,因为还有个CachedSqlEntityProcessor,这个类的名字看起来更像是一个能够批量去数据的家伙。 当然事实证明,笔者之前的想法是错的。 对于完全导入、即是full-import,来说,我们只需要关注nextRow() 方法的实现。
public Map<String, Object> nextRow() { //从缓存中取(在sqlEntityProcessor中这个应该是null,因为在设计上,sqlEntityPorcessor并没有实现缓存。) if (rowcache != null) { return getFromRowCache(); } // 这个只是为了防止rowIterator==null的出现吧 if (rowIterator == null) { String q = getQuery(); initQuery(resolver.replaceTokens(q)); } while (true) { Map<String, Object> r = getNext(); if (r == null) { return null; } // 使用转化器 r = applyTransformer(r); if (r != null) { return r; } } } 我们可以看到,nextRow一开始去检测 rowcache,这应该是一个缓存的机制,目前,还没有遇到rowcache!=null的情况。我们发现nextRow实际上调用的是getNext(), protected Map<String, Object> getNext() { try { if (rowIterator == null) { return null; } if (rowIterator.hasNext()) { return rowIterator.next(); } //如果一个批次结束了,那么就将这个rowIterator,query置为null。 rowIterator = null; query = null; return null; } catch (Exception e) { LOG.log(Level.SEVERE, "getNext() failed for query '" + query + "'", e); rowIterator = null; query = null; throw new DataImportHandlerException(DataImportHandlerException.WARN, e); } } 而getNext(),又是简单的调用了,rowIterator的next,我们可以这么认为,nextRow()其实就是返回rowIterator的next()。 SqlEntityProcessor一次性的从数据库中将数据取出来放在了rowIterator中,供DocBuilder调用。 粗略的看一下 Docbuilder中的buildDocument这个方法。
@SuppressWarnings("unchecked")
private void buildDocument(VariableResolverImpl vr, SolrWriter.SolrDoc doc,
Map<String, Object> pk, DataConfig.Entity entity, boolean isRoot,
ContextImpl parentCtx) {
.............................................
try {
while (true) {
...................................................................
Map<String, Object> arow = entityProcessor.nextRow();
if (arow == null)
break;
}
} catch (DataImportHandlerException e) {
if (verboseDebug) {
writer.log(SolrWriter.ENTITY_EXCEPTION, entity.name, e);
}
if (isRoot) {
if (e.getErrCode() == DataImportHandlerException.SKIP) {
importStatistics.skipDocCount.getAndIncrement();
} else {
LOG.log(Level.SEVERE, "Exception while processing: "
+ entity.name + " document : " + doc, e);
}
if (e.getErrCode() == DataImportHandlerException.SEVERE)
throw e;
} else
throw e;
} finally {
if (verboseDebug) {
writer.log(SolrWriter.ROW_END, entity.name, null);
if (entity.isDocRoot)
writer.log(SolrWriter.END_DOC, null, null);
}
}
}
} finally {
if (verboseDebug) {
writer.log(SolrWriter.END_ENTITY, null, null);
}
}
}
这个方法使用while循环一直调用nextrow()方法,直到nextRow返回null值,仔细观察getNext(),我们会发现当rowIterator取完的时候,就会返回null了,而这时候,也就跳出了while这个循环。 那就是说,sqlEntity会将执行query语句,并将所有的结果一次取回放到rowIterator中。 现在的问题在于,如果数据库的数量够大,一次取完所有的数据就变得不现实了,那么要怎样才能够实现批次取数据? 以下是笔者实现的一个例子,当然这个例子有很多纰漏,需要去改进,放在这里当作抛砖引玉吧。 这是要索引的表:
people CREATE TABLE `people` ( `id` int(11) NOT NULL auto_increment, `name` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1
一般情况下,相应的dataConfig.xml文件,我们可以这么写:
<entity name="y" query="select * from people "> <field column="id" name="id" /> <field column="name" name="name" /> </entity> 这个结构就会一次性从数据库中取完所有的数据,放在rowIterator中,但现在我们并不想这样去实现,以适应更多的数据量。笔者增加了一个表。下面是这个表的数据。 +-----+---------+ | id | item | +-----+---------+ | 1 | 0 | | 5 | 10000 | | 6 | 50000 | | 7 | 60000 | | 8 | 70000 | | 9 | 80000 | | 10 | 90000 | | 11 | 100000 | | 12 | 110000 | | 13 | 120000 | | 14 | 130000 | | 15 | 140000 | | 16 | 150000 | 修改dataconfig.xml文件
<entity name="x" query="select * from item" rootEntity="false"> <entity name="y" query="select * from people where id between ${x.item} and ${x.item}+1000"> <field column="id" name="id" /> <field column="name" name="name" /> </entity> </entity>
显而易见,笔者是通过增加一个表的方式来达到控制批量存取的效果的。虽然这不失为问题的解决方法,不过增加一个表来这个步骤实在让人觉得有点繁琐,且通用性不强。 当然我们也可以使用xml来代替数据库中的表,不过这只是一种换汤不换药的方式罢了。 或许,通过继承SqlEntityProcessor,覆盖nextRow方法,扩展它的功能,也是一种可以尝试的选择。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 2999 次