我在Lucene 5.2.1中开发了自己的Indexer。我试图索引一个尺寸为1.5 GB的文件,我需要在索引时间对集合的每个文档做一些非平凡的计算。
问题是,做所有的索引几乎需要20分钟!我一直遵循这个非常有用的wiki,但它仍然太慢了。我尝试过增加Eclipse堆空间和java VM内存,但似乎更多的是硬盘而不是虚拟内存的问题(我使用的是一台带有6GB或RAM的笔记本电脑和一个普通硬盘)。
我读了这个建议使用RAMDirectory或挂载RAM磁盘的讨论。RAM磁盘的问题是在我的文件系统中持久化索引(我不想在重新启动后丢失索引)。RAMDirectory的问题是,根据api,我不应该使用它,因为我的索引超过"几百兆"…
警告:这个类不适合处理大索引。超过几百兆字节的所有内容都将浪费资源(GC周期),因为它使用1024字节的内部缓冲区大小,产生数百万字节[1024]数组。该类针对小型内存驻留索引进行了优化。它在多线程环境下的并发性也很差。
你可以在这里找到我的代码:
公共类ReviewIndexer {
private JSONParser parser;
private PerFieldAnalyzerWrapper reviewAnalyzer;
private IndexWriterConfig iwConfig;
private IndexWriter indexWriter;
public ReviewIndexer() throws IOException{
parser = new JSONParser();
reviewAnalyzer = new ReviewWrapper().getPFAWrapper();
iwConfig = new IndexWriterConfig(reviewAnalyzer);
//change ram buffer size to speed things up
//@url https://wiki.apache.org/lucene-java/ImproveIndexingSpeed
iwConfig.setRAMBufferSizeMB(2048);
//little speed increase
iwConfig.setUseCompoundFile(false);
//iwConfig.setMaxThreadStates(24);
// Set to overwrite the existing index
indexWriter = new IndexWriter(FileUtils.openDirectory("review_index"), iwConfig);
}
/**
* Indexes every review.
* @param file_path : the path of the yelp_academic_dataset_review.json file
* @throws IOException
* @return Returns true if everything goes fine.
*/
public boolean indexReviews(String file_path) throws IOException{
BufferedReader br;
try {
//open the file
br = new BufferedReader(new FileReader(file_path));
String line;
//define fields
StringField type = new StringField("type", "", Store.YES);
String reviewtext = "";
TextField text = new TextField("text", "", Store.YES);
StringField business_id = new StringField("business_id", "", Store.YES);
StringField user_id = new StringField("user_id", "", Store.YES);
LongField stars = new LongField("stars", 0, LanguageUtils.LONG_FIELD_TYPE_STORED_SORTED);
LongField date = new LongField("date", 0, LanguageUtils.LONG_FIELD_TYPE_STORED_SORTED);
StringField votes = new StringField("votes", "", Store.YES);
Date reviewDate;
JSONObject jsonVotes;
try {
indexWriter.deleteAll();
//scan the file line by line
//TO-DO: split in chunks and use parallel computation
while ((line = br.readLine()) != null) {
try {
JSONObject jsonline = (JSONObject) parser.parse(line);
Document review = new Document();
//add values to fields
type.setStringValue((String) jsonline.get("type"));
business_id.setStringValue((String) jsonline.get("business_id"));
user_id.setStringValue((String) jsonline.get("user_id"));
stars.setLongValue((long) jsonline.get("stars"));
reviewtext = (String) jsonline.get("text");
//non-trivial function being calculated here
text.setStringValue(reviewtext);
reviewDate = DateTools.stringToDate((String) jsonline.get("date"));
date.setLongValue(reviewDate.getTime());
jsonVotes = (JSONObject) jsonline.get("votes");
votes.setStringValue(jsonVotes.toJSONString());
//add fields to document
review.add(type);
review.add(business_id);
review.add(user_id);
review.add(stars);
review.add(text);
review.add(date);
review.add(votes);
//write the document to index
indexWriter.addDocument(review);
} catch (ParseException | java.text.ParseException e) {
e.printStackTrace();
br.close();
return false;
}
}//end of while
} catch (IOException e) {
e.printStackTrace();
br.close();
return false;
}
//close buffer reader and commit changes
br.close();
indexWriter.commit();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
return false;
}
System.out.println("Done.");
return true;
}
public void close() throws IOException {
indexWriter.close();
}
}
那么最好的办法是什么呢?我是否应该构建一个RAM磁盘,然后在索引完成后将索引复制到FileSystem,或者我是否应该使用RAMDirectory——或者其他什么?非常感谢Lucene声称在现代硬件上150GB/小时-这是在24核机器上20个索引线程。
您有1个线程,所以预计大约150/20 = 7.5 GB/小时。你可能会看到一个核心是100%工作,其余的只有在合并段时才工作。
你应该使用多个索引线程来提高速度。参考luceneutil Indexer.java获取灵感。
当你有一台笔记本电脑时,我怀疑你有4或8核,所以多线程应该能够给你的索引一个很好的提升。
您可以尝试在IndexWriterConfig中设置setMaxTreadStates
iwConfig.setMaxThreadStates (50);