优化索引lucene 5.2.1



我在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);

最新更新