2015-08-26 4 views
2

Я разработал свой собственный Indexer в Lucene 5.2.1. Я пытаюсь индексировать файл размером 1,5 ГБ, и мне нужно сделать некоторые нетривиальные вычисления во время индексации на каждом отдельном документе коллекции.Оптимизация индексации lucene 5.2.1

Проблема в том, что для индексирования требуется почти 20 минут! Я следил за этим очень полезным wiki, но он все еще слишком медленный. Я попытался увеличить пространство кучи Eclipse и java-память VM, но это скорее вопрос жесткого диска, а не виртуальной памяти (я использую ноутбук с 6 ГБ или оперативной памятью и обычный жесткий диск).

Я читал об этом discussion, который предлагает использовать RAMDirectory или установить RAM-диск. Проблема с RAM-диском будет связана с сохраняющимся индексом в моей файловой системе (я не хочу потерять индексы после перезагрузки). Проблема с RAMDirectory вместо является то, что, в соответствии с API-интерфейсов, я не должен использовать его, потому что мой индекс больше, чем «несколько сотен megabites» ...

Предупреждение: Этот класс не предназначен для работы с огромным индексов. Все, кроме нескольких сотен мегабайт, будет тратить ресурсы (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 в любом случае или, возможно, что-то еще? Большое спасибо

+2

Профилировали ли вы свой код, чтобы узнать, какая часть занимает больше всего времени? Я подозреваю, что фактическое индексирование не медленное, а процесс чтения файлов. – user1071777

+0

Вам нужно прочитать файл последовательным образом? Если нет, вы можете ускорить работу с распараллеливанием, разбивая файл на куски и вычисляя куски в каждом процессе. – cheffe

+0

Кроме того, если у вас есть в основном уникальные термины, индексирование будет медленнее и медленнее. Можете ли вы предоставить дополнительную информацию о полях/условиях, которые вы хотите индексировать? – RobAu

ответ

1

Lucene утверждает 150GB/час на современном оборудовании - то есть с 20 индексации нитей на 24 основной машине.

У вас есть 1 нить, поэтому ожидайте около 150/20 = 7.5 ГБ/час. Вероятно, вы увидите, что 1 ядро ​​работает на 100%, а остальное работает только при слиянии сегментов.

Вы должны использовать несколько потоков индексов для ускорения работы. См. Например, luceneutil Indexer.java для вдохновения.

Поскольку у вас есть ноутбук, я подозреваю, что у вас есть 4 или 8 ядер, поэтому многопоточность должна быть в состоянии дать вашему индексированию хороший импульс.

+0

Большое спасибо, я буду помнить о ваших советах, и я буду двигаться в этом направлении. –

0

Вы можете попробовать setMaxTreadStates в IndexWriterConfig

iwConfig.setMaxThreadStates (50);

+0

Благодарю вас за ваш совет. Я попытался увеличить ThreadStates, и это на самом деле ускоряет работу. Возможно, я могу попробовать с еще большим значением, например. 100 потоков? –