java - 优化索引 lucene 5.2.1

标签 java performance lucene

我在 Lucene 5.2.1 中开发了自己的索引器。我正在尝试索引一个 1.5 GB 的文件,我需要在索引期间对集合中的每个文档进行一些重要的计算。

问题是完成所有索引需要将近 20 分钟!我已经关注了这个非常有帮助的wiki , 但它仍然太慢了。我已经尝试增加 Eclipse 堆空间和 Java VM 内存,但它似乎更多的是硬盘而不是虚拟内存(我使用的是 6GB 或 RAM 和普通硬盘的笔记本电脑)。

我读过这个discussion建议使用 RAMDirectory 或安装 RAM 磁盘。 RAM 磁盘的问题是我的文件系统中的持久索引(我不想在重新启动后丢失索引)。 RAMDirectory 的问题在于,根据 API,我不应该使用它,因为我的索引超过“数百兆位”...

Warning: This class is not intended to work with huge indexes. Everything beyond several hundred megabytes will waste resources (GC cycles), because it uses an internal buffer size of 1024 bytes, producing millions of byte[1024] arrays. This class is optimized for small memory-resident indexes. It also has bad concurrency on multithreaded environments.

在这里你可以找到我的代码:

公共(public)类 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 磁盘,然后在索引完成后将其复制到文件系统,还是应该使用 RAMDirectory - 或者其他东西?非常感谢

最佳答案

Lucene 声称在现代硬件上 150GB/小时 - 即在 24 核机器上有 20 个索引线程。

您有 1 个线程,因此预计大约 150/20 = 7.5 GB/小时。您可能会看到 1 个内核 100% 工作,其余的仅在合并段时工作。

您应该使用多个索引线程来加快速度。参见例如 luceneutil Indexer.java寻找灵感。

由于您有一台笔记本电脑,我怀疑您有 4 个或 8 个内核,因此多线程应该能够很好地促进您的索引。

关于java - 优化索引 lucene 5.2.1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32225606/

相关文章:

java - 如何以原子方式向 google appengine 的内存缓存添加新 key ?

java - 每次加载图像时堆都会增长

android - parcelable 值得实现以在 Activity 之间传递数据吗?

java - 如何使用 java Apache Lucene 检索 PDF 文档中的正则表达式搜索字母数字文本?

azure - 如何让 Lucene.net 3.0.3.0 与 Azure 配合使用?

java - 需要帮助将代码片段从 java 翻译为等效的 C#

java - Android:无法检索日期

java - 修复类之间的方法冲突?

ios - 在 Swift 中的设备上运行项目的缓慢延迟/延迟

elasticsearch - 如何根据 Elasticsearch 中的重新评分函数选择顶级术语桶